Advanced Git History Editing: Amending Commits and Interactive Rebase

Use git commit --amend and interactive rebase to clean local history without disrupting shared branches.

Advanced Git History Editing: Amending Commits and Interactive Rebase

Advanced Git history editing helps you clean up commits before they become part of shared history. When you understand amending commits and interactive rebase, you can fix small mistakes, combine noisy commits, and present a clearer story for code review.

The key rule is simple: editing local history is normal, but rewriting shared history needs care. The commands are powerful because they change commit IDs, not just commit messages.

What Git History Editing Actually Changes

Every Git commit has an ID based on its contents, metadata, parent commit, author, date, and message. If you amend a commit or rewrite it during a rebase, Git creates a new commit with a new ID.

That is fine when the commit exists only on your machine. It is risky when other people already pulled the old commit. Their branches may still point to the old history, while yours points to the rewritten history.

Use history editing for:

  • Fixing a typo in the latest commit message.
  • Adding a forgotten file to your last local commit.
  • Squashing several work-in-progress commits before opening a pull request.
  • Reordering local commits so related changes are easier to review.
  • Splitting one large local commit into smaller logical commits.

Avoid history editing on:

  • Main branches.
  • Release branches.
  • Shared feature branches used by multiple people.
  • Any branch with deployment tags or audit-sensitive commits.

Before you start, check what branch you are on and what is already pushed:

git status
git branch --show-current
git log --oneline --decorate -5

If you are unsure whether rewriting is safe, create a backup branch:

git branch backup-before-rebase

That branch gives you a known recovery point if the rebase goes sideways.

Amending the Latest Commit

git commit --amend replaces the most recent commit with a new one. It is the fastest way to fix the last commit before anyone else depends on it.

To edit only the commit message:

git commit --amend

Git opens your editor with the current message. Save the corrected message, and Git creates a replacement commit.

To add a forgotten file to the last commit:

git add path/to/file
git commit --amend --no-edit

The --no-edit flag keeps the existing message. This is useful when the commit message is already right and you only forgot to stage one change.

Here is a common scenario. You commit a Dockerfile update, then notice you forgot the related .dockerignore change:

git add Dockerfile
git commit -m "Improve Docker build caching"
git add .dockerignore
git commit --amend --no-edit

Now the branch has one clean commit instead of a second commit that says "forgot file." That makes review easier.

If the original commit was already pushed, the remote branch still has the old commit ID. Pushing the amended commit requires a force-style update:

git push --force-with-lease

Prefer --force-with-lease over --force. It refuses to overwrite the remote branch if someone else pushed new work since your last fetch.

Cleaning Up Multiple Commits with Interactive Rebase

Interactive rebase lets you edit several commits at once. You choose a range, then Git opens a todo list where you can pick, reword, squash, fix up, reorder, or stop at commits.

To edit the last five commits:

git rebase -i HEAD~5

You will see a list like this:

pick a1b2c3d Add deployment script
pick b2c3d4e Fix typo
pick c3d4e5f Add health check
pick d4e5f6a Update docs
pick e5f6a7b Adjust timeout

Change the command at the start of each line to control what happens. Common choices are:

  • pick: keep the commit as-is.
  • reword: keep the changes but edit the message.
  • squash: combine this commit into the previous one and edit the combined message.
  • fixup: combine this commit into the previous one and discard this commit's message.
  • edit: stop at this commit so you can change its content.
  • drop: remove the commit.

For example, if "Fix typo" belongs with "Add deployment script," change the second line:

pick a1b2c3d Add deployment script
fixup b2c3d4e Fix typo
pick c3d4e5f Add health check
pick d4e5f6a Update docs
pick e5f6a7b Adjust timeout

Save and close the editor. Git replays the commits and combines the typo fix into the earlier commit.

Interactive rebase is also helpful for improving commit messages before a pull request. If three commits all say "update," use reword and turn them into messages that explain the actual change.

If a conflict appears, resolve it like a normal merge conflict:

git status
git add resolved-file
git rebase --continue

If you decide the rebase is not worth it:

git rebase --abort

That returns your branch to the state before the rebase started.

Splitting a Commit During Rebase

Sometimes one commit contains two unrelated changes. For example, you might have one commit that updates a Kubernetes manifest and also fixes a README section. Those changes should probably be separate.

Start an interactive rebase:

git rebase -i HEAD~3

Change pick to edit for the commit you want to split. When Git stops at that commit, reset it while keeping the changes in your working tree:

git reset HEAD^

Now stage and commit the first logical piece:

git add k8s/deployment.yaml
git commit -m "Update deployment health check"

Then stage and commit the second piece:

git add README.md
git commit -m "Document health check behavior"

Continue the rebase:

git rebase --continue

This turns one broad commit into two focused commits. Reviewers can understand each change without mentally separating unrelated work.

When to Get Help Before Rewriting

Ask for help before rewriting any branch that other people use. A team lead, release engineer, or repository maintainer can tell you whether the branch is safe to rewrite and how the team handles force pushes.

Get help immediately if a rebase affects commits that are already deployed, tagged, or referenced by incident reports. In those cases, preserving history is often more important than making it look tidy.

For routine feature branches, history editing is a normal cleanup step. Use git commit --amend for the latest commit, interactive rebase for a small local series, and --force-with-lease when you must update a remote branch you own.