June 11 2014
Git Tip: Logical commits with git stash
Commits should always be logical, atomic changes, but parceling out your working copy into logical commits is often a struggle. Adding individual files to a certain commit is straight-forward, but adding just a subset of changes in a given file while not losing the other changes is more difficult.
In the past, I had two strategies. Sometimes, I copied a file from Xcode into TextMate, reverted unrelated changes in Kaleidoscope, committed the logical piece, then pasted the original file back into Xcode. Bit of a pain, and it didn’t scale well to many files. Other times, I counted on Undo (Command-Z) to remember what Kaleidoscope clobbered. Undo didn’t always remember what I thought it should.
Recently, I came up with a cleaner strategy using git stash apply:
- Make many overlapping changes and decide to commit a number of chunks.
- git stash – This saves your working copy as a temporary commit.
- git stash apply – This restores your working copy while keeping the temporary commit.
- Revert all unrelated changes and commit the first piece.
- git stash apply – This restores the original working copy again and silently merges in your matching changes.
- Repeat (4) and (5) until your commits match the working copy.
- git stash pop – If your commits match your original working copy, the stash will be dropped without issue, and your working copy will remain empty.
Update: As @cocoadog and @glebd point out on Twitter, there are other alternatives. You can use GitHub for Mac or SourceTree, which both have this selected-lines feature. And, for the brave, you can do interactive staging using git add -p or git add -i.