Git rebase does not move your commits. It replays them, and every replayed commit gets a new hash. That one fact explains most of what people call rebase hell: teammates whose local branch no longer matches the remote, and force pushes that overwrite someone else's work. This post covers when to rebase, when to merge instead, how to recover a rebase that went wrong, and how to push a rebased branch without a blind force push.
Rebasing is often used to streamline a series of commits into a single, cohesive narrative. This can make your project's history much easier to follow. However, rebasing can also change commit hashes, which can be problematic for team members who have already pulled those commits.
In cases where there are many commits and conflicts, merging might be a safer and easier option. While merging adds a new commit to your history, it preserves the commit hashes and can avoid the confusion that comes with rebasing.
# Use merge when dealing with complex conflict scenarios
git checkout main
git merge feature-branchgit rebase --abort before you dig deeperIf something goes wrong during a rebase, it is often best to abort and start over. This can help avoid introducing further issues.
# Abort the rebase
git rebase --abortgit rerere replay conflicts you have already resolvedIf you find yourself fixing the same conflicts repeatedly, use git rerere to automate the resolution process.
# Enable rerere
git config --global rerere.enabled truegit reflog to undo a finished rebaseOnce a rebase has finished, --abort is gone. The old commits still exist, and git reflog lists the HEAD positions from before the rewrite, so you can reset back to one.
Example:
View the reflog to find the previous state:
git reflogYou might see something like this:
a1b2c3d (HEAD -> feature-branch) HEAD@{0}: rebase finished: returning to refs/heads/feature-branch
e4f5g6h HEAD@{1}: rebase: squash commit
i7j8k9l HEAD@{2}: checkout: moving from main to feature-branchReset to a previous state:
git reset --hard HEAD@{2}Don’t change the git strategy chosen by your organization, suddenly. If your team prefers a “squash and merge” workflow, it is best to stick with it and avoid switching to rebase.
Rebasing long-lived branches can be particularly difficult due to the number of changes that have occurred. Consider whether rebasing is the best option in these scenarios.
When you rebase, you become a co-author on the commit, and GPG signatures might be lost. Make sure you understand these implications before proceeding.
--force-with-lease, never with plain --forceYou cannot rebase a branch you have already pushed and then update the remote without a force push of some kind, because the rewritten commits no longer fast-forward. Use --force-with-lease instead of --force. It only overwrites the remote branch if no one else has pushed to it since your last fetch, so you do not silently drop a teammate's commits.
Rebase your own unpushed branch as often as you like. On a shared branch, agree on the strategy first, keep the branch short, and push with --force-with-lease.
Git rebase helps create a clean, linear project history by consolidating multiple commits into a single narrative. This makes it easier to follow the project’s development and can simplify code reviews and debugging.
Merging is preferable when there are many commits with conflicts. Merging avoids changing commit hashes, making it safer and less disruptive for team members who have already pulled those commits.
Enable git rerere to record how you have resolved conflicts in the past. This can save time by automatically resolving similar conflicts in the future.
If a rebase goes wrong, abort it immediately using git rebase --abort. If you need to undo changes after a rebase, use git reflog to find the previous state and reset to it.
After rebasing, use git push --force-with-lease instead of git push --force. This command ensures that you only overwrite the branch if no one else has pushed changes to it since your last fetch, reducing the risk of losing others' work.
Occasional notes on software, tools, and things I learn. No spam.
Unsubscribe anytime.