Change the contents of an old commit
How do I edit a commit that isn't the most recent one?
Short answer
Mark the commit edit in git rebase -i. Git stops there, you make your changes and amend, then git rebase --continue replays the rest. The tidier route is git commit --fixup plus an autosquash rebase.
git rebase -i HEAD~3
# set 'edit' on the target, then amend and continue
Pause history at a commit so you can modify it in place
Does this match your situation?
- You forgot a file in a commit three commits back.
- An old commit contains a debug statement or a typo.
- A reviewer asked you to change something in an earlier commit of the series.
Step-by-step fix
The clean way: commit a fixup and autosquash
Make the correction now as a normal change, label it as a fixup for the target commit, then let rebase fold it in automatically. No manual editing of the rebase list at all.
step 1git add src/app.ts git commit --fixup a1b2c3d git rebase -i --autosquash a1b2c3d~1 # the list is pre-arranged; just save and closeThe manual way: stop at the commit
Mark it edit and the rebase pauses with that commit checked out, leaving you in an ordinary working state.
step 2git rebase -i HEAD~3 # pick a1b2c3d Older commit # edit f4e5d6c The one to change <- changed from pick # pick 9a8b7c6 Newer commitMake your changes and amend
Edit files, stage them, and amend — this replaces the paused commit rather than adding a new one after it.
step 3git status # you are AT that commit now # edit files... git add src/app.ts git commit --amend --no-editContinue the rebase
The remaining commits replay on top of your amended one. Resolve conflicts if the later commits touched the same lines.
step 4git rebase --continue git log --oneline -5Push the rewritten branch
Every commit from the edited one onwards has a new hash.
step 5git push --force-with-leaseOnly on branches you own. Coordinate first if anyone else has pulled them.
Why this works
Commits are immutable — you never truly edit one. Interactive rebase replays your history and, when it reaches a commit marked edit, hands control back with that commit checked out and its changes applied. Amending at that moment creates a replacement commit, and continuing replays everything after it onto the new parent. The result looks like an in-place edit but is really a rebuild, which is exactly why all the hashes downstream change.
How to stop it happening again
- Use git commit --fixup as soon as you spot a problem, then autosquash before pushing.
- Set rebase.autoSquash true globally so --autosquash is implied.
- Review with git diff --staged so fewer commits need fixing at all.
Commands used in this guide
Still stuck?
Search the full command reference and every other rescue guide — there are 56 of them, covering everything from detached HEAD to force-push disasters.
Browse all guides →Frequently asked questions
How do I edit an old commit in Git?
Run git rebase -i with a range covering it, change its action to edit, make your changes when the rebase pauses, run git commit --amend, then git rebase --continue. Everything after it is replayed onto the amended commit.
What is git commit --fixup?
It creates a commit whose message marks it as a fix for a specific earlier commit. Running git rebase -i --autosquash then positions it directly after its target with the fixup action already set, so folding it in requires no manual editing.
Is editing old commits safe?
On a private branch, entirely - the originals stay in the reflog if you need them back. On a shared branch it rewrites history others have pulled, so either coordinate a force-push or add a normal follow-up commit instead.
Related rescue guides
How do I edit a Git commit message?
For the most recent commit, git commit --amend -m "new message" replaces it. For older commits, git rebase -i lets you mark any of them as reword. Both rewrite history, so if the commit is already pushed you'll need git push --force-with-lease and a word to your team.
Read the fix →Always fixableHow do I break a large commit into multiple commits?
Mark the commit as edit in git rebase -i, then run git reset HEAD~ to turn it back into unstaged changes. Stage the pieces one at a time with git add -p, commit each, and finish with git rebase --continue.
Read the fix →Always fixableHow do I remove a single commit without losing the ones after it?
Mark it drop in git rebase -i and Git replays everything except that commit. On a shared branch, git revert is the safe alternative — it neutralises the change without rewriting anyone's history.
Read the fix →Always fixableHow do I combine multiple commits into a single commit?
git rebase -i HEAD~n opens an editor where you mark commits as squash or fixup to fold them into the one above. For a quick all-in-one collapse, git reset --soft HEAD~n followed by a fresh commit achieves the same result with no editor at all.
Read the fix →