How to fix This branch is X commits ahead, Y commits behind upstream/main in Git

GitBEGINNERLOWUpdated Dec 6, 2025· 286 views

This message appears on GitHub when your forked branch has diverged from the upstream repository. Your fork contains commits not in the original repo (ahead) and is missing commits from the original (behind). Syncing your fork resolves this divergence.

Quick fix

Fixes This branch is X commits ahead, Y commits behind upstream/main

# Check your remotes
git remote -v

# Expected output:
# origin    https://github.com/YOUR-USERNAME/repo.git (fetch)
# origin    https://github.com/YOUR-USERNAME/repo.git (push)
# upstream  https://github.com/ORIGINAL-OWNER/repo.git (fetch)
# upstream  https://github.com/ORIGINAL-OWNER/repo.git (push)

# If upstream is missing, add it:
git remote add upstream https://github.com/ORIGINAL-OWNER/repo.git

# Verify it was added
git remote -v
  1. Check your current fork status
  2. Fetch the latest upstream changes
  3. Sync using GitHub's web interface (easiest method)
  4. Sync with merge (preserves your commit history)
git — error
# Check your remotes
git remote -v
# Expected output:
# origin https://github.com/YOUR-USERNAME/repo.git (fetch)
# origin https://github.com/YOUR-USERNAME/repo.git (push)
# upstream https://github.com/ORIGINAL-OWNER/repo.git (fetch)
# upstream https://github.com/ORIGINAL-OWNER/repo.git (push)
# If upstream is missing, add it:
git remote add upstream https://github.com/ORIGINAL-OWNER/repo.git
# Verify it was added
git remote -v
This branch is X commits ahead, Y commits behind upstream/main

What this error means

The message "This branch is X commits ahead, Y commits behind upstream/main" is not an error but an informational status shown by GitHub (and other Git hosting platforms) when your repository has diverged from its upstream source. **What "ahead" means**: Your branch has X commits that don't exist in the upstream repository. These are changes you (or others) made in your fork that haven't been merged into the original project. **What "behind" means**: The upstream repository has Y commits that your branch doesn't have yet. The original project has received updates since you last synced. This divergence commonly happens with forked repositories when: 1. You make changes to your fork (creates "ahead" commits) 2. The original repository receives new commits (puts you "behind") While this message doesn't prevent you from working, it indicates your fork is out of sync. Being significantly behind can lead to merge conflicts when you eventually try to contribute back to the upstream project.

Typical symptoms

  • GitHub shows 'This branch is X commits ahead, Y commits behind' message on your fork
  • Pull request from fork shows unexpected diff or conflicts
  • Your fork appears to have outdated code compared to the original repository
  • GitHub suggests 'Sync fork' button on your repository page
  • Running git status shows your branch diverged from upstream
  • Merge conflicts appear when trying to merge upstream changes
  • CI/CD tests fail because your fork is missing recent upstream fixes
  • Contributors report issues that were already fixed in upstream

Common causes

  1. You forked a repository and made commits without syncing upstream changes
  2. The upstream repository received new commits after you forked
  3. You merged a pull request into your fork that wasn't accepted upstream
  4. The upstream repository rebased or force-pushed, rewriting history
  5. You haven't set up an upstream remote to track the original repository
  6. Your fork has been inactive while the original project continued development
  7. You created commits directly on main/master instead of feature branches
  8. A previous sync attempt created merge commits instead of rebasing cleanly

How to fix "This branch is X commits ahead, Y commits behind upstream/main"

1Check your current fork status

First, verify your fork's relationship with the upstream repository:

bash
# Check your remotes
git remote -v

# Expected output:
# origin    https://github.com/YOUR-USERNAME/repo.git (fetch)
# origin    https://github.com/YOUR-USERNAME/repo.git (push)
# upstream  https://github.com/ORIGINAL-OWNER/repo.git (fetch)
# upstream  https://github.com/ORIGINAL-OWNER/repo.git (push)

# If upstream is missing, add it:
git remote add upstream https://github.com/ORIGINAL-OWNER/repo.git

# Verify it was added
git remote -v

Replace ORIGINAL-OWNER/repo with the actual original repository URL.

2Fetch the latest upstream changes

Download the latest commits from the upstream repository without merging them:

bash
# Fetch all branches from upstream
git fetch upstream

