一.Git概念
Git(读音为/gɪt/)是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。 [1] 也是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源码的版本控制软件。
二.Git结构理解
上图展示了git的整体架构,以及和各部分相关的主要命令。先说明下其中涉及的各部分。
工作区(working directory),简言之就是你工作的区域。对于git而言,就是的本地工作目录。工作区的内容会包含提交到暂存区和版本库(当前提交点)的内容,同时也包含自己的修改内容。
暂存区(stage area, 又称为索引区index),是git中一个非常重要的概念。是我们把修改提交版本库前的一个过渡阶段。查看GIT自带帮助手册的时候,通常以index来表示暂存区。在工作目录下有一个.git的目录,里面有个index文件,存储着关于暂存区的内容。git add命令将工作区内容添加到暂存区。
本地仓库(local repository),版本控制系统的仓库,存在于本地。当执行git commit命令后,会将暂存区内容提交到仓库之中。在工作区下面有.git的目录,这个目录下的内容不属于工作区,里面便是仓库的数据信息,暂存区相关内容也在其中。这里也可以使用merge或rebase将远程仓库副本合并到本地仓库。图中的只有merge,注意这里也可以使用rebase。
远程版本库(remote repository),与本地仓库概念基本一致,不同之处在于一个存在远程,可用于远程协作,一个却是存在于本地。通过push/pull可实现本地与远程的交互;
远程仓库副本,可以理解为存在于本地的远程仓库缓存。如需更新,可通过git fetch/pull命令获取远程仓库内容。使用fech获取时,并未合并到本地仓库,此时可使用git merge实现远程仓库副本与本地仓库的合并。git pull 根据配置的不同,可为git fetch + git merge 或 git fetch + git rebase。rebase和merge的区别可以自己去网上找些资料了解下。
看到这里,不仅清楚了 git fetch 与 git pull。而且我们使用每个命令时,也能清楚的明白此时git做了什么工作。
临时存储区,git stash
(参考链接:https://blog.csdn.net/mozes1/article/details/106387189/)
三.如何优雅的提交代码?
1.临时存储区流
a.将工作区的修改保存到临时存储区,保证工作区的status状态是一个干净的状态
b.进行远端仓库和本地仓库代码的同步
c.将临时存储区中的代码弹出到工作区,这样会自动合并工作区中的文件,有可能有冲突,有可能没有冲突。
d.有冲突就解决冲突然后正常提交代码即可
2.本地仓库流
a.正常开发代码,写好了就提交到自己的本地仓库
b.感觉代码写好了,想推送到远端仓库,那么这个时候需要远端仓库和本地仓库代码的同步。
c.这里可以看到同步代码,出现了冲突,并且上面也提示了冲突解决后应该继续执行git rebase --continue
d.冲突解决,正常往远端仓库推送代码即可
3.总结:
自己喜欢哪个就选哪个,尽量保证远端仓库和本地仓库同步代码的时候,工作区是干净的。因为有的同学喜欢用git pull来同步代码,其实git pull = git fetch + git merge的。这样会导致同步代码后直接合并工作区,有的时候合并会导致一些意外的麻烦。
四.如何优雅的合并分支?
1.在dev分支中增加branch.txt
2.分支切换到master,在master分支增加内容
3.将分支切换回dev分支,将master分支合并到dev分支,将master分支合并到dev分支
4.出现冲突将冲突解决,并提交代码,推送到远端的dev分支
5.此时将分支切回master分支,将dev分支合并到master分支。
总结:可以看到成功合并到master分支,并且推送到远端分支。
为什么要先将master分支合并到dev分支呢?
这样坐是为了将冲突在dev分支解决,然后再将dev分支代码合并到master,这样可以最小限度污染master分支代码。
git merge --no-ff: 禁止快进式合并
Git 合并两个分支时,如果顺着一个分支走下去可以到达另一个分支的话,那么 Git 在合并两者时,只会简单地把指针右移,叫做“快进”(fast-forward),比如下图:
要把 feature 合并到 master 中,执行以下命令
$ git checkout master
$ git merge feature
结果就会变成
因为 feature 就在 master 的下游,所以直接移动了 master 的指针,master 和 feature 都指向了 C。而如果执行了 git merge --no-ff feature 的话,是下面的结果:
由于 --no-ff 禁止了快进,所以会生成一个新的提交,master 指向 G。
从合并后的代码来看,结果其实是一样的,区别就在于 --no-ff 会让 Git
生成一个新的提交对象。为什么要这样?通常我们把 master 作为主分支,上面存放的都是比较稳定的代码,提交频率也很低,而 feature
是用来开发特性的,上面会存在许多零碎的提交,快进式合并会把 feature 的提交历史混入到 master 中,搅乱 master
的提交历史。所以如果你根本不在意提交历史,也不爱管 master 干不干净,那么 --no-ff 其实没什么用。不过,如果某一次 master 出现了问题,你需要回退到上个版本的时候,比如上例,你就会发现退一个版本到了 B,而不是想要的 F,因为 feature 的历史合并进了 master 里。
--no-ff 在这的作用是禁止快进式合并。
(参考: https://blog.csdn.net/zombres/article/details/82179122)
五.其它
1.reset命令
git reset --hard [索引] : 本地库索引移动的同时,重置暂存区,重置工作区
git reset --mixed [索引] : 本地库索引移动的同时,重置暂存区,工作区不动
git reset --soft [索引]: 本地库索引移动的同时,暂存区,工作区都不动
回退到上一个版本:git reset --hard HEAD^
回退到上上一个版本:git reset --hard HEAD^^
2.找回暂存区删除的文件
a.删除工作区数据
b.同步到暂存区
c.后悔了,恢复暂存区中数据
或者:
3.找回本地库删除的文件
a.新建一个文件test.txt
b.将它add到暂存区中
c.通过commit提交到本地仓库
d.删除工作区中的test.txt
e.将删除同步到暂存区
f.将删除同步到本地仓库
g.查看日志,将历史版本切回刚才添加文件的那个版本