I sometimes find myself in a situation where I want to include some, but not all changes in a file in a Git commit.
For example, a colleague uses Visual Studio 2015, whereas I use 2013, so when I open a solution to help out on their project, the .sln file is updated to show my version of Visual Studio. I don't want to check this in, but I do want to include changes in the file such as information about new projects in the solution. Another situation where I might want to select individual changes in a file is where they correspond to two separate pieces of work, which I want to check in separately. For example, it would be nice to keep a change of using statement in a class A which happened because of renaming another file or project B separate from a refactor in class A.
Git does offer a way to do this, which I was first introduced to in a GUI-ified form in Git client SmartGit (thanks Richard).
Staging a subset of changes in a file using SmartGit
To stage some changes but not others using SmartGit, look in the Changes pane, and right click on the changed lines you want to include in your commit.
Select Stage Hunk, to stage the highlighted lines.
The file's status will be shown as 'Staged Modified' in the Files pane.
When you commit a set of changes, only the selection you made will be included, and the file will revert to a Modified status.
Staging a subset of changes in a file using Git commands
The Git command that the SmartGit GUI's stage hunk option maps to is --patch, for which there is a short version -p.
To stage a section of a file using Git through the command line, you'd enter:
Git add -p [file name]
This presents you with the first suggested 'hunk' from the file, asks 'Stage this hunk?', and presents a set of options.
The options in the screenshot above are a bit hard to read, so here they are again:
Not all possible options are displayed for this hunk – for the full set look down!
If the selection is too large, you can split it into smaller selections using the option:
(Not visible in the options in the screenshot as the suggested hunk is just one line).
You can continue to use the s command until you are at the level of granularity you need, although according to this Stack Overflow answer from user Mechanical Snail, "this only works if there is at least one unchanged line in the "middle" of the hunk, which is where the hunk will be split"
To stage the hunk, use the option:
To leave the hunk unstaged, use the option:
You will then be presented with the next suggested hunk in the file, if it contains any more changes, and the same set of options.
Here are the meanings of the other options:
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
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
E - manually edit the current hunk
? - print help
I couldn't find anything in the Git docs for the command though the ? Command was helpful. If anyone has a link to the docs, please let me know!