Merge and rebase both bring the changes from one branch into another, but they record it differently: git merge main adds a merge commit that joins the two histories, while git rebase main rewrites your commits so they sit on top of main in a straight line. Use merge for branches other people share, and rebase only for commits that are still yours alone.
The file contents end up the same either way. Only the shape of the history differs, and that shape matters when other people have copies of it.
The starting point
Every graph below is real git log --graph --oneline --all output from a test repository. A feature branch with commits F1 and F2 was created from main at commit B, and then someone added commit C to main:
F1---F2 feature
/
A---B---C main
You want feature to include C. There are two ways.
What git merge does
git switch feature
git merge main
Example output:
Merge made by the 'ort' strategy.
c | 1 +
1 file changed, 1 insertion(+)
The graph afterwards:
* a1c09b1 Merge branch 'main' into feature
|\
| * 6c21ca3 C
* | 91384b8 F2
* | e8c777a F1
|/
* 7f72d91 B
* 77dfba1 A
F1 and F2 keep their original hashes. A new commit, a1c09b1, has two parents and records the moment the branches came together. Nothing that already existed is changed, so merging is always safe on a branch others have pulled.
The cost is noise: on a busy project, repeatedly merging main into a feature branch adds a merge commit each time, and the graph becomes hard to read.
What git rebase does
git switch feature
git rebase main
Example output:
Successfully rebased and updated refs/heads/feature.
The graph afterwards (the old commits are shown on the right because a backup branch still pointed at them in the test):
* e7c2292 F2
* 865103b F1
* 6c21ca3 C
| * 91384b8 F2
| * e8c777a F1
|/
* 7f72d91 B
* 77dfba1 A
Look at the hashes. F1 was e8c777a and is now 865103b; F2 was 91384b8 and is now e7c2292. Rebase "replays" each of your commits on top of the new base, and the Pro Git book puts it plainly: you are "abandoning existing commits and creating new ones that are similar but different". With nothing else pointing at the old ones, feature now reads A, B, C, F1, F2 in a straight line, with no merge commit.
Merge vs rebase at a glance
| git merge | git rebase | |
|---|---|---|
| History shape | Branches and joins, as it happened | Straight line |
| Existing commits | Kept, same hashes | Replaced with new hashes |
| Extra commit | One merge commit | None |
| Conflicts | Resolved once, in the merge commit | Can come up once per replayed commit |
| Safe on a shared branch | Yes | No |
| Undo | git reset --hard ORIG_HEAD before pushing, or git revert -m 1 after | git rebase --abort during, reflog after |
The rule: don't rebase commits other people have
The Pro Git book states it as: "Do not rebase commits that exist outside your repository and that people may have based work on." If you rebase commits you already pushed and then force push, everyone who pulled the old versions now has commits that the remote no longer contains. When they pull, Git treats the old and new copies as different work, and they get duplicated commits and conflicts they did nothing to cause.
In practice that gives a simple split:
- Rebase your local, unpushed commits, or a feature branch only you push to, to tidy it before opening a pull request.
- Merge anything that lives on a shared branch such as
mainordevelop.
The book's own summary: "rebase local changes before pushing to clean up your work, but never rebase anything that you've pushed somewhere." Which style a team prefers beyond that is a team decision; neither is wrong.
git pull --rebase
git pull is git fetch followed by a merge or a rebase. When you and a colleague both commit to the same branch, a plain pull with merging creates a merge commit each time, even for a one-line change. --rebase replays your unpushed commits on top of what you just fetched instead:
git pull --rebase
Example output, where the remote had commit B and the local branch had an unpushed commit C:
Successfully rebased and updated refs/heads/main.
* 1a20224 C
* 7fe9af6 B
* df17502 A
This does not break the shared-branch rule, because the only commits being rewritten are your own unpushed ones. To make it the default:
git config --global pull.rebase true
If you set nothing, current Git refuses to merge or rebase on its own when your branch and the remote have both moved: the git-pull docs say --ff-only "is the default when no method for reconciling divergent histories is provided". Some installs ship a system-wide setting; Git for Windows on the test machine had pull.rebase false in its system config, so pulls merged. Check yours with git config --show-origin --get-regexp pull.
Handling conflicts during a rebase
A rebase stops at each commit that conflicts. While it is stopped, you are not on any branch: git status shows interactive rebase in progress and git branch shows (no branch, rebasing feature). That is a temporary detached HEAD (see Git detached HEAD explained). Fix the files, then:
git add path/to/fixed-file
git rebase --continue
To give up and return the branch to how it was before the rebase started:
git rebase --abort
Because rebase replays commits one at a time, a branch with ten commits that all touch the same lines can make you resolve the same conflict several times. When that happens, merging is the less painful option.
If you already rebased and pushed
If it was your own branch, push with git push --force-with-lease, which refuses if someone else pushed in the meantime. If it was a shared branch, tell everyone before they pull; the Pro Git book suggests they use git pull --rebase, which can often recognise their own commits and replay just those. For undoing a single bad commit on a shared branch, git revert is the safer tool.
Frequently asked questions
- Does rebase or merge give a different final result?
- No. If there are no conflicts, the files at the end are identical either way. The Pro Git book says the final snapshot is the same and only the history differs: merge records a merge commit with two parents, rebase rewrites your commits so they sit in a straight line on top of the other branch.
- Why is rebasing a shared branch a problem?
- Rebase replaces your commits with new ones that have different hashes. Anyone who already pulled the old commits now has a history that disagrees with the remote, and when they pull again Git sees the old and new versions as different work, which leads to duplicate commits and repeated conflicts.
- How do I make git pull rebase by default?
- Run git config --global pull.rebase true. After that, git pull fetches and then rebases your local commits on top of the updated remote branch instead of creating a merge commit.
- How do I stop a rebase that went wrong?
- Run git rebase --abort while the rebase is still in progress. Git returns the branch to exactly where it was before you started. If the rebase already finished, find the previous tip with git reflog and reset to it.