| created | "2026-03-02T00:00:00.000Z" |
| modified | "2026-06-14T00:00:00.000Z" |
| reviewed | "2026-06-10T00:00:00.000Z" |
| name | git-fork-workflow |
| description | Fork management and upstream sync. Use when working with forks, syncing with upstream, detecting divergence, or preparing commits for contribution. |
| allowed-tools | Bash(bash *), Bash(git remote *), Bash(git fetch *), Bash(git log *), Bash(git status *), Bash(git diff *), Bash(git rev-list *), Bash(gh repo *), Read, Grep, Glob |
Git Fork Workflow
Expert guidance for managing forked repositories, synchronizing with upstream, and contributing back cleanly.
Data-Gathering Script
Run this first to detect the upstream remote, compute ahead/behind via
git rev-list, and get a recommended sync strategy (a pure function — it
runs no mutations):
bash "${CLAUDE_SKILL_DIR}/scripts/git-fork-workflow.sh" --home-dir "$HOME" --project-dir "$(pwd)"
Parse STATUS= and ISSUES: from the output. It emits IS_FORK,
UPSTREAM / ORIGIN, BEHIND / AHEAD (from
git rev-list --left-right --count upstream/main...origin/main), and
RECOMMENDED_STRATEGY (one of in-sync, fast-forward, ahead-only,
rebase, not-a-fork). The strategy is a recommendation only — executing
any destructive sync (reset, rebase, force-push) stays your call, per the
strategy prose below.
When to Use This Skill
| Use this skill when... | Use git-upstream-pr instead when... |
|---|
| Understanding fork remote architecture | Ready to submit a PR to upstream |
| Diagnosing fork divergence from upstream | Need step-by-step PR creation workflow |
| Syncing fork's main with upstream | Cherry-picking specific commits for upstream |
| Deciding on a sync strategy | Creating a cross-fork PR via gh CLI |
| Contributing from an environment that can't reach upstream | Upstream is directly reachable for a normal cross-fork PR |
Remote Architecture
Forks use two remotes:
| Remote | Points To | Purpose |
|---|
origin | Your fork (you/repo) | Push your work here |
upstream | Original repo (owner/repo) | Pull updates from here |
Setup
git remote -v
git remote add upstream https://github.com/owner/original-repo.git
git fetch upstream
git remote -v
Identifying Fork vs Upstream
git remote get-url upstream
git remote get-url origin | sed -E 's#.*github\.com[:/]##; s#\.git$##'
git remote get-url upstream | sed -E 's#.*github\.com[:/]##; s#\.git$##'
The Divergence Problem
When you squash-merge branches into your fork's main, the commit SHAs differ from upstream's commits. This creates divergence even when the code content is identical.
Detecting Divergence
The data-gathering script (above) fetches both remotes and computes the
ahead/behind counts — read BEHIND and AHEAD from its output. To view the
specific divergent commits behind those counts:
git log --oneline upstream/main..origin/main
git log --oneline origin/main..upstream/main
Reading the Counts
The script's BEHIND / AHEAD come from
git rev-list --left-right --count upstream/main...origin/main:
BEHIND AHEAD | Meaning |
|---|
0 0 | Perfectly in sync |
5 0 | Fork is 5 behind upstream (upstream has 5 new commits) |
0 3 | Fork is 3 ahead (fork has 3 commits not on upstream) |
5 3 | Diverged: upstream has 5 new, fork has 3 unique |
Sync Strategies
Strategy 1: GitHub CLI Sync (Simplest)
gh repo sync owner/fork-repo
git pull origin main
Best when: fork has no unique commits worth preserving on main.
Strategy 2: Fast-Forward Merge (Clean Canary)
git fetch upstream
git merge --ff-only upstream/main
Best when: fork's main has not diverged. Fails cleanly if diverged (no messy merge commits).
Strategy 3: Hard Reset (Force Sync)
git fetch upstream
git reset --hard upstream/main
git push --force-with-lease origin main
Best when: fork's main has diverged and you want to discard fork-only commits. Destructive - ensure no unique work is on main.
Strategy 4: Rebase (Preserve Fork Work)
git fetch upstream
git rebase upstream/main
git push --force-with-lease origin main
Best when: fork has unique commits on main that should sit on top of upstream's history.
Strategy Selection
The script's RECOMMENDED_STRATEGY maps the BEHIND/AHEAD counts to a
strategy keyword via a pure function; use it as the starting point and confirm
against this table before running any destructive command:
RECOMMENDED_STRATEGY | Situation | Strategy |
|---|
in-sync | 0 behind, 0 ahead | Nothing to do |
fast-forward | Behind only, fork main clean | Fast-forward or gh repo sync |
ahead-only | Ahead only, nothing to pull | No sync needed; fork leads upstream |
rebase | Diverged, unique work worth keeping | Rebase (Strategy 4) |
| (diverged, work expendable) | Unique work expendable / match upstream exactly | Hard reset (Strategy 3) |
| (unsure) | Not sure | Try fast-forward first; it fails safely if diverged |
The recommendation never executes a sync — picking and running Strategy 3
(hard reset) or 4 (rebase + force-push) stays your decision.
Golden Rule for Upstream PRs
Branch from upstream/main, not from your fork's main. This completely bypasses fork divergence:
git fetch upstream
git switch -c feat/my-contribution upstream/main
git push -u origin feat/my-contribution
See git-upstream-pr for the complete workflow.
Fork-Main as an Upstream Staging Area
When the environment cannot reach upstream directly — e.g. a Claude Code session whose repository scope only includes your fork, so issues/PRs against owner/repo are denied — don't let that block development. Stage the contribution in your fork's main, then resubmit upstream from a session that can reach it.
The pattern
-
Stage in the fork. Branch (ideally from upstream/main), implement, open a PR into your fork's main, self-review, and merge. The change is now landed and usable immediately, independent of upstream reachability.
-
Contain the divergence. Merging into fork main diverges it from upstream/main (different SHAs — the Divergence Problem above). That is the accepted cost of staging. Keep it bounded by periodically pulling upstream/main back in (rebase or merge) so the fork doesn't rot.
-
Resubmit cleanly — never PR fork:main → upstream:main. That drags every staged commit plus the divergence into one PR. Instead, from a session that can reach upstream, branch fresh from upstream/main and cherry-pick only the one contribution's commit(s), then open the cross-fork PR (syntax below). Each upstream PR stays atomic and reviewable — what maintainers actually accept.
-
Track upstream status. Stamp staged commits so a later session knows what still needs a PR:
Upstream-status: pending # staged in fork, not yet submitted
Upstream-PR: https://github.com/owner/repo/pull/NN # once submitted
List what's still pending with git log --grep='Upstream-status: pending' upstream/main..origin/main.
When to use vs. the Golden Rule
| Situation | Approach |
|---|
| You can reach upstream now | Branch from upstream/main, open the cross-fork PR directly (Golden Rule above) |
| You cannot reach upstream from this environment | Stage in fork main now; cherry-pick onto an upstream/main branch and PR later |
The staging pattern is the Golden Rule deferred — it still ends with a clean upstream/main-based branch; it just buys you an unblocked checkpoint in between.
Cross-Fork PR Syntax
gh pr create \
--repo owner/upstream-repo \
--base main \
--head your-username:feat/branch-name \
--title "feat: description" \
--body "PR description"
The --head must include the fork owner prefix (your-username:branch) when targeting a different repository.
Common Patterns
Check if Working in a Fork
git remote get-url upstream 2>/dev/null && echo "Fork" || echo "Not a fork"
Periodic Sync Workflow
git fetch upstream
git switch main
git merge --ff-only upstream/main || echo "Diverged - manual sync needed"
git push origin main
View Upstream Changes Since Last Sync
git fetch upstream
git log --oneline origin/main..upstream/main
Agentic Optimizations
| Context | Command |
|---|
| Divergence count | git rev-list --left-right --count upstream/main...origin/main |
| Fork ahead commits | git log --oneline --format='%h %s' upstream/main..origin/main |
| Fork behind commits | git log --oneline --format='%h %s' origin/main..upstream/main |
| Quick sync check | git fetch upstream && git merge --ff-only upstream/main |
| Remote listing | git remote -v |
Related Skills