
What Git Rebase Actually Does to Your Commit History
Five commits touching the same lines of code don't trigger one merge conflict. They trigger up to five, because rebase resolves each replayed commit against the evolving tree independently instead of reconciling everything in one pass. So when does that per-commit replay turn from a minor annoyance into a punishing conflict loop, and when should you just use merge instead?
The replay mechanism is where things get messy. Say five of your commits touch the same lines, and the target branch has changed those same lines since you branched off. Git doesn't resolve that conflict once. It resolves it up to five separate times, once per commit, because each commit gets applied independently against whatever the tree looks like at that moment.
- Each commit gets checked out, diffed, and reapplied as its own step in the git rebase --continue loop.
- Every replayed commit gets a fresh SHA, which breaks any reference to the old commit IDs.
- There's no unified resolution point. Unlike a merge commit, nothing brings all the conflicting lines together to get resolved at once.
- Order matters more than people expect: when the branch being rebased includes merge commits, a replay order that isn't strictly timestamp-based can produce different results depending on how those merges get unraveled, something documented repeatedly in GitLab-style trunk workflow discussions.
- Git's rerere feature (reuse recorded resolution) can auto-apply a fix you made before, but it doesn't reliably catch cases where merge commits got unraveled and replayed in a different order than last time.
The practical effect: rebase trades one big reconciliation for a bunch of small ones. Fine tradeoff for a short-lived branch with a handful of commits. Miserable one for a branch with dozens of tiny commits touching overlapping code. The decision to rebase should hinge on commit count and branch age, not habit. And that tradeoff, many small resolutions instead of one big one, is exactly what turns a manageable rebase into a conflict loop once branch age and commit count cross a certain threshold.
Why Conflict Loops Happen and When to Stop Rebasing
Conflict loops happen because rebase resolves the same logical change multiple times instead of once. Practitioners writing about Git internals have documented this for years: make enough small commits, and if several touch the same block of code, you end up resolving what's functionally the same conflict ten times over, once for each commit in the replay sequence. Worse, sometimes you'll burn time resolving a conflict in code that a later commit in your own branch deletes entirely. That resolution effort was dead on arrival.
It gets a lot worse on long-lived branches. A branch that survives a month and gets rebased repeatedly against a moving target forces you to redo conflict resolution every single time, instead of once. One workflow practitioners describe involves two long-running trunks where merge commits from pull requests kept landing in a shared branch. That setup produced repeated conflicts during rebase, even with rerere turned on, because the merges kept getting unraveled and replayed on top of each other differently each time.
- Use git merge instead: for any branch alive longer than a few days, one merge commit at the end resolves the accumulated drift once, rather than forcing you to resolve it incrementally on every rebase.
- Trunk-based development fixes this in theory, through short-lived branches, though in practice teams don't always pull it off. Long-lived feature branches stick around anyway.
- "Fix merge issues" commits, the follow-up patches for leftover conflict damage, show up after both merging and rebasing. Switching strategies doesn't erase the cleanup work.
- git rebase --continue vs git commit --amend: running amend during a paused rebase is generally a bad idea. It can mess with the in-progress rebase state.
- Force-push risk: updating a shared remote branch after a rebase requires a force push, and that can silently wipe out a collaborator's commits if they pushed to the same branch while you were rebasing.
None of this makes rebase a bad tool. It makes rebase a tool with a narrow operating window. It works great on small, recent, single-author branches, and degrades predictably as commit count, branch age, and merge-commit contamination climb. Developers arguing rebase versus merge in 2026 are really arguing about branch lifetime management, not just which command leaves a prettier log. So here's the concrete answer: reach for merge once a branch outlives a few days or piles up commits that keep touching the same lines, and save rebase for branches short and clean enough that one replay pass stays cheaper than one merge commit. Teams that write that threshold down as policy, capping branch lifetime and commit sprawl, end up with far fewer repeated conflicts than teams that leave it to individual taste.