Code Cleanup: Splitting Up git Commits In the Middle of a Branch

I tend to follow a fairly traditional git development flow. When I am working on a new feature or a bug fix, I will make a branch and commit changes as I progress. I often just quickly commit incremental changes and make brief notes on my logic for that chunk.

I like to clean up these commits prior to merging the changes or submitting a pull request. I take the time to rebase the branch and squash related changes together until I am left with a set of atomic commits.

Sometimes I end up in a sticky situation where I have a single commit that contains changes destined for multiple atomic commits. Perhaps I added multiple files accidentally by using git commit -am, or perhaps I didn't originally notice that changes within a file would eventually be separated. If you catch this early you can revert a commit and split up the changes, but the situation is a little trickier if the offending commit is buried in the middle of a branch with other changes built on top of it.

After handling commit splits multiple times in the past two weeks, I figured I'd document a workflow.

Workflow for Splitting git Commits

Here's how I approach splitting up a git commit buried in the middle of a branch:

  1. Checkout the branch that you want to modify (e.g. pj/feature)
  2. Start an interactive rebase which includes your commit.
    • At a minimum, git rebase -i commit^ will start the rebase at the commit you want to split
    • You can also rebase the whole branch, which I usually do to split all target commits in one go
  3. Mark the commit(s) that you want to split with edit
  4. When git presents the commit that you want to split:
    1. Reset state to the previous commit using git reset HEAD^
    2. Use git add to carefully and incrementally add changes to the index
    3. Run git commit when you have a set of atomic changes that you are ready to commit
    4. Repeat the git add and git commit process until you have processed each set of changes represented by the commit
  5. Run git rebase --continue to resume or finish the rebase

That's all there is to it!

Further Reading