工作中我是怎么使用git的--git教程 中
本篇为中篇,介绍git在多人协同开发中的使用
中篇
节点树
在上篇中,我们了解到commit
会生成一个提交记录,每一个提交记录均有一串唯一编码。将每一次的提交记录看作是一个节点,节点和节点相连形成图中的节点树。
这里我使用的是来自Sourcetree
软件的截图,这里我们重点关注右侧表格。每一行为一个节点,按时间降序排列在表中。我们来认识这里每一列的含义。
- 图谱,图谱中便是节点树本树了,节点下方的线条表示这个节点是从哪个节点变化而来的,一个节点下方最多只会有两条线,表示这个节点最多由两个节点变化而来。一般这类git工具都会选用不同的颜色来区分每一个分支。
- 描述,描述中的文字很简单,就是这一次提交时输入的文字,左侧会有两种标记,分支名和标签。
- 分支,如果分支出现在这一行,则表示这个分支最新的提交记录就在这了。带有
origin/
前缀的为远程分支,这个origin
是对远程分支的默认前缀,可自定义成其他名称。 - 标签,和分支名一样,如果出现在这一行,则表示在这个节点上有一个标签。
- 分支,如果分支出现在这一行,则表示这个分支最新的提交记录就在这了。带有
- 日期,这个节点的提交日期和时间。
- 作者,提交人。
- 提交,每一个节点的唯一编码,此处展示的是前6位,可以直接使用这个来代替整串编码进行操作,如果项目提交数过多的话位数会有所增加。
另外图中的第一行是有未提交的更改
,这其中便是我们正在修改的内容。其他git工具对节点树的展现方式也基本时这样的形式。
先来热热身
在进入下面教程之前让我们在上篇教程中的test
项目上做一个小小的热身。
-
来到我们的
test
项目, 确保当前分支是master
。如果不是的话,请切换到master
分支。 -
先创建一个文件
编程书籍.txt
,输入以下三行内容并保存。1. Java 2. 代码质量 3. Linux
-
执行
add
,commit
,push
,将本次提交推送到远程。 -
新建三个分支
book-java
,book-code
以及book-linux
。 -
切换到分支
book-java
上,修改编程书籍.txt
,在Java下增加几本书,并执行提交。 -
切换到分支
book-code
上,修改编程书籍.txt
,在代码质量下增加几本书,并执行提交。 -
切换换到分支
book-linux
上,修改编程书籍.txt
,在Linux下增加几本书,并执行提交。 -
最后切回到分支
master
执行以下命令。git merge book-java git merge book-code
在执行第二个命令的时候我们的git bash会弹出一串提示信息,我们暂且略过,按下
shift+;
后再输入q,回车。(这里的操作类似于linux系统的vim。) -
恭喜你,热身结束,可能有小伙伴发现我们创建了三个分支,还有一个呢?这个嘛,剩下的分支
book-linux
我们一会就会操作到了。
分支合并和冲突
在上篇中我们已经学习到了merge
的使用,为什么当我们进行第二次merge
命令时会出现提示信息呢?这里我们就要来看到合并之后的节点树了。
当把执行git merge book-java
时,由于分支book-java可以通过下方的连接线找到分支master,所以不会有弹出框;而执行git merge book-code
时,分支book-code无法通过下方的连接线找到分支master,所以需要合并形成一个新的提交节点,弹出框中输入的内容就是我们这一次merge的提交内容。
冲突
现在让我们执行git merge book-linux
,可以看到提示和之前的merge
又不一样了,这次又是什么问题呢?
CONFLICT (content): Merge conflict in 编程书籍.txt
Automatic merge failed; fix conflicts and then commit the result.
可以看到我们的文件出现了CONFLICT,也就是文件内容冲突。这是在协同开发中常见的问题之一。在执行merge
时,如果两个分支对一个文件的修改有重叠的时候,git便无法判断需要保留哪个分支的修改内容,因此需要我们进行解决。
解决冲突
打开编程书籍.txt
,我们可以看到文件内容变成了以下情况。
1. Java
《Java核心技术 卷I》
《Java核心技术 卷II》
2. 代码质量
<<<<<<< HEAD
《图解设计模式》
《重构 改善既有代码的设计》
3. Linux
=======
3. Linux
《鸟哥的Linux私房菜 基础学习篇》
《鸟哥的Linux私房菜 服务器架设篇》
>>>>>>> book-linux
<<<<<<< HEAD
,=======
,>>>>>>> book-linux
便是冲突标记,从<<<<<<< HEAD
到=======
就是当前master
分支的内容,从=======
到>>>>>>> book-linux
就是book-linux
分支的内容。我们解决冲突,需要做的就是将冲突标记全部移除。通常我们有3种方式。
-
选择两个中的一个。
-
自行选择两者的内容进行合并。
-
也可以把冲突的内容全部删掉,换上一个全新的内容。
1. Java 《Java核心技术 卷I》 《Java核心技术 卷II》 2. 代码质量 我就是要来个新的
现在我们来操作一下解决冲突,
-
把文件内容改成下面的样子。
1. Java 《Java核心技术 卷I》 《Java核心技术 卷II》 2. 代码质量 《图解设计模式》 《重构 改善既有代码的设计》 3. Linux 《鸟哥的Linux私房菜 基础学习篇》 《鸟哥的Linux私房菜 服务器架设篇》
-
执行
git add "编程书籍.txt"
。 -
执行
git commit -m "Merge branch 'book-linux'
。 -
执行
git push
,把我们写的书籍推送到远程仓库。 -
执行
git tag v2.0
标记一个新版本。
这样冲突就被我们成功解决了。通常在工作中解决冲突时候,需要联系到冲突内容的提交者。双方进行协商得到最后的合并内容。另外也会使用git工具,或者在开发工具上进行冲突解决,毕竟命令行和基本的文本软件来操作实在是费时费力。
变基rebase
合并和冲突并不是分支与分支之间独有的,在多人协作的时候,执行pull
命令也会出现合并与冲突。这又是怎么回事呢?这里我用另外一个项目来举例。
现在我和小伙伴都在master
上有一个提交,但是小伙伴先于我提交了。在我执行push
时候就会报错,因此我需要使用pull
将master
最新的代码先拉取到本地,这样就会形成一个合并。
有合并自然就有冲突,当然处理的方式和分支冲突的处理方法是相同的。但是这样通过pull
合并的代码在分支内会将节点树变得非常不清爽。为了让节点树看起来简简单单的一条直线,我们可以使用变基rebase
。
rebase
通常有两种使用场景。
- 将本地某个分支上连续的多次提交合并成一个。
- 在同个分支中,本地需要
merge
远程获取最新代码时将其变成直接提交。(冲突依旧是需要手动进行解决的)
在现在第一张图的这个场景下,执行命令git rebase
,我们就可以得到下图完美的节点树了。
回滚和重置
刚才我们已经成功的把基本编程书籍汇总,并打上了一个新的标签表示我们的项目又达到了一个新的版本,现在我们来学习一下版本回滚。
- 确保当前在
master
分支。 - 新建文件
多余的.txt
,随意输入内容。 - 执行
add
和commit
,注意不要使用push
。
现在我们的项目中多出了一个没有意义的文件,我们可以很简单的删除它,然后再进行一次提交。不过这里git给了我们其他更简单的解决方案。
回滚revert
刚才的提交,在我机器上生成的编码是ae93f1fd135b6a91d5b75288a71feab9062d3c29
,缩写为ae93f1f
,执行git revert ae93f1f
。可以看到出现一个提示框,这个提示框的内容与之前我们使用merge
时候是一样的,执行revert
会生成一次提交。我们不修改内容退出,现在我们看到多余的.txt
文件就被删除了,在Sourcetree
中展示的结果就是这样的。
rever
命令可以回滚某次提交的内容,如果我们有多次提交需要进行回滚,那么要按照最新的提交到最晚的提交顺序一个一个进行revert
。若是遇到需要回滚有冲突的merge
时候,还要增加-m [1或2]
参数来选择回到哪个分支的内容。例如git revert 35f6996 -m 1
便是把回滚到合并book-linux
之前的内容。
重置reset
接着我们来试试reset
,reset
有三种常用模式。
- soft,保留当前文件内容(不会清空缓存区),将分支最新提交回退到指定版本。
- mixed,默认模式,保留当前文件内容(会清空缓存区),将分支最新提交回退到指定版本。
- hard,将当前文件内容和分支均回退到指定版本。(如果有未提交的内容也会被清理)
因为文件已经通过revert
删除了,所以不管是哪种模式都可以达到我们的目标,现在我们来执行下git reset
。可以发现项目最新的提交节点回到了之前v2.0
的地方,之前我们操作的内容全部消失了。所以各位要向使用reset
的时候必须要谨慎,否则导致代码丢失就要哭惨了。
以上版本回滚和重置如果只是涉及到自己本地的内容都还好,最多就是自己的工作白费了,但是要没有仔细审核内容而提交到远程,甚至还使用了git push -f
,那么可能会对整个项目产生类似于rm -rf
或者是删库跑路的这样严重的问题。
本次教程的下篇将会介绍Git Flow。
总结
本次中篇我们使用了Sourcetree
来作为git查看和管理的工具,作为开发人员来说,开发软件通常会自带便利的插件进行git操作。
总结一下本次的新命令。
rebase
变基操作可以将多个提交或合并提交变成一个提交,让节点树更清爽。rever
撤销某一次提交记录。reset
将当前分支的最新提交移动到指定提交记录。