github linkedin rss
git add -p
Mar 28, 2014

You have probably - just like me - found yourself in a situation where you wanted to stage just a part of a file. For some reason you found that it is most appropriate for a chunk of the file to go in a commit of its own.

Recently I discovered the git command git add -p. It basically allows you to interactively choose which parts of a file that you want to stage (go into your next commit).

Example

Let us assume that you are working on a file called utils.js. With the following contents

function isString(value) {
    return typeof value === 'strung';
}

function isNumber(value) {
    return typeof value === 'number';
}

After you’ve commited the changes you notice the error, and fix it - but you also start to work on a new function.

function isString(value) {
    // fix the error
    return typeof value === 'string';
}

function isNumber(value) {
    return typeof value === 'number';
}

// start working on new function
function isObject(value) {
    // figure out how to do this
}

Now you might start to think that the fix should go into a commit of its own, so that you’re free to experiment without having to worry about messing something up when working on the new function.

$ git status
# On branch master
# 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: utils.js
#
#

$ git add -p utils.js
diff --git a/utils.js b/utils.js
index 472dc8f..dfad433 100644
--- a/utils.js
+++ b/utils.js
@@ -1,7 +1,11 @@
 function isString(value) {
-   return typeof value === 'strung';
+   return typeof value === 'string';
 }

 function isNumber(value) {
    return typeof value === 'number';
 }
+
+function isObject(value) {
+   // figure out how to do this
+}

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

You can see that there are a lot of options to choose from here. I will not go into details or explain what they mean, I just want to give an introduction to using the tool. Well anyhow, in this case you can see that git wants to stage all the changes by default. We just want the part where we fix the error to go into the commit, so let us type e in order to edit.

Choosing the e option will bring up your default texteditor, and you will see something along the lines of the following

function isString(value) {
-   return typeof value === 'strung';
+   return typeof value === 'string';
 }

 function isNumber(value) {
    return typeof value === 'number';
 }
+
+function isObject(value) {
+   // figure out how to do this
+}

In this case it is enough to just remove the lines starting with + that you don’t want to stage.

function isString(value) {
-   return typeof value === 'strung';
+   return typeof value === 'string';
 }

 function isNumber(value) {
    return typeof value === 'number';
 }

If you now save and exit the texteditor, you should have staged part of the file.

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   utils.js
#
# 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:   utils.js
#

Congratulations, I hope that you’ve learnt something new!


Back to posts