首页 > 代码库 > 《Git小书》笔记:4 暂存区

《Git小书》笔记:4 暂存区

这节讲了暂存区,我觉得讲的很好啊, 之前一起奇怪暂存区怎么用来的。

还用之前的比喻吧。

暂存区就好比侦探的那个相机嘛,暂存区的本质其实不是用来暂存的,如果说用来暂存的,至少会引起误解,因为我们会说为什么要暂存呢?直接存不就好了,为啥多此一举。的确,如果某种情况你要直接存当然不需要暂存区了。

但是暂存的是什么?暂存的是文件吗?正如那个侦探拍摄到的嫌疑人,他拍摄的是整个人吗?不是,他拍摄的一个行为。同理,暂存区暂存的是什么?暂存的是修改而非文件,我们要用改动的眼光看待文件,一个文件从诞生伊始,空无一物,接着我们每次添加一点或者删除一点,文件的本质就是这些添加和删除的动作的合体。

那么如何证明暂存的是修改而非文件呢?

插播一下,Ubuntu下升级Git到最新版本:

sudo add-apt-repository ppa:git-core/ppa

sudo apt-get update

sudo apt-get install git

首先创建一个文件,添加一行内容进去:

技术分享

那么该如何理解这个file2呢?

技术分享

不要把file2理解成一个文件,而是要看到一个修改:添加了line1,而file2这个修改的名字,所以接下来的:

技术分享

其实添加的不是file2,而是指代添加的修改,让我们验证一下,先把这个暂存区的东西提交上去:

技术分享

再次修改file2:

技术分享

(这里我也感觉说不清楚了)

好的,现在等于又在file2这个大盘子里,放了个line2水果,但是这个改动还没有提交给老板呢,

老板要查看所有改动:也就是对比工作区和参考盘子里面东西的差异,这里diff对比的其实暂存区和工作区里差异,因为是为了看我们要提交哪些组合(会事先暂存一下),而不是比较的仓库和工作区:

技术分享

那个file1无视吧,是我之前删掉的文件。

这里解释下那个

技术分享

什么意思吧:两个@@限定了变动行数的范围;

-表示变动前的文件,1表示第一行开始,因为没有第二个数字,所以就表示相同的行;

+表示变动后的文件,1表示第一行开始,到第二行结束;

也就是变动位置范围是原来文件的第一行变动到后来的第一行到第二行。

参考读懂diff

老板发现file2盘子又多了个(+)line2

我们把这个line2页添加到暂存区了吧:

技术分享

查看一下状态,说暂存的这个改动没有提交:

技术分享

那我们就提交一下吧:

技术分享

好的,所以说Git管理的究竟是什么?是文档吗?不是,Git管理的修改。提交又是什么?提交是文档的修改吗?不是,提交的是修改的组合。软件版本不就是修改的组合吗。

??

如何不暂存就提交呢?git commit -ma "change" 但是不建议这么做,因为我这是我用的最多的方式,而这种方式根本没有体现版本管理,如果经常用这个,会忘记真正的版本管理该如何合理操作,所以不建议,除非是用Git来备份文件用的。

-------------------------------------------好的,上面提到了提交的本质是修改的组合,所以现在来看看,如何提交修改的组合。

先创建一个代码仓库:

技术分享

常见的一种情况是,我们有一个项目,项目目录是code,然后项目是由一些文件构成的

比如今天,我为几个文件添加了几个功能,然后又修改了几个bug,假设这几个功能和bug都分布在独立的文件里面:

我们先对几个文件完成跟踪,然后再修改这几个文件,最后收工的时候再完成分类修改并分类提交:

技术分享

因为新的暂存会覆盖旧的文件,所以我们先提交commit一下:

技术分享

接着把5个文件修改一下,好吧,这一天的工作都用来fixbug了:
?

技术分享

好了现在我们把暂存区当做一草稿纸,在草稿纸上列下你想提交的修改项目(这里为了简化问题,修改以文件为单位),你可以添加git add addfeat1.c,也可以添加多个修改,git add addfeat1 addfeat2,也可以撤销某个修改git reset addfeat1,既然是修改嘛,肯定就有反悔了,我们不是经常做了某件事就想反悔了嘛,Git提供了强大的撤销功能,后面再说。

------------------------------------------------------上面为了简化说明,把整个文件的修改当做一次修改,这也是我们最习以为常的思维方式。其实Git的强大之处在于以修改为单位进行分类提交,而不是以文件为单位,你可以修改一次提交一次,但是如果整个文件改完了才想起提交怎么办呢?没事,Git还提供了Hunk拆分,不要不这个单词吓住了,简单地说,一个文件会有一系列的修改,这里我们把修改限定到行上,也就是行修改是修改能识别的最小单位也就是:

源文件内容是:

技术分享

以行修改为最小修改单位,Git以连续行修改为Hunk识别对象:

技术分享

上面这种情况,有两个行修改,因为是连续的,所以被识别为一个Hunk。

技术分享

上面这个情况,也有两个行修改,但是不连续,所以被识别为两个Hunk修改块

技术分享

上面这个也是两个修改块Hunk。

??

好了,那么怎么处理Hunk呢(我们把问题限定到一个文件内),怎么把一些Hunk提交为功能,把另一些Hunk提交为bug修复呢?

我们使用互动暂存功能,方法就是加个p参数:

技术分享

如果可以识别到两个以上的Hunk,则输入s(split)会提示拆分成了两个hunks,接着输入g(go)去到hunk列表,然后问你

选择哪一个修改块hunk,选择后,会问你是否暂存呢选择的块,输入y(yes),系统会暂存这个块,然后循环这个问答,直到所有块被暂存或者你输入q退出本次暂存。

如果你只暂存了一个文件的部分hunks,则文件的状态为MM,表示处于修改和暂存的状态,很有意思,以前肯定没有想过一个修改完成的文件居然还可以拆分开来提交,所以说修改才是文件的本质,把文件看做整体那是从阅读者的角度而非构成角度

选择了特定的几个hunks,然后就可以分类提交了,比如是添加功能还是修复bugs等等,而不用一次性提交整个文档了。

很酷吧。

??

接下来,可以查看一下提交历史满足一下满足感:

git mist 还记得之前的别名技巧吗?这里就很方便了,而且不用看见哪些莫名其妙的SHA1乱码了。

技术分享

《Git小书》笔记:4 暂存区