When git rebase Goes Wrong
Ask a group of Git users about git rebase and you'll quickly find strong opinions. Some people use it constantly without issue; others avoid it entirely. To understand this divide, it helps to look at the specific problems people actually encounter — not general statements about rewriting history, but concrete failures. The list is longer and more varied than you might expect.
Before diving in, two clarifications. First, the workflow assumed here is a typical team setup: a central main branch that is protected from force pushes, feature branches with pull requests, and deploys from main on every merge. Other workflows, like open source projects or desktop software with releases, operate differently. Second, note that there are two distinct kinds of rebase:
- Rebasing on an ancestor, e.g.
git rebase -i HEAD^^^^^^^, which squashes commits. This rarely introduces merge conflicts. - Rebasing onto a diverged branch, e.g.
git rebase main. This is where merge conflicts tend to appear.
Keeping that distinction in mind helps because many complaints about rebase really target type 2.
Repeated Conflict Resolution
If you make many small commits, rebasing onto a diverged branch can force you to resolve the same conflict over and over — or resolve conflicts in code that a later commit deletes. Two strategies help:
- Squash first, then rebase. Run
git rebase -i HEAD^^^^^^^^^^^to collapse tiny commits into one, thengit rebase main. Conflicts get resolved only once. - Enable
git rerere(reuse recorded resolution) withgit config rerere.enabled trueso Git automatically replays previously recorded conflict resolutions.
If conflicts crop up more than once during a rebase, a pragmatic move is to run git rebase --abort, squash the commits, and start over.
Undoing a Bad Rebase
Newcomers sometimes finish a rebase that went wrong and then permanently lose a week of work because they didn't know a rebase could be undone. Compared to undoing a merge with git reset --hard HEAD^, recovering from a bad rebase is far less obvious. It is possible, using the reflog:
- Perform a bad rebase (e.g.
git rebase -I HEAD^^^^^and delete some commits). - Run
git reflog.
ee244c4 (HEAD -> main) HEAD@{0}: rebase (finish): returning to refs/heads/main
ee244c4 (HEAD -> main) HEAD@{1}: rebase (pick): test
fdb8d73 HEAD@{2}: rebase (start): checkout HEAD^^^^^^^
ca7fe25 HEAD@{3}: commit: 16 bits by default
073bc72 HEAD@{4}: commit: only show tooltips on desktop
- Find the entry immediately before
rebase (start). - Run
git reset --hard <that-commit>.
Alternative recovery methods: git reset --hard @{1} resets the branch to its previous location, or you can create a backup branch beforehand with git switch -c backup.
Force Pushing to Shared Branches
Collaborating on a branch and then rebasing it introduces real risk. The scenario goes like this: you push changes to a shared branch, a collaborator rebases and runs git push --force, and everyone else's next git pull fails with fatal: Need to specify how to reconcile divergent branches. Recovering can mean multiple people digging through the reflog, and commits can get lost in the process.
The standard avoidance advice: don't rebase shared branches, and when force pushing is absolutely necessary, use --force-with-lease. That flag protects against overwriting work someone else pushed after your last fetch — but only if nothing was fetched in between. Running git fetch immediately before git push --force-with-lease defeats the protection entirely.
Why do people force push to shared branches at all? Some do it intentionally on collaborative feature branches that need rebasing onto main. Open source maintainers may rebase a contributor's branch to fix conflicts. Others do it by accident — because they copied instructions online, or they were used to force pushing a personal branch and grabbed the wrong one.
Reviewing Force-Pushed PRs
Force pushing also complicates code review. If you rebase and force push after addressing review comments, the reviewer sees all commits as "new" and can't easily tell what changed since the last round. One solution: push new commits addressing feedback first, and only rebase to clean up the history after the pull request is approved.
Metadata and Intermediate Commits
Squashing with rebase can strip commit metadata like Co-Authored-By trailers, and GPG signatures are lost during any rebase. There is no simple workaround here beyond re-adding the metadata afterward.
Rebasing can also break intermediate commits in an atomic-history workflow where every commit is expected to pass tests. Even if the final commit is fine, the replayed intermediate ones may not be. Running git rebase -x to execute the test suite at each step can catch this, though it's rarely used.
Process Confusion
When resolving a conflict during a rebase, it's easy to run git commit --amend instead of git rebase --continue. The confusion is understandable: both occur while editing files during a rebase. But an edit in git rebase -i expects git commit --amend when done, while a merge conflict expects git rebase --continue. Mixing them up creates a stray commit with the wrong message or author.
Splitting Commits and Complex Rebase
Splitting a commit during an interactive rebase is notably harder than combining ones, especially if the target commit is several revisions back. Even comfortable rebase users may reach for git reset HEAD^^^ and rebuild history from scratch instead. Similarly, trying to do too much in one interactive rebase — reordering, squashing, and editing simultaneously — gets confusing fast. The safer pattern is one operation per rebase.
Long-lived branches are another pain point. Rebasing a branch that has lived for a month repeatedly gets tedious, and a single merge at the end might be more practical. Avoiding long-lived branches is ideal, though not always realistic.
Less Common Pitfalls
- Stopping a rebase incorrectly: aborting a bad rebase with
git reset --hardinstead ofgit rebase --abortleaves things in a weird state until properly stopped. - Interactions with merge commits: rebasing a branch that contains merges can produce ugly results — an interactive rebase of
HEAD~4might show dozens of commits if the fourth commit back is a merge. As one practitioner put it: never rebase if anything was merged from another branch.
Rebase and Commit Discipline
Disagreements about rebase often mask different expectations about commit quality. People generally fall into three levels:
- Anything goes — commits like "wip", "fix", "idk".
- Pull request cleaned up — all changes squashed into one reasonable commit, often titled by the PR name.
- Atomic beautiful commits — history split into well-messaged commits that tell a coherent story.
Levels 1 and 2 don't require rebase. Level 2 is easy via GitHub's "squash and merge" or git merge --squash at the command line. Level 3, however, typically requires rebase or a similar history-editing tool. Arguments about whether rebase "should" be used may really be arguments about what level of commit discipline is expected. The size of changes matters too — a 6000-line change benefits from being split into multiple commits, while a small pull request can be squashed without loss.
A No-Rebase Alternative
A workflow that skips rebase entirely:
- Make commits as you go.
- Periodically run
git merge mainto integrate the main branch and resolve conflicts. - When the work is done, use GitHub's "squash and merge" (or
git checkout main; git merge --squash mybranch) to collapse everything into one commit.
This approach avoids ugly merge commits in history, and git log main..mybranch still shows only the changes on your branch. It's not aimed at those who deliberately craft atomic commits — just an easier path for cleaning up a messy history like "add new feature; wip; wip; fix; fix" without touching rebase.
The catalog of rebase pitfalls is broader than even regular users might expect. Many of these problems resolve with practice — knowing when to abort, how to use the reflog, and keeping rebases simple. But the accumulated risk makes it wise to be cautious before recommending rebase to newcomers without explaining safe usage patterns first.



