‘git add –p’ is awesome

It lets you stage parts of files for commit, let me show you how.

Intro

I cannot do one thing at a time, I try to, but never succeed. Especially when It comes to coding. All the time I find myself working on a feature, and when jumping around in the code base I find stuff that needs fixing, and I fix it. As a result of this, my commit messages often have a bullet list, or some “and”s in there. I don’t like this at all – but on the other hand, I don’t like commit messages that hide what the commit does. But today, from the InfoQ presentation by Scott Chacon, A tale of three trees, I learnt about “git add –p”. My git mentor at work Philip Nilsson pointed me to it. Let me show you how it works.

The starting point

public void TemplateMethod()
{
	MethodA();
	MethodB();
}

public void MethodA()
{
	//code

}
public void MethodA()
{
	//code

}

After some coding

public void TemplateMethod()
{
	MethodA();
	MethodB();
}

public void MethodA()
{
	//code
	//fix in A
}
public void MethodA()
{
	//code
	//fix in B
}

running “git status” on this shows

# Changes not staged for commit:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#       modified:   foo.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

just as you would expect, the changes are there and unstaged.

The partial stage

So, what if I now only want to stage and commit the fix in method A, not method B. Easy! Just run:

git add -p

That command will diff you working dir and feed you with each change separately, and ask you what to do with it.

First output:

$ git add -p
diff --git a/foo.txt b/foo.txt
index 0169cf2..ca42269 100644
--- a/foo.txt
+++ b/foo.txt
@@ -7,7 +7,7 @@ public void TemplateMethod()
 public void MethodA()
 {
        //code
-
+       //fix in A
 }

Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]?

I’ll answer “y” here, which gives a question on the next change:

@@ -60,7 +60,7 @@ asdfasdfasdf
 public void MethodB()
 {
        //code
-
+       //fix in B
 }

Stage this hunk [y,n,q,a,d,/,K,g,e,?]?

 

And here I’ll answer “n”.

The result

Running “git status” now shows the magic:

# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#       modified:   foo.txt
#
# Changes not staged for commit:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#       modified:   foo.txt
#

Some of the changes from my foo.txt file have been staged for commit, but some haven’t.

How neat is that?

Splitting up chunks

public void asdf()
{
 asdffasdfk = ;
}

When you start using this you’ll find out that git does not always understand what changes should go together. But of course git has options for controlling that! Hitting “?” when choosing what to do with a chunk displays the options for each chunk:

 

The interesting option here is “s” which stands for “split the current hunk into smaller hunks” – which will do just what is says.

This Post Has 3 Comments

  1. Andreas Hammar

    And -p stands for –patch

  2. Craig Taverner

    Definitely awesome. Not that surprising that git can do this. But I really wonder if hg and bzr are able to do this too?

Leave a Reply