Two weeks ago I wrote about writing nice commit messages. Of course, it would be even nicer if you did not have to change
you commit messages retrospectively but instead created nice atomic commits from the beginning. When people refer to atomic commits they usually mean
commits that are limited to one logical change each. This implies that your commit messages should rarely have the word and
in them. A message like
change heading color and add teaser text
should be split into two commits: change heading color
and add teaser text
. Why? Say your boss comes to you
and lets you know that they really like the new copy but they are not happy with how the color looks on their screen. If you properly split your commits
into two, fixing this is just a quick git revert
away now. If not, you will have to go back and edit the files manually which will be a much more
tedious process.
The problem of course is that sometimes we do make multiple changes while we are in the flow. Luckily, git allows us to only take parts of our changes and bundle them up into artisanal commits. An example might look like this:
When you call git add <filename>
, you can pass it an additional flag: -p
. That is p
as in partial. When you pass this flag to it, git will present you hunks of code
and ask you what to do with them: Stage this hunk [y,n,q,a,d,s,e,?]?
. Typing ?
and hitting enter here will present this explanation to you:
n - do not stage this hunk
q - quit; do not stage this hunk or any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk or any of the later hunks in the file
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
In the video above, you can see me using three of those options: s
, y
and n
. When I start the partial add, git presents me with one big hunk. This hunk includes
both changes that I made: the added style
block as well as the new p
element. As the very reason why I started this in -p
mode was that I did not want
to make both changes in one commit, I am replying with s
to ask git to split the hunk up further for me. It does so and only asks me about the style
section afterwards.
I say that it should stage this but not the other one. Afterwards, I run a quick git diff --staged
(the opposite of a regular git diff
) to see the changes
that are now made. I am happy and commit those. Afterwards, only the p
change is left which I can add with a regular git commit -am
.
There is one more trick that might sometimes be helpful. If you made changes in neighboring lines and want to put those in separate commits, git might not split them up enough for you. In this case, you can use the edit command:
Once you enter edit mode, git offers three choices again:
# To remove '-' lines, make them ' ' lines (context).
# To remove '+' lines, delete them.
# Lines starting with # will be removed.
In the video you can see me enter edit mode by hitting e
. The diff opens in my editor of choice and I can hand-pick what should be done with each line by editing
the first character (this might feel familiar from the interactive rebase example). I pick the line
that I am not interested in (the font-family
) and change the character to #
so that this line is excluded. This leaves me with just the changes that I want.
Of course there are also graphical tools to achieve this. I often use gitx to do partial adds but I think it is good to know that all of this can also be done from the command line in case you ever find yourself somewhere without a GUI available.