← Back to list

Git: Rewriting History

In Part 7, we used rebase to cleanly stack our commits on top of another branch. But what if the commits themselves are a mess?

Mohammed Faham · 2026-07-09 10:01 · 0 claps · 4.7 min read
#github #git #git-bash #git-basics #git-rebase
Open on Medium ↗
Wiki topics: 🔓 · Open Source

Git: Rewriting History

In Part 7, we used rebase to cleanly stack our commits on top of another branch. But what if the commits themselves are a mess?

Imagine you are working locally for a few hours. Your commit history looks like this:

  • Commit 1: Implement core login logic
  • Commit 2: Fix typo in login logic
  • Commit 3: Oops, forgot a semicolon
  • Commit 4: Add user authentication tests

If you push this to a professional team, they will see all your minor mistakes. It is messy and hard to review. Interactive Rebasing is your time machine’s editing room. Before you publish your work, it allows you to pause time and mold your local history. You can squish Commits 1, 2, and 3 into a single, beautiful commit, rename the message, or simply delete “Commit 3” from history entirely as if it never happened.

Formal Explanation & Mechanics

The command git rebase -i (the -i stands for interactive) leverages the same underlying mechanics we learned in Part 7 (saving deltas, moving the pointer, and replaying). However, instead of immediately applying the commits to a new base, Git opens a text file containing a script of the commits about to be replayed.

You, the user, edit this script. Git then reads your edited script top-to-bottom and executes the commands.

The Rebase Script Commands: When Git opens your default text editor, you will see a list of commits prefixed with the word pick. You can change pick to several other commands:

  • pick (or p): Use the commit exactly as it is.
  • reword (or r): Use the commit, but pause to let me rewrite the commit message.
  • edit (or e): Pause the rebase entirely at this commit so I can add new files or change code before continuing.
  • squash (or s): Melt this commit's changes into the commit immediately above it in the list, and let me combine their messages.
  • fixup (or f): Exactly like squash, but discard this commit's message (keep only the previous commit's message).
  • drop (or d): Delete this commit and its changes from history entirely.

(Mechanics Note: Because we are altering the content or metadata of the commits, Git generates entirely new SHA-1 hashes for all commits processed during this operation, just like a standard rebase. The Golden Rule of Rebasing still applies: Do not do this to commits you have already pushed.)

Concrete Examples & Code

Let’s clean up a messy local branch before pushing it to GitHub.

Step 1: Inspect the Messy History: Assume you have made three commits on your branch.

git log --oneline
# Output:
# 3c4d5e6 (HEAD) Fix syntax error
# 2b3c4d5 Add debug print statements
# 1a2b3c4 Write initial data parsing script
# 0f1e2d3 (main) Previous stable commit

We want to combine 3c4d5e6 and 1a2b3c4, and completely delete 2b3c4d5 (because we don't want debug prints in production).

Step 2: Initiate Interactive Rebase: We tell Git we want to interactively rebase the last 3 commits. (HEAD~3 means "three commits before where I am now").

git rebase -i HEAD~3

Step 3: Editing the Script: Git immediately opens your terminal text editor (often Vim or Nano) with this script:

pick 1a2b3c4 Write initial data parsing script
pick 2b3c4d5 Add debug print statements
pick 3c4d5e6 Fix syntax error

# Rebase 0f1e2d3..3c4d5e6 onto 0f1e2d3
# ... (Git provides helpful instructions here)

Note: The script is listed oldest-to-newest (top-to-bottom).

We edit the text to look like this:

pick 1a2b3c4 Write initial data parsing script
drop 2b3c4d5 Add debug print statements
fixup 3c4d5e6 Fix syntax error

We save and close the editor.

Step 4: Git Executes the Script Git reads our instructions:

  1. It applies 1a2b3c4 normally.
  2. It sees drop and completely skips 2b3c4d5 (the debug prints are gone).
  3. It sees fixup and merges the changes from 3c4d5e6 directly into the parsing script commit, discarding the "Fix syntax error" message.
# Output:
# Successfully rebased and updated refs/heads/my-feature.

git log --oneline
# Output:
# 8x9y0z1 (HEAD) Write initial data parsing script
# 0f1e2d3 (main) Previous stable commit

Our history is now a single, perfect commit. Notice the hash changed from 1a2b3c4 to 8x9y0z1.

Common Misconceptions & Pitfalls

The “Vim Panic” Pitfall: By default, Git uses Vim as its text editor on many systems. Beginners frequently get trapped in Vim when git rebase -i opens.

  • To edit in Vim: Press i to enter "Insert" mode. Now you can type.
  • To save and exit: Press Esc (to exit Insert mode), type :wq, and press Enter.
  • To abort the rebase from Vim: Delete all text, or type :cq to exit with an error code, which tells Git to cancel the operation.
  • Pro-tip: If you hate Vim, you can configure Git to use VS Code instead: git config --global core.editor "code --wait".

Misconception: You can’t change the order of commits. You absolutely can. In the text script, you can literally cut and paste the pick lines to reorder them. Git will replay the commits in the new order you specified. (Beware: this frequently causes merge conflicts if the commits touch the same files).

Hands- Off Exercises

Level 1: The Basic Squash

  1. Initialize a new repo and make a base commit.
  2. Create file.txt, add line 1, and commit with message "Add line 1".
  3. Add line 2 to file.txt and commit with message "Add line 2".
  4. Add line 3 to file.txt and commit with message "Add line 3".
  5. Run git rebase -i HEAD~3.
  6. Change the second and third pick commands to squash (or s).
  7. Save and close. Git will pop open the editor again to let you combine the three commit messages. Delete the old ones and write “Add lines 1, 2, and 3”. Save and close.
  8. Run git log to verify you only have one clean commit.

Level 2: The Reword

  1. Make a commit with a terrible typo in the message (e.g., git commit -m "Fx buggs").
  2. Run git rebase -i HEAD~1.
  3. Change pick to reword. Save and close.
  4. The editor opens again. Fix the typo. Save and close. Check git log.

Find my attempt here.

Sources & Recommended Resources

  • Source: Chacon, S., & Straub, B. (2014). Pro Git. (Chapter 7.6: Git Tools — Rewriting History). This chapter is essential reading for advanced Git control. git-scm.com/book/en/v2/Git-Tools-Rewriting-History
  • Resource: Thoughtbot Blog — “Git Interactive Rebase, Squash, Amend and Other Ways of Rewriting History”. Excellent practical walkthroughs.

What’s Next?

We have learned how to surgically alter history. But what happens when an advanced manipulation goes horribly wrong? What if you drop a commit you actually needed, or you run a destructive command by accident?

Next up: We look at Part 9: Advanced Undoing & The Safety Net. We will cover the mechanics of the dangerous git reset command, the safer git revert, and introduce Git's ultimate insurance policy: the reflog, which allows you to recover "lost" or deleted commits.

So long!


메타데이터
post_id
c93d2f2f6a24
slug
git-rewriting-history-c93d2f2f6a24
url
https://medium.com/@mohdfahamb/git-rewriting-history-c93d2f2f6a24
canonical_url
https://medium.com/@mohdfahamb/git-rewriting-history-c93d2f2f6a24
author_url
https://medium.com/@mohdfahamb
status
ok
fetched_at
2026-07-09 23:18:01