Select Hunks to Stage in Git
How to pick which parts of what files you want to stage in git.
Stage everything
Often, we want to stage and then commit all our changes in git. To change everything in the working directory,
git add .
Stage selectively
To stage selectively, git allows us an interactive interface for staging. Add the -i
flag:
git add -i .
Our changes are tracked in hunks, or parts of the files that we change. One file can have many hunks, depending on the spread and space between the changes. Git makes some calculation on the hunk splits, but I'm not sure how it does it.
Let's try it out with a test project. My git --no-pager diff
shows:
diff --git a/test.js b/test.js
index f7cc1c0..76e7ad9 100644
--- a/test.js
+++ b/test.js
@@ -1,9 +1,9 @@
function addMe() {
- doThis();
+ // doThis();
}
function doThis() {
- console.log("asdf");
+ console.log("changed");
}
function main() {
@@ -11,3 +11,7 @@ function main() {
}
main();
+
+function newThing() {
+ return 1 + 1;
+}
Let's say that I want to skip the addMe
change, stage the doThis
change and stage the newThing
change.
Once I type git add -i .
and enter the interactive stage, I see a menu of options:
staged unstaged path
1: unchanged +6/-2 test.js
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
What now> 5
staged unstaged path
1: unchanged +6/-2 test.js
Patch update>> 1
staged unstaged path
* 1: unchanged +6/-2 test.js
Patch update>>
What I want to do is patch
for the stage. I select p
and then 1
for the test.js
file, then enter
. Now I'm brought to a prompt with the first hunk:
diff --git a/test.js b/test.js
index f7cc1c0..76e7ad9 100644
--- a/test.js
+++ b/test.js
@@ -1,9 +1,9 @@
1 ⋮ 1 │ function addMe() {
2 ⋮ │- doThis();
⋮ 2 │+ // doThis();
3 ⋮ 3 │ }
4 ⋮ 4 │
5 ⋮ 5 │ function doThis() {
6 ⋮ │- console.log("asdf");
⋮ 6 │+ console.log("changed");
7 ⋮ 7 │ }
8 ⋮ 8 │
9 ⋮ 9 │ function main() {
(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,s,e,?]?
Two of my changes have been put into one hunk. I can split them with s
. Then I'm re-asked the same question, now on each hunk. The first looks like:
Split into 2 hunks.
@@ -1,5 +1,5 @@
1 ⋮ 1 │ function addMe() {
2 ⋮ │- doThis();
⋮ 2 │+ // doThis();
3 ⋮ 3 │ }
4 ⋮ 4 │
5 ⋮ 5 │ function doThis() {
(1/3) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?
In this case, we decide that no, I don't want to stage this change, so I press n
. The next hunk is presented:
@@ -3,7 +3,7 @@
3 ⋮ 3 │ }
4 ⋮ 4 │
5 ⋮ 5 │ function doThis() {
6 ⋮ │- console.log("asdf");
⋮ 6 │+ console.log("changed");
7 ⋮ 7 │ }
8 ⋮ 8 │
9 ⋮ 9 │ function main() {
(2/3) Stage this hunk [y,n,q,a,d,K,j,J,g,/,e,?]?
I want that staged, so I press y
. So comes the last hunk:
@@ -11,3 +11,7 @@ function main() {
11 ⋮ 11 │ }
12 ⋮ 12 │
13 ⋮ 13 │ main();
⋮ 14 │+
⋮ 15 │+function newThing() {
⋮ 16 │+ return 1 + 1;
⋮ 17 │+}
(3/3) Stage this hunk [y,n,q,a,d,K,g,/,e,?]?
y
, stage that one too. As that is the last hunk, I'm brought back to the first command menu, where I q
for quit.
Key bindings
Here are a few explainers on keys used in the interactive staging:
j/k
next and previous hunks, a la vimg
shows a goto index for hunks to jump to, by line number and first line/
allows you to search by regex for code in the hunke
edit the hunk manually. A step up from split. You get full control of the hunk boundaries here.
Finally, if you use the interactive staging for patching, you can jump directly to that and bypass the command menu with:
git add --patch -i .
Now commit
Don't be a Horace Wimp. Commit! Staging is just playing around. Let's make it real. Reflog or it didn't happen.
Check what you've staged with git diff --staged
.
See what you're leaving uncommitted with git diff
.
Finally, commit with: git commit -m "gone done it"