← Back to list

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…

Mohammed Faham · 2026-07-06 08:13 · 0 claps · 4.1 min read
#git #git-basics #github #git-bash #git-rebase
Open on Medium ↗
Wiki topics: 🔓 · Open Source

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:

  1. Find the Common Ancestor: Git finds the “Merge Base” (the exact commit where feature branched away from main).
  2. Save the Deltas: Git takes every commit you made on feature since that split, calculates the exact changes (diffs) introduced by each one, and saves them in temporary memory.
  3. Reset the Pointer: Git forcefully moves the feature branch pointer to exactly match the current tip of main.
  4. 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.

  1. Open api.py and fix the text markers.
  2. Run git add api.py to stage the fix.
  3. 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 rebase that same branch onto main (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 merge instead.

Hands-off Exercises

Level 1: The Clean Slate

  1. Create a new directory and initialize Git.
  2. Create base.txt, add text, and commit on main.
  3. Create a branch called update and switch to it. Add a line to base.txt and commit.
  4. Switch back to main. Add a different file hotfix.txt and commit.
  5. Switch to update. Run git rebase main.
  6. Run git log --oneline --graph --all to 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