Skip to content

Git Rebase: Handling Divergent Branches

When you try to push changes and Git says your branch has diverged, it's protecting you from losing work. Let's understand why this happens and how to fix it cleanly.

The Problem

You're working on a feature branch, make some commits, and try to push. Suddenly:

$ git push
To https://github.com/dwdas9/home.git
 ! [rejected]        feature/25.10.25 -> feature/25.10.25 (fetch first)
error: failed to push some refs to 'https://github.com/dwdas9/home.git'

Push Rejected

Git is telling you: "The remote has changes you don't have locally. Pull first!"

So you run git pull, but instead of fixing things, you get another error:

$ git pull
fatal: Need to specify how to reconcile divergent branches.

What Git is Really Asking

"Your local and remote branches have diverged. How do you want to combine them?"

  • git config pull.rebase falsemerge (create a merge commit)
  • git config pull.rebase truerebase (replay your commits on top)
  • git config pull.ff onlyfast-forward only (only works if you haven't committed)

This guide will help you choose the right strategy.


Understanding Divergent Branches

Think of it like two editors working on the same document simultaneously. Eventually, you need to reconcile the changes.

Divergent Branches

Breaking Down the Diagram
  • Commits A, B, C: Shared history between local and remote
  • Commit C: Where the branches diverged (common ancestor)
  • Commits E, F (red): Changes pushed to remote while you worked locally
  • Commit D (yellow): Your local commit that hasn't been pushed

Git doesn't know which version is "correct"—both have valid work!

Common Causes

You and a teammate both work on feature/auth. They push first. When you try to push, your branches have diverged.

You push from your work laptop, then commit from home (forgetting to pull first). Divergence!

Your pipeline makes automated commits (version bumps, lockfiles) while you're coding locally.

Someone force-pushed to the branch, rewriting history. Your local branch is now out of sync.


Three Solutions

Git offers three ways to reconcile divergent branches. Let's explore when to use each.

1. Merge Strategy

Merge Strategy

Creates a new "merge commit" with two parents, preserving both histories.

When to Use Merge

Best for: Main/shared branches where you want full transparency

Example: Working on main with your team. You want to see exactly when features were integrated.

git config pull.rebase false
git pull  # Creates a merge commit
git push
Merge Advantages
  • Preserves complete history
  • Shows when branches were integrated
  • Non-destructive (doesn't rewrite history)
  • Good for collaborative branches

Rebase Strategy

Replays your commits on top of the latest remote commits, creating a linear history.

When to Use Rebase

Best for: Feature branches where you're the primary developer

Example: Working solo on feature/login. You want clean, linear history.

git config pull.rebase true
git pull  # Replays your commits on top
git push
Rebase Advantages
  • Clean, linear history
  • Easier to understand commit flow
  • No extra merge commits cluttering history
  • Perfect for feature branches

Golden Rule of Rebase

Never rebase commits that you've already pushed to a shared branch where others might have based work on them. Only rebase local commits or personal feature branches.


3. Fast-Forward Only

Fast-Forward Only

Only updates if your local branch is simply "behind" (no local commits).

When to Use Fast-Forward

Best for: When you want to be extra cautious and avoid automatic merges

Example: You cloned a repo and haven't made changes. Just want to update.

git config pull.ff only
git pull  # Works only if you haven't committed locally
Why It Often Fails

Fast-forward only works when:

  • Remote has new commits
  • You have NO new local commits

In our divergent branch scenario, you HAVE local commits (Commit D), so this fails with:

fatal: Not possible to fast-forward, aborting.


Solving the Problem: Step-by-Step

Let's fix the divergent branch issue from our example.

Quick Solution (Feature Branch)

For a personal feature branch, rebase is cleanest:

# 1. Set rebase as the strategy
git config pull.rebase true

# 2. Pull with rebase
git pull

# 3. Push your changes
git push

Done!

Your commits are now replayed on top of the remote changes. Clean, linear history!

Handling Merge Conflicts

Sometimes your changes and remote changes touch the same lines:

$ git pull
Auto-merging myfile.py
CONFLICT (content): Merge conflict in myfile.py
error: could not apply 396de08... changes
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
Conflict Resolution Steps

1. Open the conflicting file(s)

Git marks conflicts with special markers:

<<<<<<< HEAD
# Remote version (what's on GitHub)
print("Hello from remote")
=======
# Your version (your local commit)
print("Hello from local")
>>>>>>> 396de08 (changes)

2. Edit to resolve the conflict

# Resolved version - keep what you need
print("Hello from both versions")

3. Stage the resolved file

git add myfile.py

4. Continue the rebase

git rebase --continue

5. Push your changes

git push

Need to Abort?

If things go wrong during conflict resolution:

git rebase --abort  # Returns to state before rebase


Best Practices

Minimize divergent branches with these habits:

Always Pull Before Pushing

# Make it a habit
git pull
git push

Set a Default Strategy

Choose your preferred method globally:

git config --global pull.rebase true
git config --global pull.rebase false
git config --global pull.ff only

Additional Tips

Team Coordination

  • Communicate when working on the same branch
  • Use separate feature branches per developer
  • Consider branch protection rules

Commit Frequently

  • Don't let your local branch get too far ahead
  • Smaller, frequent pushes reduce conflict chances
  • Push daily (or more often)

Use Pull Requests

For main/shared branches, use PRs instead of direct pushes. This prevents accidental divergence.


Quick Reference

Strategy Command Best For Result
Rebase git pull --rebase Feature branches, solo work Linear history
Merge git pull --no-rebase Shared branches, teams Preserves full history
FF Only git pull --ff-only Safe updates, no local commits Simple updates only
Common Commands
# Set default strategy
git config pull.rebase true   # or false, or ff-only

# Pull with specific strategy (one-time)
git pull --rebase
git pull --no-rebase
git pull --ff-only

# During conflict resolution
git rebase --continue   # After resolving conflicts
git rebase --abort      # Undo the rebase
git rebase --skip       # Skip current commit

# View branch status
git status
git log --oneline --graph --all

Key Takeaways

Remember

  • Divergent branches are normal—they happen when local and remote histories differ
  • Three solutions: Merge, Rebase, or Fast-Forward (when possible)
  • For feature branches: Use rebase for clean, linear history
  • For shared branches: Use merge to preserve complete history
  • Always pull before pushing to minimize divergence

Real-World Solution

For the scenario we started with:

git config pull.rebase true
git pull
git push
Clean history maintained, changes successfully pushed!


Learn More