If you have been using Git long enough, you have probably heard about
git add -p/--patch, which allows you to selectively stage parts of files. However, did you know that many other Git commands support this argument as well? Among them are
log, and they represent the main topic of the present post.
git add -p
Let’s start with the classic. Suppose you have added a feature and fixed a bug, and both of these changes required you to modify the same files.
$ git status -s M CHANGELOG.rst M retdec/decompiler.py M tests/decompiler_tests.py
As a practitioner of good source control, you want to make your commits atomic, i.e. commit the feature and the bug fix separately. As we have made changes to the same files, we need to split these modifications. This can be done by using the so-called patch mode of
$ git add -p --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,8 +8,10 @@ dev * Added support for selecting the optimizations to be used when compiling C source files. +* Added support for stripping the compiled binary file. * Added support for printing script versions via the ``-V``/``--version`` parameter. +* Fixed the list of supported target high-level languages. Stage this hunk [y,n,q,a,d,/,s,e,?]?
Git will ask us about every change we have made. For each block of changes (a hunk in Git parlance), we can either stage it (
y), skip it (
n), split it into smaller hunks (
s), or manually edit what will be staged (
e). Since we want to commit only e.g. the feature, we need to press
s so Git splits the current hunk into two smaller hunks. Then, we stage the first hunk (
* Added support...) and skip the second one (
* Fixed...). We make a similar decision for the remaining two files.
After we have staged all the changes we wanted, we can commit them:
$ git commit
Tip: Enable colors in Git to make the hunks more readable.
git commit -p
When all we want is to stage changes and then immediately commit them, we can run just
$ git commit -p
which is a shortcut for
$ git add -p $ git commit
git add -p, Git will ask us which changes we want to stage, and then automatically commit them.
git reset -p
Suppose we have staged changes to be committed via
git add. Then, we find out that we have accidentally staged something we did not want to include in the next commit. The situation is easy when we want to unstage all changes in a file:
$ git reset FILE
However, what if we want to unstage only some of the changes done to a file? Git’s patch mode to the rescue! Simply run
$ git reset -p FILE
Git will ask you about each staged hunk whether you want to keep it or unstage it.
Of course, if you want to unstage changes from multiple files, you can run just
$ git reset -p
This will make Git ask us about staged hunks in all files.
Tip: If you want to partially reset a commit,
git reset -p 6b141d7 allows you to do that.
git checkout -p
Sometimes, you may want to throw away some of the changes you have done. The easiest thing to do is to run
$ git checkout -p
which will cause Git to selectively ask you about each hunk whether you want to keep it or discard it.
Beware: When you discard a hunk, it will be lost forever. Think twice before throwing away a hunk!
Another, less-known use of
git checkout -p is when you want to apply changes from one branch to another branch. Suppose there is a branch
bug-572-fix-attempt. As its name suggests, it contains an experimental fix of bug #572. The attempt turned out to lead to a dead end, but you still would like to apply some of the changes to your current branch. To do this, simply run
$ git checkout -p bug-572-fix-attempt
Git will selectively ask you about each changed block of code in
bug-572-fix-attempt whether you want to apply it to the current branch. Say
y to all the changes you want to include.
git stash -p
Stashing is a nice Git feature that allows you to save your unfinished changes, do some other work, and then re-apply the stored changes. However, as you quickly find out, running
$ git stash
will stash all the changes you have made. What if you want to stash only some of the changes? Yes, your guess is correct! We use the patch mode:
$ git stash -p
It will make Git selectively ask us about each change whether we want to stash it or keep it.
git log -p
Last, but certainly not least, you can use the patch mode in tandem with
git log. Lets start with a motivation. During a code review, it is often useful to see a list of changes that were done in the commits under review. When you run
git log, Git only includes basic information about each commit, e.g. its hash, author, and commit message. However, when you run
$ git log -p
Git will also include the changes that were done in each commit:
There you go. As you can see, Git’s patch mode is very powerful. If you know other useful scenarios, be sure to leave a comment!
You can also discuss this post at r/programming.