# See the difference between your branch and upstream
git log HEAD..upstream/main --oneline

# This shows commits in upstream that you don't have

# To see commits you have that upstream doesn't:
git log upstream/main..HEAD --oneline

This helps you understand exactly what's different before making changes.

3Sync using GitHub's web interface (easiest method)

GitHub provides a simple way to sync your fork:

1. Go to your fork on GitHub (github.com/YOUR-USERNAME/repo)
2. Click the "Sync fork" button (or "Fetch upstream" on older UI)
3. Review the changes to be synced
4. Click "Update branch"

Limitations of this method:
- Only works if there are no conflicts
- Creates a merge commit
- Doesn't work if you have unpushed local commits

If GitHub shows conflicts or you prefer command-line control, use the manual methods below.

4Sync with merge (preserves your commit history)

If you want to keep your fork's commits visible in the history:

bash
# Make sure you're on your main branch
git checkout main

# Fetch upstream changes
git fetch upstream

# Merge upstream into your branch
git merge upstream/main

# If there are conflicts, resolve them:
# 1. Open conflicted files
# 2. Edit to resolve conflicts
# 3. Stage resolved files: git add <file>
# 4. Complete merge: git commit

# Push the merged result to your fork
git push origin main

This creates a merge commit but preserves the complete history of both branches.

5Sync with rebase (cleaner history)

Rebasing creates a linear history by replaying your commits on top of upstream:

bash
# Make sure you're on your main branch
git checkout main

# Fetch upstream
git fetch upstream

# Rebase your commits on top of upstream
git rebase upstream/main

# If conflicts occur:
# 1. Resolve conflicts in affected files
# 2. Stage resolved files: git add <file>
# 3. Continue rebase: git rebase --continue
# (repeat for each conflicting commit)

# Force push to update your fork (required after rebase)
git push origin main --force-with-lease

Warning: Only rebase if:
- No one else is working on your fork's main branch
- You haven't shared these commits with others
- You're comfortable with force pushing

6Hard reset to match upstream exactly

If your ahead commits are unwanted (experiments, mistakes), you can reset to match upstream exactly:

bash
# WARNING: This DELETES all your commits that aren't in upstream!

# First, backup your work if needed:
git branch backup-before-reset

# Fetch upstream
git fetch upstream

# Hard reset to match upstream exactly
git reset --hard upstream/main

# Force push to your fork
git push origin main --force

Use this when:
- Your "ahead" commits were experimental and you don't need them
- Your fork got into a messy state you want to start fresh
- You want an exact mirror of upstream

Do NOT use this if:
- You have commits you want to keep
- Others have forked your fork

7Set up automatic sync (GitHub Actions)

To keep your fork automatically synced, create a GitHub Action:

Create .github/workflows/sync-fork.yml:

yaml
name: Sync Fork

on:
  schedule:
    - cron: '0 0 * * *'  # Daily at midnight
  workflow_dispatch:  # Manual trigger

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Sync fork
        run: |
          git remote add upstream https://github.com/ORIGINAL-OWNER/repo.git
          git fetch upstream
          git checkout main
          git merge upstream/main
          git push origin main

Replace ORIGINAL-OWNER/repo with the actual upstream repository.

Note: This only works if there are no conflicts. For repos with frequent conflicts, manual syncing is better.

8Prevent future divergence

Best practices to minimize fork divergence:

bash
# 1. Never commit directly to main - use feature branches
git checkout -b my-feature
# ... make changes ...
git push origin my-feature

# 2. Sync before starting new work
git checkout main
git fetch upstream
git merge upstream/main
git push origin main
git checkout -b new-feature

# 3. Keep feature branches short-lived
# Merge or close old branches promptly

# 4. Rebase feature branches before creating PRs
git checkout my-feature
git fetch upstream
git rebase upstream/main

Key principle: Keep your fork's main branch as a clean mirror of upstream. All your work should happen on feature branches.

Advanced notes

### Understanding Fork Divergence

When you fork a repository on GitHub, you create an independent copy at that point in time. From that moment:

bash
Time 0: Fork created
         Upstream: A--B--C
         Your fork: A--B--C (identical)

Time 1: Both repos receive commits
         Upstream: A--B--C--D--E--F (upstream adds D, E, F)
         Your fork: A--B--C--X--Y   (you add X, Y)

