Rewriting History With Git Rebase, Reset, and Amend
Photo © Matt Slack, used with permission. https://flic.kr/p/bpfPH7
While reviewing changes to a feature before submitting a PR, 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, 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 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 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.
 We utilize Github Pull Requests (PRs) for peer code review before committing changes to master.
 The current HEAD commit can be modified with
git commit --amend
 This is short for the master branch’s
HEAD commit. This works because our feature branch was originally branched off of master.
 The –mixed flag is the default reset mode and does not need to be explicitly specified.