Sooner or later every team asks: “do we rebase or merge?”. The answer is both, just in different places. Both commands combine changes from two branches, but they leave a different history behind.
Merge: history as it happened
git merge creates a new commit with two parents. Nothing is rewritten, so it is safe even on branches other people use. The price is a branching history that, on a busy repo, looks like a metro map.
git switch main
git merge feature/login
Rebase: history as you want to tell it
git rebase takes your commits and replays them on a new base. The history is linear and reads like a story. But the commits get new hashes — they are new objects, even if the changes are the same.
git switch feature/login
git rebase main
# after resolving a conflict:
git add . && git rebase --continue
The golden rule: never rebase a branch that someone other than you is working on.
Putting it together
| Situation | Choice |
|---|---|
| Updating your own branch with changes from main | rebase |
| Cleaning up before a pull request | rebase -i |
| Landing a finished feature in main | merge (or squash) |
| A branch shared by several people | merge |
Two lines of config I recommend to everyone: git pull will rebase instead of creating pointless merge commits, and uncommitted local changes are stashed automatically.
git config --global pull.rebase true
git config --global rebase.autoStash true
Pushing after a rebase
After a rebase a plain git push is rejected because the histories differ. Instead of --force use --force-with-lease: it only overwrites the branch if nobody has pushed to it in the meantime.
Something went wrong? Reflog
Git loses almost nothing. git reflog shows where HEAD was before every operation, so a failed rebase is undone with one command.
git reflog
# a1b2c3d HEAD@{4}: rebase (start): checkout main
git reset --hard HEAD@{5}
Finally The rebase-or-merge debate is usually about who reads the history. Agree on it once as a team, write it down in CONTRIBUTING.md and get back to work.
