Using Git Index
An healthy git repository, is readable and tracable. We need fully clear what we commit. The Git Index, is what we need, just like a shopping cart. We pick goods(updates) from the shelves(work tree). Then push the cart(index) to cash register, and buy(commit) them. With the Git Index, we have ability to deal with a big heap of updates orderly.
Basic Commands
There are three git commands for managing Git Index.
They are add
, reset
and checkout
.
-
add
add updates from work tree to index -
reset
remove updates from index -
checkout
give up updates that not be added to index (cover updates in work tree by index) Bothreset
andcheckout
are multi-purpose. The commandreset
also can use to move current branch. And the commandcheckout
also can use to move HEAD and checkout to the work tree. The difference is the parameter for the command. If the parameter is a commit(hash or branch, tag…), it’s for the branch and HEAD. If the parameter is a path, or there is no parameter, it’s for the index.
Meticulous operations: --patch
Each of add
, reset
, checkout
can run with option --patch
, or -p
in short.
Git will iterate over the updates and let’s handle them one by one.
You can run with paths as parameters to iterate over one file or several files,
or just run with no parameter to iterate over all updates.
Using there command with -p
option is the best way currently to manage the Git Index.
I name it 3Ps Sorcery.
After run the command, we get a interactive interface like this:
diff --git a/index.md b/index.md
index 921ba51..1c0d98b 100644
--- a/index.md
+++ b/index.md
@@ -3,5 +3,5 @@
layout: home
-list_title: foo
+list_title: bar
---
Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,s,e,?]?
The last Line is different with different command:
add
Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,s,e,?]?
reset
Unstage this hunk [y,n,q,a,d,k,K,j,J,g,/,s,e,?]?
checkout
Discard this hunk from worktree [y,n,q,a,d,k,K,j,J,g,/,s,e,?]?
As we see, git show an update in the file index.md
.
And give us several operations y,n,q,a,d,k,K,j,J,g,/,s,e,?
. What are they use for?
By the first sight, I only know the ?
provides helps.
So we input ? Enter.
We get the message:
add
y - stage this hunk
n - do not stage this hunk
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
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
reset
y - unstage this hunk
n - do not unstage this hunk
q - quit; do not unstage this hunk or any of the remaining ones
a - unstage this hunk and all later hunks in the file
d - do not unstage 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
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
checkout
y - discard this hunk from worktree
n - do not discard this hunk from worktree
q - quit; do not discard this hunk or any of the remaining ones
a - discard this hunk and all later hunks in the file
d - do not discard 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
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
What’s a hugging heap of dazing stuffs! Don’t worry, just let’s reorder them:
handlers:
`y` yes do (add/reset/give up);
`n` no don't (add/reset/give up);
`a` all do for all in this file;
`d` don't don't for all in this file;
`e` edit see next section;
`s` split some times, git will assume several updates as one, you can split it;
navigations (only works in a file):
`g` goto goto the nth update, such as `g 1`,`g 2`, the number start with 1;
`/` search just like searching in vim, less... It's convenient for a big file with lots of updates;
`j` next next unprocessed;
`J` Next next update;
`k` previous previous unprocessed;
`K` Previous previous update;
others:
`q` quit quit;
`?` help print help;
We only need know y
, n
, s
, q
for basic using.
For advanced using, we need know one more: e
.
For programmers, that’s enough.
For dictionary keeper, or Webpack configuratician, navigations will be useful.
In this section, we talk about the e
.
To begin the editing, we need an editor.
Just like when you run commit
without -m
opiton,
git will open vim or nano when you using e
.
And the text in the editor will like this:
# Manual hunk edit mode -- see bottom for a quick guide
@@ -20,4 +20,5 @@
><ul
><li>foo</li
- ><li>bar</li
+ ><li>baz</li
+ ><li>qux</li
></ul
# ---
# Here will be some manual text.
Here is an update, we delete the line bar, and insert lines baz and qux.
The line @@ ... @@
shows the line number and line counts before and after edit.
And follows the content of update.
The first character of each line is the line type, can be space, -
or +
.
The space means this line is a normal line,
a -
for a deleted line, and an +
for a new inserted line.
Attention, this space is not indentation.
If you use indent characters for indentation, here is a space at the first.
If you use spaces instead of indentation, one more space each line.
If you just quit the editor without edit anything,
it’s just equal to press a y
instead of e
.
If you recover the update, remove all +
lines, change -
s to spaces,
it’s just equal to press a n
instead of e
.
We can modify it as you like, but not all modifications are allowed.
It’s easier to understand when we run add
. Here is an example,
if we make modifications like this:
><ul
- ><li>foo</li
+ ><li>qux</li
><li>bar</li
+ ><li>Baz</li
></ul
As we see, we don’t delete line bar, but delete line foo. And we edit line baz, and insert qux to another position. That’s not difficult. We’ll found that space lines and
-
lines can change to each others, but you can not modify their content;+
lines can make any modifications, remove or insert anywhere whenadd
.
But when reset
, it’s different. Oppositely, space lines and +
lines can change to each others,
but you can not modify their content; -
lines can make any modifications, remove or insert anywhere when add
.
It’s confusing. So, example again. the same situation, let’s edit the text to this:
><ul
+ ><li>foo</li
- ><li>Bar</li
+ ><li>baz</li
><li>qux</li
- ><li>ET</li
></ul
To understand what will happen, we must using words like give up or cancel.
We change line foo from space line to +
line, means we cancel the adding of line foo,
but the line foo is not added, it’s over there original,
so it’s means delete the line foo in fact.
We change line bar to line Bar, means don’t cancel the deleting of bar,
but cancel deleting of line Bar. And means delete line bar and add line Bar in fact.
At last, insert a line ET.
If you still hard to get it, just assume +
lines as -
lines and -
lines as +
lines.
On checkout
, since the direction is same with reset
, so reverse +
and -
too.
What in the paper is abstract. For fully understand, you need try it by your self.
There is a feature lack that, the add -p
doesn’t with new files. However, reset -p
dose.
For the new files, you can use add filename
then reset -p filename
to add it with patching.
File level and global operations
Usually, always check over what you change with -p
is fine.
But some times you need file level or global operations.
-
git add file
add all updates in the file from work tree to index -
git reset file
remove all updates in the file from index -
git checkout file
give up all updates in the file that not be added to index (cover the file in work tree by index) -
git add .
add all updates from work tree to index -
git reset
remove all updates from index -
git checkout
give up all updates that not be added to index (cover all updates in work tree by index)
Imperfect ultimate weapon add --interactive
There is another more fashion option --interactive
on command git add
, -i
in short.
By the name, this is a interactive interface too. It seems like this:
staged unstaged path
1: unchanged +0/-1 TODO
2: unchanged +1/-1 index.html
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
What now>
It’s shows status
above which like git status
but more clear, and commands below.
There are 8 commands shown, and a ?
hidden:
1 status show the main interface, usually for refresh
2 update add files into index, just like `add file` but not work for new files
3 revert remove files from index,just like `reset file`
4 add untracked add new files into index
5 patch like `add -p file`
6 diff show what in the index
7 quit quit
8 help help, about commands
? help, about the interface
You can just use the index or the first letter instead of full command.
There are 5 core commands: u
r
a
p
d
. Each of them leads to a second level interface,
the command prompt change from >
to >>
.
In this level, we can choose files with index or unique prefix of filename.
Currently, it’s not support segmental matching, fuzzy matching or *
, ?
yet.
Nor tab hints and input history. Wish they will be added in the future.
For now, the index is enough. We can add a -
before the index or file path, to remove adding,
Type Enter to confirm the selection and type Enter again to take the action.
The add --i
bring us a great interface, we can play fluently, without repeating git status
.
On the mode, this is the ultimate weapon. But it’s an imperfect weapon.
There are add file
, reset file
and add -p file
within the add -i
.
But reset -p file
, checkout file
, checkout -p file
are missing.
So, for right now the best way is still the 3Ps Sorcery.