Git: Rewriting the Past
In Part 4, we learned how to merge. Merging is non-destructive; it preserves the exact, messy reality of when you branched off, what you…
Git: Rewriting the Past

In Part 4, we learned how to merge. Merging is non-destructive; it preserves the exact, messy reality of when you branched off, what you did, and when you came back. Over time, a heavily merged project looks like a complex subway map with tracks splitting and converging everywhere.
Rebasing is an alternative way to integrate changes. It is a tool for perfectionists who want a completely clean, linear project history.
Imagine you pull a book off a shelf, write a new chapter on loose paper, and then realize the author published an updated edition of the book while you were writing.
- Merging is like taking your loose chapter, stapling it to the back of the updated book, and writing a note: “These two versions are now combined.”
- Rebasing is like magically lifting your loose chapter, sliding it into the updated book exactly where it belongs, and seamlessly rewriting the page numbers so it looks like you wrote your chapter after the author’s updates, in perfect chronological order.
Formal Explanation & Mechanics
Under the hood, git rebase is fundamentally different from git merge. While a merge creates a new commit with two parents to tie histories together, a rebase rewrites history by creating brand new commits.
Here is the exact mechanical sequence when you are on branch feature and run git rebase main:
- Find the Common Ancestor: Git finds the “Merge Base” (the exact commit where
featurebranched away frommain). - Save the Deltas: Git takes every commit you made on
featuresince that split, calculates the exact changes (diffs) introduced by each one, and saves them in temporary memory. - Reset the Pointer: Git forcefully moves the
featurebranch pointer to exactly match the current tip ofmain. - Replay the Commits: Git takes those saved changes and applies them one by one onto the new base.
The Critical Detail: Because a commit’s cryptographic SHA-1 hash is generated using its parent commit’s hash, applying these changes to a new parent generates entirely new hashes. Your old commits are orphaned and deleted by Git’s garbage collector. You have literally rewritten the timeline.
Concrete Examples & Code
Let’s walk through a standard rebase workflow in the terminal.
Step 1: The Setup (Diverging Timelines): Imagine main has moved forward with an important security patch, but you are still working on your feature-agent branch. You want that security patch in your branch before you finish your work.
# You are currently on your feature branch
git branch
# Output:
# main
# * feature-agent
Step 2: The Rebase: You tell Git to lift your branch and put it on top of main.
git rebase main
# Output:
# Successfully rebased and updated refs/heads/feature-agent.
If there were no conflicting lines of code, the process is instantaneous. If you run git log, you will see your commits neatly stacked on top of the latest main commits, with brand new hashes.
Step 3: Handling Rebase Conflicts Because Git replays your commits one by one, conflicts happen differently than in a merge. If a conflict occurs, Git pauses the rebase at that specific commit.
# Example Output during a conflict:
# CONFLICT (content): Merge conflict in api.py
# error: could not apply 3a4b5c6... Add new API endpoint
# Resolve all conflicts manually, mark them as resolved with
# "git add/rm <conflicted_files>", then run "git rebase --continue".
Unlike a merge, you do not run git commit after fixing a rebase conflict.
- Open
api.pyand fix the text markers. - Run
git add api.pyto stage the fix. - Run
git rebase --continue. Git will finish creating that commit and move to replaing the next one.
Common Misconceptions & Pitfalls
THE GOLDEN RULE OF REBASING: Never rebase commits that exist outside your repository and that people may have based work on.
The Disaster Scenario: You push a branch to GitHub. Your colleague downloads it and starts adding code to it. Meanwhile, you locally
git rebasethat same branch ontomain(rewriting all the commit hashes!) and force-push it back to GitHub. The Result: When your colleague tries to push or pull, Git realizes their history and the server's history have completely different cryptographic hashes. Git panics, resulting in a catastrophic mess of duplicate commits and broken timelines that will take hours to untangle.
Summary: Only rebase local branches that you have never pushed to a public remote. Once a commit is public, treat it as immutable. Use
git mergeinstead.
Hands-off Exercises
Level 1: The Clean Slate
- Create a new directory and initialize Git.
- Create
base.txt, add text, and commit onmain. - Create a branch called
updateand switch to it. Add a line tobase.txtand commit. - Switch back to
main. Add a different filehotfix.txtand commit. - Switch to
update. Rungit rebase main. - Run
git log --oneline --graph --allto verify you now have a perfectly straight, single line of history.
Level 2: The Abort Just like merging, if you get halfway through resolving conflicts during a rebase and realize you’ve made a terrible mistake, Git has a ripcord. Run git rebase --abort. Git will immediately stop the process and return your repository to the exact state it was in before you typed git rebase.
Sources & Recommended Resources
- Source: Chacon, S., & Straub, B. (2014). Pro Git. (Chapter 3.6: Rebasing). Read the section titled “The Perils of Rebasing” specifically. git-scm.com/book/en/v2/Git-Branching-Rebasing
- Resource: Atlassian Git Tutorial on Merging vs. Rebasing. This is considered an industry-standard guide for teams deciding which workflow to adopt.
What’s Next?
We now know how to move commits around. But what if you want to fundamentally change the commits themselves?
Next up: We look at Part 8: Interactive History Rewriting. This is Git’s scalpel. We will use git rebase -i to combine (squash) five messy commits into one perfect commit, rename old commits, and quietly delete mistakes from history before anyone else sees them.
메타데이터
- post_id
- 60f49d4a1e1d
- slug
- git-rewriting-the-past-60f49d4a1e1d
- url
- https://medium.com/@mohdfahamb/git-rewriting-the-past-60f49d4a1e1d
- canonical_url
- https://medium.com/@mohdfahamb/git-rewriting-the-past-60f49d4a1e1d
- author_url
- https://medium.com/@mohdfahamb
- status
- ok
- fetched_at
- 2026-07-07 00:45:30