Note: This is a reference, mainly for myself and others, condensed from a much more verbose article which does a lot of hand-holding for Git newcomers, and attempts to explain what is going on in a little more detail.
Also, if you are newer to Git you might want to review my introductory posts on Getting Started with Git and a Handy Git Command Line Reference. While these tutorials were originally targeted at Windows developers, the information is pretty universal. Also, you might benefit from the more through treatment of this topic in the full-fledged walk-thru.
Image by msun523 Some Rights Reserved
I'm new and/or I enjoy reading. Take me to a full-fledged walk-through!
The git add –p
command allows us to interactively stage chunks of code within a file or files for commit, while leaving the rest of the file of files un-staged. The command syntax is:
The git add –p Command Syntax:
$ git add -p [optionalFileName]
In the above, the file name is optional, but without a specific file name, git will interactively move through all files with un-staged changes. Best to include only the file or files of interest.
Once the git add –p
command is executed, git enters interactive mode, and interactively moves through chunks of code in the file or files, prompting you to indicate what to do as far as staging each chunk. Following is a table of the options available with this command:
Interactive Patch Staging Options:
Option | Action |
y | Stage the current code chuck for the next commit |
n | Do not stage the current code chunk for the next commit |
a | Stage the current chunk, and all remaining chunks in the current file |
d | Do not stage current chuck, or any remaining chunks in the current file |
g | Select the next code chuck to review |
/ | Search for a code chuck matching the given regex |
j | Leave undecided, see next undecided chunk |
k | Leave undecided, see next code chunk |
K | Leave undecided, see previous undecided code chunk |
s | Split the current code chunk into smaller chunks |
e | Manually edit the current code chunk |
? | Print help |
On occasion, we perform a number of changes in the same code file, and then, after laboring to get it right for hours, we realize we have introduced unrelated changes, to different parts of the file, which should really be in separate commits.
Consider the following contrived, but illustrative situation (the examples here are in C#, but this exercise could apply to any platform). We open our latest project on branch master
and review a file, ComplicatedExistingClass
, which looks like this to start with:
Original Code File for ComplicatedExistingClass:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GitAddPartialFile
{
public class ComplicatedExistingClass
{
public int ComplexCalculation(int numberOne, int numberTwo)
{
int sum = 0;
sum = numberOne + numberTwo + 1;
return sum;
}
}
}
We then add our new method, which requires the addition of a couple new using
statements at the top of the code file (yes, I know System.Data
and System.Data.OleDb
are not actually used here, just mixing it up a bit – work with me), and of course, our new method:
Our Code File with New Method:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.OleDb;
namespace GitAddPartialFile
{
public class ComplicatedExistingClass
{
public int ComplexCalculation(int numberOne, int numberTwo)
{
int sum = 0;
sum = numberOne + numberTwo + 1;
return sum;
}
public IEnumerable<int> DoSomethingWithNumbers(int[] numbers)
{
var output = new List<int>();
foreach (int i in numbers)
{
int result = this.ComplexCalculation(i, numbers.Count());
output.Add(result);
}
return output;
}
}
}
While testing out our complicated new method, which also calls the original ComplexCalculation
method, we notice there is a bug in the original method. The bug fix is quite complex and takes hours, requiring us to modify several lines of code after we discern just what it is that is wrong:
Modified Code File, including Arduous Bug Fix:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.OleDb;
namespace GitAddPartialFile
{
public class ComplicatedExistingClass
{
public int ComplexCalculation(int numberOne, int numberTwo)
{
int sum = 0;
sum = numberOne + numberTwo;
return sum;
}
public IEnumerable<int> DoSomethingWithNumbers(int[] numbers)
{
var output = new List<int>();
foreach (int i in numbers)
{
int result = this.ComplexCalculation(i, numbers.Count());
output.Add(result);
}
return output;
}
}
}
Only now do we come up for air long enough to realize we should have done the bug fix separately from adding our new method. For one, we might not be done with our feature yet, but the bug fix is critical and should be able to be merged back into master
immediately. Also, it simply makes sense that a bug fix in the existing code base should be a singular commit, separate from adding new code. What to do?
What we would like to do is create a commit for the bug fix first, separate from our newly added feature code. Here is how.
We can now use the git add –p
to do this interactively, and stage our code in patches. With git add –p
, we will selectively add chunks of a file (or files) from our working tree to the staging area, enabling us to select discreet chunks of changed code and build separate commits with pieces of a file or files.
Once we type this command and hit enter, git jumps into an interactive mode, allowing us to decide which file chucks we wish to add to the next commit. In the case of our example project, we would type the command like this:
Staging Patches from our Existing File for Commit:
$ git add -p ComplicatedExistingClass.cs
Our terminal window looks like this before we hit enter:
Once we hit the enter key, we see this rather busy window:
See the stuff called out in the red box? this represents the first chunk of changed code git has identified in the file. The changes are shown in green, and surrounding (unmodified) code is shown in white for context. Also notice the text in blue at the bottom of the window, with a prompt waiting for us to tell git what to do. The prompt is waiting for us to enter one of the options from our table above.
In our example case here, the code chunk above is related to our new method (work with me here, it's contrived, remember?), so we we don't want to add this chunk to the next commit. Hit n, then Enter:
Do Not Stage Current Code Chunk and Move to the Next Code Chunk:
Whoa. OK, now we see the bug fix code we were looking for, but we also see our newly added method. We want to isolate the bug fix code. In this case, we need to select the s option from the menu, splitting the above chunk into smaller pieces. This results in a code chunk including our bug fix, and only our bug fix:
Split Current Code Chunk and Isolate Bug Fix:
Now we have what we want to include in our next commit. Obviously, we choose the y option so that this chunk is staged for commit. Git then moves to the next code chunk:
Choose Bug Fix for Next Commit:
What we now see in the terminal window is the rest of the code for our new feature. We don't want this in our bug fix commit. Also, because our entire bug fix has just been staged for commit by selecting the y option, we can tell git not to stage the current code chunk, or any remaining code chunks. We do this by selecting the d option:
Exit and Return to Terminal Command Prompt
Now we are ready to commit our bug fix. After we do that, we can then stage our newly added feature code in the normal fashion and commit.
In this article I walked through this as briefly as I could while including sufficient examples and illustrative screenshots to show what is going on. There is more detail in the full tutorial Git: Interactively Stage Portions of a Single Changed File for Commit Using git add –p.
If you found this useful, consider some of my other posts related to Git, and as always, the most excellent book (free online) by Scott Chacon:
John on Google