Git Tools - Interactive Staging
# Git Tools - Interactive Staging
The interactive Git commands in this section can help you combine specific parts of files into commits. When you have modified many files and want to split those changes into several commits rather than lumping them all into one, these tools are very useful. This way, you can ensure each commit is a logically independent changeset, making it easier for other developers to review your work. If you run git add with the -i or --interactive option, Git enters an interactive terminal mode that displays something like this:
$ git add -i
staged unstaged path
1: unchanged +0/-1 TODO
2: unchanged +1/-1 index.html
3: unchanged +5/-1 lib/simplegit.rb
*** Commands ***
1: [s]tatus 2: [u]pdate 3: [r]evert 4: [a]dd untracked
5: [p]atch 6: [d]iff 7: [q]uit 8: [h]elp
What now>
2
3
4
5
6
7
8
9
10
You can see this command shows the staging area in a very different view from the usual one -- essentially the same information as git status, but more concise. It lists staged changes on the left and unstaged changes on the right.
After this area is the "Commands" section. Here you can perform various tasks, including staging files, unstaging files, staging parts of files, adding untracked files, and showing diffs of staged content.
# Staging and Unstaging Files
If you type u or 2 (update) at the What now> prompt, it asks which files you want to stage:
What now> u
staged unstaged path
1: unchanged +0/-1 TODO
2: unchanged +1/-1 index.html
3: unchanged +5/-1 lib/simplegit.rb
Update>>
2
3
4
5
6
To stage the TODO and index.html files, you can type their numbers:
Update>> 1,2
staged unstaged path
* 1: unchanged +0/-1 TODO
* 2: unchanged +1/-1 index.html
3: unchanged +5/-1 lib/simplegit.rb
Update>>
2
3
4
5
6
The * next to each file means the file is selected for staging. If you press Enter without typing anything at the Update>> prompt, Git will stage the previously selected files:
Update>>
updated 2 paths
*** Commands ***
1: [s]tatus 2: [u]pdate 3: [r]evert 4: [a]dd untracked
5: [p]atch 6: [d]iff 7: [q]uit 8: [h]elp
What now> s
staged unstaged path
1: +0/-1 nothing TODO
2: +1/-1 nothing index.html
3: unchanged +5/-1 lib/simplegit.rb
2
3
4
5
6
7
8
9
10
11
Now you can see that TODO and index.html have been staged while simplegit.rb has not. If you want to unstage the TODO file, use the r or 3 (revert) option:
*** Commands ***
1: [s]tatus 2: [u]pdate 3: [r]evert 4: [a]dd untracked
5: [p]atch 6: [d]iff 7: [q]uit 8: [h]elp
What now> r
staged unstaged path
1: +0/-1 nothing TODO
2: +1/-1 nothing index.html
3: unchanged +5/-1 lib/simplegit.rb
Revert>> 1
staged unstaged path
* 1: +0/-1 nothing TODO
2: +1/-1 nothing index.html
3: unchanged +5/-1 lib/simplegit.rb
Revert>> [enter]
reverted one path
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Checking the Git status again, you can see the TODO file has been unstaged:
*** Commands ***
1: [s]tatus 2: [u]pdate 3: [r]evert 4: [a]dd untracked
5: [p]atch 6: [d]iff 7: [q]uit 8: [h]elp
What now> s
staged unstaged path
1: unchanged +0/-1 TODO
2: +1/-1 nothing index.html
3: unchanged +5/-1 lib/simplegit.rb
2
3
4
5
6
7
8
To view the diff of staged content, use the d or 6 (diff) command. It shows a list of staged files from which you can select to view the staged diff. This is very similar to running git diff --cached on the command line:
*** Commands ***
1: [s]tatus 2: [u]pdate 3: [r]evert 4: [a]dd untracked
5: [p]atch 6: [d]iff 7: [q]uit 8: [h]elp
What now> d
staged unstaged path
1: +1/-1 nothing index.html
Review diff>> 1
diff --git a/index.html b/index.html
index 4d07108..4335f49 100644
--- a/index.html
+++ b/index.html
@@ -16,7 +16,7 @@ Date Finder
<p id="out">...</p>
-<div id="footer">contact : support@github.com</div>
+<div id="footer">contact : email.support@github.com</div>
<script type="text/javascript">
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
With these basic commands, you can use the interactive add mode to conveniently manage the staging area.
# Staging Patches
Git can also stage specific parts of files. For example, if you make two changes in the simplegit.rb file and want to stage only one of them, Git makes this easy. In the same interactive prompt shown in the previous section, type p or 5 (patch). Git will ask which files you want to partially stage; then for each selected file, it displays the file diff section by section and asks if you want to stage each one:
diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index dd5ecc4..57399e0 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -22,7 +22,7 @@ class SimpleGit
end
def log(treeish = 'master')
- command("git log -n 25 #{treeish}")
+ command("git log -n 30 #{treeish}")
end
def blame(path)
Stage this hunk [y,n,a,d,/,j,J,g,e,?]?
2
3
4
5
6
7
8
9
10
11
12
13
14
At this point you have many options. Type ? to display a list of all available commands:
Stage this hunk [y,n,a,d,/,j,J,g,e,?]? ?
y - stage this hunk
n - do not stage this hunk
a - stage this and all the remaining hunks in the file
d - do not stage this hunk nor any of the remaining 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
2
3
4
5
6
7
8
9
10
11
12
13
14
Typically you would type y or n to choose whether to stage each hunk. Of course, staging all parts of a specific file or skipping a hunk for later is also very useful. If you stage only part of a file, the status output may look like this:
What now> 1
staged unstaged path
1: unchanged +0/-1 TODO
2: +1/-1 nothing index.html
3: +1/-1 +4/-0 lib/simplegit.rb
2
3
4
5
The status of simplegit.rb is interesting. It shows that some lines are staged and some are unstaged. You have partially staged this file. At this point, you can exit the interactive add script and run git commit to commit the partially staged file.
You don't have to be in interactive add mode to do partial file staging -- you can start the same script from the command line with git add -p or git add --patch.
Furthermore, you can use git reset --patch to partially reset files, git checkout --patch to partially check out files, and git stash save --patch to partially stash files. We will cover more details when we discuss the advanced usage of these commands.