Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stage hunk non-interactively in git

Tags:

git

The git add -p command allows interactive staging of hunks or parts of a file ( https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging).

Is there a way to stage a hunk non-interactively? Say, I have these hunks:

$ git diff
diff --git a/test.txt b/test.txt
index 77e67ac..34eabb1 100644
--- a/test.txt
+++ b/test.txt
@@ -1,4 +1,4 @@
-this is the first change
+this is the first change, don't stage it!



@@ -6,5 +6,5 @@ this is the first change



-this is the first change
+this is the second change, stage it!

It would be nice to run a single command like git add -p 2 to stage the second hunk without going through the interactive menu.

NOTE: One solution is mentioned here (How to stage chunks non-interactively in git?), but it involves multiple commands and an additional step of editing a patch file.

When would this be useful? Say I was editing a long and repetitive JSON file, and after running git diff, I know I want to stage every other hunk. I don't want to go through each hunk individually; I just want to tell git "stage the 2nd, 4th, 6th, 8th, etc. hunks".

This can also be useful when trying to interact with Sourcetree (which enables working with hunks), using self-defined scripts.

like image 631
Ben Cook Avatar asked Aug 13 '15 15:08

Ben Cook


2 Answers

In case you are able to manually or automatically (say, thanks to sed) edit your patch (the one produced thanks to git diff), you can stage hunks non-interactively thanks to the following command:

git apply --cached patchfile

PS: I could actually find the answer to your question here: https://stackoverflow.com/a/31498768/7009806

like image 180
Olivier Avatar answered Oct 21 '22 11:10

Olivier


This answer is more for the exercise's sake and for the fun side of finding a solution for it. I am not too sure if that can really be applied in a real world case. It also shows a solution about how to use git add -p given a list of desired choices.

git add --patch reads from stdin, so you could prepare your interactive actions, say, in a file (called for the example's sake /tmp/foo), with each line the hunk action you would want and then do:

git add -p < /tmp/foo

Here is a full example:

I made a file with a number per line from 0 to 100, committed it and remplaced the 0's by a. The beginning of the diff looks like it:

diff --git a/my-file b/my-file
index 3b53b00..8f9a65c 100644
--- a/my-file
+++ b/my-file
@@ -1,4 +1,4 @@
-0
+a
 1
 2
 3
@@ -8,7 +8,7 @@
 7
 8
 9
-10
+1a
 11
 12
 13
@@ -18,7 +18,7 @@
 17
 18
 19
-20
+2a
 21
 22
 23
@@ -28,7 +28,7 @@
 27
 28
 29
-30
+3a
 31
 32
 33
@@ -38,7 +38,7 @@
 37
 38
 39
-40
+4a
 41
 42
 43

Now, I want to stage only one change out of two, then I create my foo file:

echo `y
n
y
n
y
n
y
n
y
n
y' > /tmp/foo

The creation of this file can be automated or not.

Then I run it:

git add -p < /tmp/foo

and I get staged:

> git diff --cached
diff --git a/my-file b/my-file
index 3b53b00..00010f9 100644
--- a/my-file
+++ b/my-file
@@ -1,4 +1,4 @@
-0
+a
 1
 2
 3
@@ -18,7 +18,7 @@
 17
 18
 19
-20
+2a
 21
 22
 23
@@ -38,7 +38,7 @@
 37
 38
 39
-40
+4a
 41
 42
 43
[.....]

and unstaged:

> git diff
diff --git a/my-file b/my-file
index 3b53b00..00010f9 100644
--- a/my-file
+++ b/my-file
@@ -1,4 +1,4 @@
-0
+a
 1
 2
 3
@@ -18,7 +18,7 @@
 17
 18
 19
-20
+2a
 21
 22
 23
@@ -38,7 +38,7 @@
 37
 38
 39
-40
+4a
 41
 42
 43
[...]

Another way to do the same without a file would be:

echo 'y
n
y
n
y
n
y
n
y
n
y' | git add --patch
like image 38
padawin Avatar answered Oct 21 '22 09:10

padawin