引言

Git的学习笔记(一)中学习了:git init、git add和git commit ,这三个命令的执行我们可算是完成了创建版本库的前奏三部曲。这篇文章就学习下Git与其他版本控制系统相比更先进人性化的设计。

一、工作区(Working Directory)、 版本库(Repository)和 暂存区(stage or index)

1、工作区

我们会想当然的认为,当前仓库所在目录就是我们的工作区,其实这是不完全正确的。在当前仓库中,新增,更改,删除文件这些动作,都发生在工作区里面。

2、版本库(.git目录)和暂存区

当前仓库下,如果没有任何的提交,那么版本库就是对应上次提交后的内容。
暂存区,英文名stage(or index)。在版本库.git目录下,有一个index文件。它实际上就是一个包含文件索引的目录树,像是一个虚拟的工作区。在这个虚拟工作区的目录树中,记录了文件名、文件的状态信息(时间戳、文件长度等),但是文件的内容并不存储其中,而是保存在Git对象库(.git/objects)中,文件索引建立了文件和对象库中对象实体之间的对应。如果当前仓库,有文件更新,并且使用git add 命令,那么这些更新就会出现在暂存区中。

  • 当执行 git reset HEAD 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。

  • 当执行 git rm –cached 命令时,会直接从暂存区删除文件索引,工作区则不做出改变,注意一点,.gitignore只能忽略那些原来没有被track的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的,假如说你已经track了一些不该track的文件,每一次你git status都会提示你已经修改了,拿Android studio文件下的.idea/文件夹来说吧,这个文件是不需要提交的,而每次我们提交的时候都会提示已经被修改了,很烦,而且直接修改.gitignore还是无效,此时我们只需做几步:git rm –cached .idea/ ——>git add .——>git commit -m”“——Done。

  • 当执行 git checkout .或者 git checkout – 命令时,会用暂存区全部或指定的文件替换工作区的文件。友情提醒该操作很危险,会清除工作区中未添加到暂存区的改动。

  • 当执行 git checkout HEAD .或者 git checkout HEAD 命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。友情提醒该操作也很危险,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。

3、工作区与版本库之间的关系

这里写图片描述
如上图所示左边为工作区(Working Directory),右侧为版本库(Repository)。而在版本库中最重要的就是index(或者叫stage)的暂存区,还有Git为我们自动创建的第一个分支master(master 分支所代表的目录树),以及指向master的一个“指针”叫HEAD。其实上图中的命令中出现 HEAD 的地方可以用 master 来替换。最后一个objects 标识的区域为 Git 的对象库,实际位于 “.git/objects” 目录下,里面包含了创建的各种对象及内容(如果感兴趣Git对象的各种真面目可以使用git cat-file -t -p commitId 来探寻)。

二、git add的理解

当对工作区新增(或修改)的文件执行 git add 命令时,暂存区的目录树被更新,同时工作区新增 (或修改)的文件内容被写入到对象库中的一个新的对象中,而该对象的Id被记录在暂存区的文件索引中。一句话add就是把文件修改添加到暂存区

三、git commit的理解

当执行提交操作git commit时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。简而言之,commit把暂存区的所有内容提交到当前分支

四、 git diff 的妙用

通过使用不同的参数,我么利用git diff 可以完成工作区、暂存区和HEAD之间的比较。
这里写图片描述

1、git diff 比较的是工作区和暂存区的差别

2、git diff –cached 比较的是暂存区和版本库的差别

3、git diff HEAD 可以查看工作区和版本库的差别

这里写图片描述
接下来做个简单的实验,如图所示已经提交过了两个版本,然后再在工作区中修改文件teststage(添加了一个字符串Git),但是还未执行add即还没有把这次修改add到暂存区中

addcommit之时,
这里写图片描述
commit之后
这里写图片描述

五、 git reset和git revert的区别

reset是重置,默认是git reset –mixed commitid 可以让版本库重置到某个commit状态,该commit之后的commit不会保留,并重置暂存区,但是不改变工作区。即这个时候,上次提交的内容在工作区中还会存在;如果使用git reset –hard commitid版本库,暂存区和工作区的内容全部重置为某个commit的状态。之后的commit也不会保留。

revertreset更加温柔一点,回滚到某次commit且该commit之后的提交记录都会保留,并且会在此基础上新建一个提交。所以对于已经push到服务器上的内容作回滚,推荐使用revert。

六、 Git 提交流程的简要描述

Git是由工作区、版本库构成的,其中版本库中又细分为暂存区、分支和Git对象库
Git 每一次追踪的历史都是针对操作(修改、新增或者删除),而非文件。从某种意义上来说Git 的管理可以看作是一个类似”快照“功能,一个版本对应一整个快照。所以当我们想要使用Git管理文件。一般流程是把文件都复制到工作区里,然后使用git add至暂存区,再通过git commit 把暂存区里的修改一次性commit到当前分支。如果把这一切操作比喻成购物shopping,我们选择商品就相当于是把文件复制到工作区里,commit操作就相当于付款。等等这里是不是还漏了一个暂存区。暂存区可以看成缓冲区,在shopping的过程中就像是我们的购物车,没有完成付款前我们就不确定那些商品是需要购买的,如果没有购物车我们只能选一件付款一件,那就麻烦了。

小结

暂存区意义在于确定你要把哪些修改(包括新增和删除)纳入到当前版本管理分支中,修改过的文件通过执行git add放置到暂存区。等确定完哪些需要提交之后(假如当多个文件修改完成放入暂存区的时候,突然惊觉其中一个文件的代码有问题,此时通过checkout单独将这个文件还原重改;如果你将这些文件一次性全部放进分支,等你发现有问题时就不能单独拿出一个文件了,只能版本回档,那时你就要重新修改所有文件的代码),再通过git commit 把暂存区的修改提交至当前分支。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