GIT状态转换图解

最近项目提交时总是感觉很慌,不是这里出问题,就是那里出问题。研究了一下git的常用操作,也自己动手操作了一下。画了这么个图。后面会对常用操作和一些重要的概念做一些文字说明。GIT状态转换图解心得体会:

1.工具固然用起来方便,问题还是蛮多的。比如TortoiseGit,还有eclipse,IDEA集成的git图形界面。你不知道它后台给你执行了什么命令。有时候它自作聪明给文件加上花里胡哨的图标,让你很不舒服,甚至还有点心慌。所以,干脆,命令行敲起来,想做什么自己做主,不用假手于人,看人“脸色”。

2.比较重要的几个概念:

1)暂存区:工作区就是你当前编辑的文件。如果想提交,先add到暂存区。这样可以给你选择提交哪些不提交哪些的余地。

2)本地仓库:add到暂存区之后,再执行commit,就把文件提交到了本地仓库。进了仓库的文件,就比较安全了,后面误删,误改,都可以通过git reset commitID在所有的提交版本之间进行切换,就像时空穿梭。比如你的文件经过几次修改,已经面目全非,你想回到前面的版本,拿到当时提交的代码。那么就使用git reset commitID回到那个时刻,把文件复制出来,在切换回现在。HEAD ,顾名思义,头部,表示本地版本库的最新提交的那个版本,头指针指向的位置。

3)本地仓库中的远程镜像:这是一个独立的版本仓库,独立于本地提交的仓库,每次使用fetch命令的时候,会把远程仓库最新的代码复制到本地仓库的远程镜像。这就是fetch和pull的差别。fetch只是把远程代码复制到本地远程镜像里,而pull除了复制到远程镜像,还会尝试把远程代码和本地代码进行合并。如果本地工作区或者暂存区有东西没提交,pull就不会执行,git会提示你,先把这些文件commit或者stash一下。因为合并是针对仓库里最新的版本来说的,而不是跟你工作区进行合并。这也就是为什么上面说,提交到本地仓库就比较安全的原因。

4)分支:分支是多版本的管理的核心,也是git的精髓所在。只有在项目中善于使用分支才算是真正掌握了git。根据需要建立分支,在适当的时候做提交。这样,再也不担心文件丢失,覆盖。

3.几个比较容易混淆的概念:

1) git checkout --  与 git reset :

git checkout -- filename 将工作区文件恢复到最近一次提交到暂存区或者仓库的状态。暂存区有东西就恢复到暂存区的样子,暂存区为空,就恢复到最近一次提交的仓库状态。

git reset commitID 这个是直接恢复整个工作区到之前提交的某个版本。有3个模式 :

--soft 只恢复提交区,不影响工作区和暂存区

--mixed 只恢复提交区和暂存区,不影响工作区(默认模式)这就是为什么想把暂存区的内容全部取消掉,可以使用git reset HEAD,这样就把暂存区的内容恢复到最新版本库提交后的状态,那时候暂存区里是没有任何东西的,同时还不影响工作区。这个操作特别适合一次取消很多文件的情况。

--hard 提交区,暂存区,工作区全部恢复到某个版本,如果工作区有内容会要求先commit或者stash。贴心。

2)git reset 与 git revert:

git reset 如上面所讲,是直接移动指针在各个版本之间穿梭;什么意思呢?比如我有1,2,3这3个提交,我现在想穿梭会2,使用git reset的话,就直接回到2版本了,使用git log查看,3这个提交就消失了。(使用 git reflog还是可以找得到3)

git revert 不同,还是我有1,2,3这3个提交,我想回到版本2,revert会创建一个跟版本2一样的版本4出来,我用git log查看的话,3还在。

实际操作体验,使用revert回滚时,会提示冲突,需要解决冲突之后才能提交,相当于是一次新的修改;而reset回滚时,直接回滚到当时的版本内容,并不会提示冲突。(这里的前提是你的工作区和暂存区没有未提交的内容,否则reset命令不会执行,而是提示你先commit或者stash)

3)git fetch 和git pull:

这个上面已经说了,一个是更新文件到本地远程镜像;一个是更新代码到本地远程镜像并且尝试合并远程文件到HEAD。

4)checkout 和 clone:

这两个差的有点多,这里主要说一下用法:

git checkout branchname 切换分支;

git checkout -b branchname 使用当前分支作为模板创建分支并切换到新建的分支

git clone http://xxx.xx/xxx.git 把远程仓库克隆到本地,默认克隆master分支

git clone -b branchname http://xxx.xx/xxx.git 指定克隆的分支到本地

这里可以看到,checkout是以本地版本库中的某个分支作为模板进行检出的。如果本地想检出远程的分支怎么办呢?

git fecth //先把远程的版本库复制到本地的远程镜像中

git checkout -b branchname origin/branchname  //origin指代远程仓库

5)git add :

git add . 将当前修改、新增的文件加入暂存区,包括变化的文件,不包括被删除的文件;

git add -u 将当前修改、删除的文件加入暂存区,本质上是那些被追踪的文件,不包括新增的文件,因为新增文件没有被追踪;

git add -A 上面两个操作的并集

6)  git update-index --skip-worktree 与 git update-index --assume-unchanged

有时候,我们从服务器clone下来项目之后,会修改一些配置文件以便于本地开发,但是提交的时候git会把这些修改列出在修改列表里。每次都选择性提交很不方便。这时有人可能会想到把这些文件放进.ingnore中,结果提交之后发现服务器竟然把文件给删了,简直哭笑不得。这时候你就需要用到 git update-index --skip-worktree filename了。他的作用是在提交时跳过提交这个文件。

那么跟它意义很相似的另外一条命令git update-index --assume-unchanged 是干什么的呢?字面意思是假定未改变。什么意思呢?比如我们源码里面有个包下面放的我们的基础组件,很稳定,开发完成后几乎不会再修改。但是每次git status的时候,git都要去检查这个目录,无形中浪费了一些时间。这时候我们就可以使用这条命令把这个目录标记为无变化文件夹,从而提升性能。

这两条命令对应的取消命令分别是 --no-skip-worktree 和--no-assume-unchanged.

7)参数有的用一个短线,有的用两个短线,什么意思呢?

一个短线是简写,两个短线的就是全拼,可能作者认为,你既然想费事,那就多费一点吧。

4.想要熟练掌握,首先搞清楚基本概念,遇到问题仔细想一下当前处于什么状态,再对照各个状态之间转换改用什么命令。一般情况下,命令行操作都有非常准确的提示信息以及命令使用建议,遇到异常不要慌,解决几次难题,有了自信,后面就越来越得心应手了。