Rewriting History With Git Rebase, Reset, and Amend

Photo © Matt Slack, used with permission.

While reviewing changes to a feature before submitting a PR[1], I noticed I had mistakenly committed unwanted changes to db/schema.rb in an earlier commit. The unwanted changes included a leftover retailer\_locations table from a database migrated with changes for a separate feature and a change in column order.

As I wanted to keep the commit history clean and the offending commit was a few commits back, I reached for a handy pattern for rewriting git history: rebase, reset, and amend.

git rebase -i master

To modify a commit further back in history than the HEAD commit,[2] we will need to utilize git’s handy rebase tool. While git rebase serves many purposes, we will provide an argument of the commit SHA one further than the commit(s) we want to change. In our case, we’ll specify master[3] to rewrite commits in the range master..HEAD. We will add the -i flag to make the rebase interactive to give ourselves complete control over the git history and the opportunity to alter individual commits. We will change the pick next to the commit we would like to modify to edit to specify that we want to “use the commit, but stop for amending”.

git reset HEAD^ db/schema.rb

In many cases the necessary change can be made directly to the file, staged for commit, and then amended to the current commit. In our case, however, we will want to reset the file, update what parts of the file are staged for commit, and then amend the current commit with this change. We will do this by telling git to reset db/schema.rb to the version in the parent commit. We will use the default --mixed[4] action to reset the index but maintain the working tree.

git add -p db/schema.rb

With the original changes still staged for commit we will update the index for db/schema.rb, this time specifying the -p flag to interactively select which portions of the file to add to the index. We enter y for portions we want to commit, n for portions we don’t.

git commit --amend

With the correct portions of the db/schema.rb file staged we amend the current commit. Et voila, we have rewritten our git history. We force push our rewritten branch and after another quick review of our changes we open the PR for peer review.

[1] We utilize Github Pull Requests (PRs) for peer code review before committing changes to master.

[2] The current HEAD commit can be modified with git commit --amend

[3] This is short for the master branch’s HEAD commit. This works because our feature branch was originally branched off of master.

[4] The –mixed flag is the default reset mode and does not need to be explicitly specified.

Photo of Eric Milford

Eric’s career in developing well-architected web applications spans over a decade. He’s worked for established companies and small startups.


    Rebecca Ripon
    July 30, 2019 at 8:36 AM

    Thanks for that it really helped a lot - Rebecca Ripon