Add Specific Lines With Git Patch

You know that git add adds files to index. But did do you know that it can add specific lines of files? Or even add files, ignoring their contents? Let’s check this out!

First let’s get familiar with git add --patch command or it’s shorthand git add -p. What does it do?

Let’s imagine that you’ve been working on some task. During the process you’ve got carried away and introduced some changes not related to your current task.

Now it’s time to commit the changes, but some of them are irrelevant. It would be wrong to put everything in that commit.

This is where git add --patch comes into play.

See The Example

Imagine we had a file poem.txt with two unfinished couplets:

Roses are red
Violets are blue

Roses are red
Violets are blue

After a full day of dedicated hard work we’ve completed both:

➜  git_add_patch (master) ✗ git diff

diff --git a/poem.txt b/poem.txt
index 39f13e6..f4b70ab 100644
--- a/poem.txt
+++ b/poem.txt
@@ -1,5 +1,9 @@
 Roses are red
 Violets are blue
+Sugar is sweet
+And so are you

 Roses are red
 Violets are blue
+Onions stink
+And so do you.

But now we are a bit concerned about the second couplet and want to commit only the first part.

➜  git_add_patch (master) ✗ git add -p

diff --git a/poem.txt b/poem.txt
index 39f13e6..f4b70ab 100644
--- a/poem.txt
+++ b/poem.txt
@@ -1,5 +1,9 @@
 Roses are red
 Violets are blue
+Sugar is sweet
+And so are you

 Roses are red
 Violets are blue
+Onions stink.
+And so do you.
Stage this hunk [y,n,q,a,d,/,s,e,?]?

See the last line, Stage this hunk [y,n,q,a,d,/,s,e,?]? Here it gives you some options where the most important are:

  • y - stage this hunk
  • 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

There are some more options, you can see them by choosing the ? option.

Here we want only the first part about the sugar and sweetness, so we choose the option s.

Stage this hunk [y,n,q,a,d,/,s,e,?]? s
Split into 2 hunks.
@@ -1,5 +1,7 @@
 Roses are red
 Violets are blue
+Sugar is sweet
+And so are you

 Roses are red
 Violets are blue
Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? y

We chose to stage that hunk, and now it asks if we want to stage the second one:

Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? y
@@ -3,3 +5,5 @@

 Roses are red
 Violets are blue
+Onions stink
+And so do you.
Stage this hunk [y,n,q,a,d,/,K,g,e,?]? n

And we don’t want to stage this one, so we choose n.

Great, let’s see what we have now.

➜  git_add_patch (master) ✗ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   poem.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   poem.txt

Cool beans, time to commit this thing.

➜  git_add_patch (master) ✗ git commit -m "Complete the first couplet"

Git splits hunks by the empty lines, but what if you really need to stage only specific lines.

Behold The Power Of E

Imagine you have a diff like this:

➜  git_add_patch (master) ✗ git diff

diff --git a/poem.txt b/poem.txt
index 9737e9f..a2baecd 100644
--- a/poem.txt
+++ b/poem.txt
@@ -5,3 +5,6 @@ And so are you

 Roses are red
 Violets are blue
+Flowers smell good
+Onions stink
+And so do you.

And you are really concerned about that onion part, but you don’t want to remove it. So you want to stage only the “Flowers smell good” and “And so do you” lines.

Now the s option won’t help us, because those lines aren’t separated by empty lines, and git considers them as one hunk.

e option to the rescue.

➜  git_add_patch (master) ✗ git add -p
diff --git a/poem.txt b/poem.txt
index 9737e9f..a2baecd 100644
--- a/poem.txt
+++ b/poem.txt
@@ -5,3 +5,6 @@ And so are you

 Roses are red
 Violets are blue
+Flowers smell good.
+Onions stink.
+And so do you.
Stage this hunk [y,n,q,a,d,/,e,?]? e

It will open the default text editor and you’ll be able to manually edit that hunk.

editor

Just remove the part about onions and here you go:

➜  git_add_patch (master) ✗ git add --staged

diff --git a/poem.txt b/poem.txt
index 9737e9f..a2baecd 100644
--- a/poem.txt
+++ b/poem.txt
@@ -5,3 +5,6 @@ And so are you

 Roses are red
 Violets are blue
+Flowers smell good
+And so do you.

Nice, now you can decide what to do about those stinky onions later.

But what if you need to add some specific lines from the new file?

Use The Intent To Add

Use git add --intent-to-add or git add -N to add specific file, but not its contents.

Imagine that we had our poem written from scratch.

Now git diff shows nothing, and if we’ll use git add -p it will say No changes.

No problem, let’s tell git that the file exists.

➜  git_add_patch (master) ✗ git add -N poem.txt

Now we can use git add -p and then edit the hunk to remove the lines about onions.