Status: "2 commits ahead, 3 commits behind"

### The "Commits Ahead" Problem

Commits you're "ahead" by typically fall into categories:

1. Intentional changes: Features or fixes you want to contribute back via PR
2. Local customizations: Changes specific to your use case
3. Accidental commits: Work that should have been on a branch
4. Merged PRs: Pull requests you merged into your fork but weren't accepted upstream

For intentional changes, create a PR to upstream. For local customizations, consider keeping them on a separate branch. For accidents, reset or revert them.

### Choosing Merge vs Rebase

| Situation | Use Merge | Use Rebase |
|-----------|-----------|------------|
| Shared fork (multiple contributors) | ✓ | ✗ |
| Solo fork with clean history preference | ✗ | ✓ |
| Commits already pushed | ✓ | Only with force push |
| Complex conflict resolution | ✓ | ✓ (commit by commit) |
| Public commits others may depend on | ✓ | ✗ |

### Handling Upstream Rebases

If the upstream repository rebased or force-pushed, your fork's history no longer shares common ancestors:

bash
# This can cause "refusing to merge unrelated histories"

# Option 1: Hard reset (lose your changes)
git fetch upstream
git reset --hard upstream/main
git push --force origin main

# Option 2: Rebase with new upstream
git fetch upstream
git rebase upstream/main --onto upstream/main

# Option 3: Cherry-pick your commits onto fresh base
git checkout -b temp upstream/main
git cherry-pick <your-commit-hashes>
git checkout main
git reset --hard temp
git branch -d temp

### Multiple Upstream Branches

If you need to sync multiple branches:

bash
# Sync main
git checkout main
git fetch upstream
git merge upstream/main
git push origin main

# Sync develop
git checkout develop
git merge upstream/develop
git push origin develop

# Or use a loop for multiple branches
for branch in main develop release; do
  git checkout $branch
  git merge upstream/$branch
  git push origin $branch
done

### Fork vs Clone Considerations

| Scenario | Fork + Clone | Just Clone |
|----------|--------------|------------|
| Contributing to open source | ✓ | ✗ |
| Personal backup of a repo | Either | Either |
| Modifying for personal use | ✓ | ✗ |
| Team collaboration (org repo) | ✗ | ✓ |
| You have push access | ✗ | ✓ |

### Upstream Remote Conventions

While "upstream" is the conventional name, you might encounter:

bash
# Common naming conventions:
upstream  # Most common, recommended
original  # Alternative
source    # Alternative

# Check what you have
git remote -v

# Rename if needed
git remote rename old-name upstream

### When "Ahead" Commits Are Desired

Sometimes being "ahead" is intentional:

- Customization forks: You maintain a modified version
- Staging forks: Testing changes before upstream PR
- Archive forks: Preserving deleted upstream repos

In these cases, the "ahead/behind" message is informational, not a problem to fix.

### Sync Strategies for Active Forks

For forks you actively develop:

1. Daily sync: git fetch upstream && git merge upstream/main
2. Before each PR: Sync, then create feature branch
3. After upstream PR merge: Sync to get your merged changes

For forks that are just backups or references:

1. Periodic sync: Monthly or when you remember
2. GitHub Sync button: Easiest, no local action needed

Frequently asked questions

What does "This branch is X commits ahead, Y commits behind upstream/main" mean?
The message "This branch is X commits ahead, Y commits behind upstream/main" is not an error but an informational status shown by GitHub (and other Git hosting platforms) when your repository has diverged from its upstream source. What "ahead" means: Your branch has X commits that don't exist in the upstream repository. These are changes you (or others) made in your fork that haven't been merged into the original project.
How do I fix "This branch is X commits ahead, Y commits behind upstream/main"?
This message appears on GitHub when your forked branch has diverged from the upstream repository. Your fork contains commits not in the original repo (ahead) and is missing commits from the original (behind). Syncing your fork resolves this divergence.
What causes "This branch is X commits ahead, Y commits behind upstream/main"?
You forked a repository and made commits without syncing upstream changes The upstream repository received new commits after you forked You merged a pull request into your fork that wasn't accepted upstream
Is the "This branch is X commits ahead, Y commits behind upstream/main" error serious?
It is a low-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading