Commit only part of a file with `git add -p`

Published: 2020-11-15
|
Updated: 2020-11-15

Almost every time I git add, I actually git add -p. It feels kinda weird and scary not to now. The -p is short for --patch and adds just enough cleverness to stop all sorts of silly commit mistakes happening. Have you ever wanted to commit only a subset of the changes you’ve made to a file, without undoing the others? Patch mode lets you step through all the changes in any file you’re about to add, and select which to include on a line-by-line basis. Maybe it’s best described with a small example.

Let’s say we’re changing a style file to remove the background colour from this very site. In tandem, we’re toying with changing the colour of horizontal rules. We’d like to commit the background colour change, but not the other horizontal rule change. Patch mode is going to let us do this without having to do anything tedious like temporarily removing some code.

When we git add -p our style file, git brings up this command line interface.

The git patch interface with a patch that is accepted.

It’s showing a diff of the first change in the file. In this case it’s a very small change, so it’s nicely isolated. Sometimes, multiple changes will be pulled into one diff, in which case we could ask git to try harder to split them by entering s at the prompt. In this instance, we do want to add that change to the commit, so we enter y at the prompt. Now, we’re presented with the next change.

The git patch interface, with a patch that is rejected.

We don’t want to commit that change right now, so we enter n at the prompt. The commit will include only the parts of the changed file that we want!

A little warning: the git status associated with this commit will show the style file in both the “Changes to be committed” and the “Changes not staged for commit” sections. This is correct! There are changes to be committed and changes not to be committed in the same file.

There are a lot more commands to patch mode, but my workflow was vastly improved by knowing only the three above:

  • y to include a change
  • n to ignore it for this commit
  • and s to split a change into smaller chunks for review

We can Ctrl+C to back out of the git add altogether. I see two big benefits to patch mode:

  1. It enables committing in logical chunks, which might not be the same as file chunks. Sometimes we need to work ahead in a file and make changes that shouldn’t be bundled into one big commit.
  2. It forces us to review all our changes before committing. This has prevented me making all sorts of silly commit mistakes. Even when I want to commit a whole file, I almost always walk through each change in patch mode to do so.

There’s a small gotcha to be aware of. When you add a bunch of files with git patch, using a git command like

git add -p patched_file.py another_patched_file.py new_file.py

you’ll be presented the interface to step through patched_file.py and another_patched_file.py. Since new_file.py is (here) a new file, there are no changes to step through, and it won’t be added to the commit. Just add new files separately to changed files.