Interactive add

The exposed staging area Git offers sometimes lead to confusion, especially when adding a file, changing it a bit, and then adding the file again to be able to commit the changes made after the first add. While this can seem a bit cumbersome to add the file after every little change, it is also a big advantage that you can stage and unstage changes. With the git add command, it is even possible to only add some changes to a file in the staging area. This comes in handy especially if you make a lot of changes to a file and for example, want to split the changes into bug fixes, refactoring, and features. This example will show how you can easily do this.

Getting ready

Again, we'll use the cookbook-tips-tricks repository. Clone it and check out the interactive branch:

$ git clone https://github.com/dvaske/cookbook-tips-tricks.git
$ cd cookbook-tips-tricks
$ git checkout interactive

How to do it...

First, we need some changes to be added; we do this by a resetting the latest commit:

$ git reset 'HEAD^'
Unstaged changes after reset:
M    liberty.txt

Now, we have a modified file. To start the interactive add, we can either run the git add -i or git add -p filename. The -i option brings up an interface where all the different files in the modified state can be added interactively one at a time. The add -p/--patch option is simpler and just gives you the option to add parts of the file specified:

$ git add -p liberty.txt
diff --git a/liberty.txt b/liberty.txt
index 8350a2c..9638930 100644
--- a/liberty.txt
+++ b/liberty.txt
@@ -8,6 +8,13 @@
          WW) ,WWW)
          7W),WWWW'
          'WWWWWW'
+          9---W)
+      ,,--WPL=YXW===
+     (P),CY:,I/X'F9P
+     WUT===---/===9)
+     -HP+----Y(C=9W)
+      '9Y3'-'-OWPT-
+       'WWLUIECW
         (:7L7C7'
        ,P--=YWFL
        Y-=:9)UW:L
Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]?

Git asks you whether you want to stage the previous change (the hunk), but also shows quite a lot of options, which can expand a little bit if you type ?:

Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? 
y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk nor any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk nor any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help

There are a lot of options, but with the help text, they are quite self-explanatory. Let's add the current hunk, y, and look at the next one:

Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? y
@@ -17,16 +24,17 @@
        7WYW))PW W
         7WH)),WC)
          7L--/XY)
+DEBUG: Don't include this line...
          9+-,KY7)
          W9-Y3+7)
          W'=9WI7)
         ,W  '-YY)
-         W    ::W
-        ,T     :X)
-        ()     '9W  'L.                    ,-
-        (C     =:9   '9L                  ,T
-        ()    ,,-7)    7WL              ,F'
-        ()    , T9)     '9WL          ,YF
+         W    ::W                ,
+        ,T     :X)              ()
+        ()     '9W  'L.         ()         ,-
+        (C     =:9   '9L        ()        ,T
+        ()    ,,-7)    7WL      WW      ,F'
+        ()    , T9)     '9WL    --    ,YF
         ()    '-/(W       -==+PE9P7===O)          -,
         'W, ,  T+/WX=L-. ,WP+()+3L3,),=WL  --==-T-
          7)    -,YW '-=9WPL+PT-- ':--L/=9WP=-'
Stage this hunk [y,n,q,a,d,/,K,j,J,g,s,e,?]?

Whoa! It looks like there is a debug line there that we should not add. Let's split the hunk, s:

Stage this hunk [y,n,q,a,d,/,K,j,J,g,s,e,?]? s
Split into 2 hunks.
@@ -17,7 +24,8 @@
        7WYW))PW W
         7WH)),WC)
          7L--/XY)
+DEBUG: Don't include this line...
          9+-,KY7)
          W9-Y3+7)
          W'=9WI7)
         ,W  '-YY)
Stage this hunk [y,n,q,a,d,/,K,j,J,g,e,?]?

We don't want the output to be staged, use n, but we'll stage the next hunk and all the hunks later in the a file:

Stage this hunk [y,n,q,a,d,/,K,j,J,g,e,?]? n
 @@ -20,13 +28,13 @@
          9+-,KY7)
          W9-Y3+7)
          W'=9WI7)
         ,W  '-YY)
-         W    ::W
-        ,T     :X)
-        ()     '9W  'L.                    ,-
-        (C     =:9   '9L                  ,T
-        ()    ,,-7)    7WL              ,F'
-        ()    , T9)     '9WL          ,YF
+         W    ::W                ,
+        ,T     :X)              ()
+        ()     '9W  'L.         ()         ,-
+        (C     =:9   '9L        ()        ,T
+        ()    ,,-7)    7WL      WW      ,F'
+        ()    , T9)     '9WL    --    ,YF
         ()    '-/(W       -==+PE9P7===O)          -,
         'W, ,  T+/WX=L-. ,WP+()+3L3,),=WL  --==-T-
          7)    -,YW '-=9WPL+PT-- ':--L/=9WP=-'
Stage this hunk [y,n,q,a,d,/,K,j,J,g,e,?]? a

Let's see the current status and difference between the working directory and staging area:

$ git status
On branch interactive
Your branch is behind 'origin/interactive' by 1 commit, and can be fast-forwarded.
  (use "git pull" to update your local branch)

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   liberty.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:   liberty.txt
$ git diff
diff --git a/liberty.txt b/liberty.txt
index 035083e..9638930 100644
--- a/liberty.txt
+++ b/liberty.txt
@@ -24,6 +24,7 @@
        7WYW))PW W
         7WH)),WC)
          7L--/XY)
+DEBUG: Don't include this line...
          9+-,KY7)
          W9-Y3+7)
          W'=9WI7)

Perfect! We got all the changes staged except the debug line, so the result can be committed:

$ git commit -m 'Statue of liberty completed'
[interactive 1ccb885] Statue of liberty completed
 1 file changed, 36 insertions(+), 29 deletions(-)

There's more…

As mentioned earlier, it is also possible to use git add -i to interactively add files. If we do this after resetting our branch, we would get the following menu:

$ git add -i
           staged     unstaged path
  1:    unchanged      +37/-29 liberty.txt

*** Commands ***
  1: status    2: update    3: revert    4: add untracked
  5: patch     6: diff      7: quit      8: help
What now>

The eight options pretty much do what they say. We can choose the patch option to get into the patch menu as we saw previously, but first we have to choose which file to add patches for:

What now> p
           staged     unstaged path
  1:    unchanged      +37/-29 liberty.txt
Patch update>> 1
           staged     unstaged path
* 1:    unchanged      +37/-29 liberty.txt
Patch update>>
diff --git a/liberty.txt b/liberty.txt
index 8350a2c..9638930 100644
--- a/liberty.txt
+++ b/liberty.txt
...

Once we have chosen the files, we want to add patches so they get a * character in the menu. To begin the patching, just click on <return>. When you're done, you'll return to the menu and can quit, review, revert, and so on.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset