Git 暂存区的使用
一个健康的版本库,是可阅读,可追溯的。对于每一次提交,我们需要有清晰的把握。 Git 的暂存区(index),就是我们的得力工具。暂存区,就像是超市里的购物车。 我们在货架(工作区)上挑选商品(文件的修改),并带到收银台结帐(提交)。 有了暂存区,我们可以对一大堆修改进行分门别类,先后有序的提交。
基本命令
对暂存区的操作,主要使用三个命令 add
、reset
、checkout
。
它们的作用分别为:
-
add
将修改加入暂存区 -
reset
将修改从暂存区移出 -
checkout
放弃未加入暂存区的修改(从暂存区同步到工作区) 其中resset
和checkout
都是多用途的命令,分别还有另一个用途。reset
还可用于重置当前分支,checkout
还可用于重置 HEAD 并检出文件。 区别在于若命令后跟提交(hash)或指向提交的指针(分支、tag 等), 则是重置分支和 HEAD 的功能; 命令后跟文件,或没有参数,则是本文所说的用途。
精细操作 --patch
add
、reset
、checkout
三个命令都可以加 --patch
选项,简写为 -p
。
遍历每一处修改进行精细处理。
后面可以跟文件名作为参数;也可以不加参数,表示对所有修改进行处理。
三个带 -p
的命令组合使用,我给它起了个俗名,叫“3P 大法”。
是目前处理 git 暂存区的最理想方案。
执行命令将进入一个交互界面。大致如下:
最后一行的内容三个命令个有不同,分别为:
说明了各自的用途。
这里可见,git 展示了我们对 index.md 文件作出的一处修改。
并提供了 y,n,q,a,d,k,K,j,J,g,/,s,e,?
十一个可用的操作。分别表示什么呢?
别的不清楚,但 ?
想必是用来提供帮助。我们输入 ? Enter。
得到提示信息:
add
reset
checkout
初次看简直眼花缭乱,让我们整理一下:
基本使用只需要掌握 y
、n
、s
、q
,高级使用就再加上个 e
。
程序员一般有 y
、n
、s
、e
就够用了。
导航命令则对于字典维护人员,webpack 配置师这样的工种比较有用。
下面我们详细讲一下这个 e
。既然是 edit,自然需要 editor。
和不带 -m
选项的 commit
一样,它会调起编辑器,vim、nano 或是其它,依据你的配置。
内容如下:
以上展示了一处修改,我们删除了 bar 行,并增加了 baz、qux 两行。
@@ ... @@
中的内容展示了修改所在的行号和修改前后的行数。
紧接着是内容,在每行的行首第一个字符,表示行的类型,可以是 空格、-
、+
。
空格表示普通行,此行没有修改;-
表示删除的行,而 +
则表示新加的行。
注意,此空格不是缩进。若你使用缩进符,则非常清晰;若使用空格符代替缩进符,则要仔细了,要多一个空格。
此时,若保存退出编辑器,则表示应用(加入/移出/丢弃)此修改,相当于直接敲 y
。
若我们将修改还原,即删除所有新加的行,即把删除的行取消删除,即将-
改为空格,
则等于不应用此修改,相当于直接敲 n
。
若我们修改内容,则可以得到更多的效果。要注意不是所有修改都是允许的。
在 add
时,情况比较容易理解。例如我们修改为如下的样子:
表示我不删除 bar 行,而删除 foo 行。
baz 行的内容进行修改。而 qux 行则换个位置插入。
理解起来并不困难。
我们可以总结出规律:在 add
时,空格行和 -
行可以相互转换,但的内容不能修改;
而 +
行则可随意修改,删除,还可以在任意地方插入。
而 reset
时,情况就和 add
相反了。空格行和 +
行可以相互转换,但的内容不能修改;
而 -
行则可随意修改,删除,还可以在任意地方插入。
这让人十分费解,还是用例子说明吧。还是上面的内容,我们作如下编辑:
我们得以“放弃”,“取消”这样的字眼来分析。
我们将空格行 foo 改为 +
行,表示取消对 foo 行的添加。
可 foo 行并非添加的,而是原来就在,所以就是删除 foo 行啰。
删除的 bar 行改为 Bar 行,表示不放弃对 bar 行的删除,而取消对 Bar 行的删除。
那么 bar 行还是要删,然后添加 Bar 行。取消不存在的删除,等于添加。即 bar 行改为 Bar 行。
最后,放弃对 ET 行的删除,也等于新插入一个 ET 行。
有点绕脑。有一个囫囵吞枣的办法:reset 时,把 +
当 -
,把 -
当 +
就行了。
checkout
时,由于方向和 reset
一致,因此允许的修改和效果,都和 reset
一致,是反的。
区别只是 reset
改的是暂存区,而 checkout
改的是文件内容。
因此,可以 checkout
来做做实验。躬行所悟,可比纸上所得要深刻百倍。
需要注意,对于新文件,add -p
是无效的,它会跳过这些文件,而 reset -p
则没有这个问题。
对于新文件的 add
,必须整个文件进行操作。
整个文件操作和全局操作
通常,用 -p
浏览一遍到底提交了些什么总是好的。
但也会有需要整文件操作,甚至全局操作的时候。
只是勿图方便而滥用。
-
git add file
将文件中的全部修改加入暂存区 -
git reset file
将文件中的全部修改从暂存区移出 -
git checkout file
放弃文件中的全部未加入暂存区的修改 -
git add .
将文件中的全部修改加入暂存区 -
git reset
将暂存区中的全部修改移出(清空购物车) -
git checkout
全部未加入暂存区的修改
未完善的终极武器 add --interactive
git add 中,还有一个更加新潮的选项:--interactive
,简写为 -i
。
顾名思义,这也是一个交互界面。样子如下:
上方显示 status
内容,与 git status
得到得主体内容差不多,列表得方式看起来更加清晰。
下方显示可用的操作,一共有 8 个,此外还有个隐藏的 ?
,分别为:
实际使用时,敲数字或首字母即可,无需键入完整命令。
其中 u
r
a
p
d
为核心操作,执行后,会进入到二级界面,我们看到命令提示符由 >
变为 >>
。
这时候,我们可以选取要操作的文件。可用序号选择,也可输入文件名(前面一段,没有重复即可)。
目前,文件名还不支持分段匹配、模糊匹配、*
?
,也不支持 tab 键输入提示,和上下键输入历史,希望将来能有。
但序号也够用了。在所选的序号或文件名前加 -
则表示取消选择。第一次回车,执行选择,然后可以继续选择。
第二次回车,执行操作。
add --interactive
给了我们一个很棒的操作方式,我们可流畅地操作,不必一而再再而三地执行 git status
。
就操作方式而言,可以说是终极武器。然而这个未来的终极武器还有需多不够完善之处。
它有 add file
、reset file
以及 add -p file
却缺少了 reset -p file
、checkout file
、checkout -p file
。
可以说只整合了一半的功能。最关键的 add -p file
和 reset -p file
,就少了一个。
我们只能先 reset file
再 add -p file
。若文件中有很多修改,这会相当麻烦。
因此,这个命令还需要观望。目前最佳方案,还是三个 patch,俗称 3P 大法。