理解git结构与简单操作(二)工作区与暂存区

工作区

其实工作区没什么好讲的,这个区域其实就是抽象了你的磁盘文件本身。但是,单独抽象出工作区对于git概念的整体理解是相当有必要的。

比如说,工作区其实是整个git流程的源头,你对工作区的修改其实就是git要保存的对象。所以,当你修改工作区完成(写完代码),将修改从工作区提交到远程仓库的流程中工作区的内容是绝对不会变的。简而言之,在提交的流程中只有你自己去修改文件,git不会去动。

但是,当你发现你修改错误之后,就可以借用git版本库和暂存区的内容反向修改工作区。比如:

  • 将暂存区的改动同步到工作区,就是git checkout
  • 将版本库的代码同步到工作区,就是git reset HEAD <commitId> --hard

这种对于工作区的修改其实是非常危险的:如果你将改动checkout掉,在没有手动备份的情况下你修改的这部分内容就找不回来了。所以,修改代码要谨慎,checkout要谨慎,版本回退要谨慎。

涉及操作:git checkout, git reset HEAD <commitId> --hard

暂存区

暂存区的概念虽然在所有git教程中都是重点提到的内容,但是实际工作中大部分同学对此都是懵懵懂懂。我认为,这是因为暂存区的英文翻译导致的╮(╯▽╰)╭。

暂存区的英文名称叫stage。这个stage呢,既是个名词也是个动词,但是都没有「存储」的意思,这是很多人疑惑的地方。我们从暂存区的作用来看看stage到底是什么意思。

在用git提交的过程中,每当工作区发生了修改,git status就会显示你修改的文件为红色,代表这些文件发生过修改,上面提到了,这些文件在git里叫做「Changes not staged for commit」(git status可以显示工作区修改、暂存区文件以及你本地分支相对于远程分支的情况)。而当你执行git add <filepath>之后,这些文件就变成了绿色,如图:

绿色的文件git称之为「Changes to be committed」,就是将要被提交的修改。也就是说,暂存区会集中一批修改,统一提交成一个commit。

举个例子,git的提交流程就像是一个生产流水线:你先咔咔生产一批产品(修改文件),然后把生产好的文件放到一个存放的地方(git add到暂存区),当你觉得这批货不管是质量还是数量都OK了,就把这批货打包装箱(git commit)。

这样就明白暂存区是啥意思了吧。所以我认为,暂存区存在的意义就是规范你的每一次commit。你可以把暂存区想象成一个分支的一次commit的内容,执行git commit提交时就把暂存区这个commit放到现有分支的顶端。

还有很多人不理解暂存区和工作区的关系,有一种情况可以加深对其的理解:当你把一个文件的修改add到暂存区之后,再次从工作区修改这个文件,会出现这样的情况:

这说明暂存区和工作区是分开的。暂存区保存的是当你add时修改的内容,而你再次修改工作区时,git又会检测到你的修改跟暂存区中的不一样,就出现了未暂存和已暂存同时出现的情况,这时继续git add,暂存区中的修改就会集中这两次的修改内容,然后commit就会把两次修改提交成同一个了。

综上所述,暂存区stage的英文含义像是一个阶段性的平台,用来保存你即将打包成一次commit的提交们。从英文含义角度理解,这个词儿其实还是挺生动形象的。(emmmmmm......)

而暂存区的修改是如何同步到文件区呢? 在说暂存区时已经提到过,答案就是git checkout <filename>啦。checkout就是「检出」的意思,当出现上面图中暂存区和工作区都有修改的时候,checkout会从暂存区「检出」修改到工作区中,使工作区与暂存区同步(关于checkout其他用法后面再说)。

最后,已经在暂存区中的修改如何去掉,git已经提示了:「git reset HEAD <file>...」。观感上,就是把暂存区中的某些修改从中删去了,实际上,这个git reset的操作是从版本库同步代码到暂存区中的意思。也就是说,在这里的git reset完成了使用版本库的代码修改暂存区的操作。

涉及操作:git status, git add, git commit, git checkout, git reset HEAD <file>



评论

暂无评论

在这里输入