天天看点

Git轻松入门2:分支篇

Git中的“分支(branch)”就如同游戏中的剧情路线,用户可以为项目建立不同的分支,使得项目能在不同的分支里独立进行,并且互不干预。本讲介绍了一些和分支相关的命令以及Git会采取的3种合并策略:Fast-forward(直接移动指针),recursive strategy(采取三方合并)以及merge conflict(手动修改存在冲突的文件)。

什么是分支

Git轻松入门2:分支篇

在玩剧情类游戏时,不同的选择会触发不同的剧情路线,每条剧情路线都会独立发展,最终走向不同的结局。

Git中所谓的“分支(branch)”就如同游戏中的剧情路线,用户可以为项目建立不同的分支,使得项目能在不同的分支里独立进行,并且互不干预。

当用户初始化一个仓库时,Git会自动为其建立一条主分支,默认称其为master。若用户没有创建其他分支,那么项目发展的各个版本就默认存储在这条

master

分支上。

分支指令介绍

分支的新建和切换

假设你正在项目上工作,并且在

master

分支上已经有了如下的提交。

Git轻松入门2:分支篇

对应的图即为如下:

Git轻松入门2:分支篇

master

指针指向该分支上最新的提交;

HEAD

指针指向的是当前所在分支。

此时你发现了项目中有一个代号为#11的bug需要你解决。你决定专门新建一个分支,在那条分支上把该问题解决。于是你敲入了新建分支的指令。

Git轻松入门2:分支篇

上面两行命令可以仅用一条命令替代:

$ git branch -b bug#11

当我们在创建新的分支时,实际上是创建一个新的指针。它会指向

master

此时指向的提交。当我们切换到分支

bug#11

时,

HEAD

指针就会指向

bug#11

,如下图所示。

Git轻松入门2:分支篇

此外,我们可以用如下命令查看了目前仓库中存在的分支。

Git轻松入门2:分支篇

可以看到目前共存在2个分支,其中带*号的是目前所在分支:

master

分支的作用

于是你开始在

bug#11

这条分支上工作,并作出了如下的提交(commit)。

Git轻松入门2:分支篇

于是

bug#11

指针往前移动了一步,而

master

指针还是留在原地。

Git轻松入门2:分支篇

这时,当你用

$ git checkout master

命令切换回

master

分支时,你发现刚才在

bug#11

分支上新建的

log.txt

文件不见了,当前的工作目录和你开始在

bug#11

分支工作前一模一样。

这就是分支的好处,它将工作切分开来,让工作多线独立发展。

合并分支

我们将介绍在合并分支时会遇到的3种情况。

Fast-Forward

此时,你已经把

#bug11

修复完毕,你决定把这项修复合并到主线

master

中。于是,你使用了

$ git merge

命令来实现这个目的。

Git轻松入门2:分支篇

在合并的时候,你注意到了“快进(Fast-forward)”这个词。当你试图合并两个分支时, 如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候, 只会简单的将指针向前推进,因为这种情况下的合并操作没有需要解决的分歧——这就叫做 “快进(fast-forward)”,如图所示。

Git轻松入门2:分支篇

此时合并完成,所以你也不再需要

bug#11

分支了。你可以使用带

-d

选项的

$ git branch

命令来删除分支:

Git轻松入门2:分支篇

'recursive' strategy

此时,你又发现了项目中有一个代号为

bug#31

的漏洞需要修复,于是你先用

$ git branch bug#31

命令新建了一个分支。

现在的你还在

master

这条分支上工作:你将

Scheduling.txt

的文件内容修改为

Project Scheduling - 85% Done.

, 然后commit这次的修改。

此时,对应的图为如下:

Git轻松入门2:分支篇

现在的你感到心满意足,决心切换到

bug#31

分支上开始修复

bug#31

。于是你先用

$ git checkout bug#31

命令切换到了该分支。

接着你辛辛苦苦了一整天,总算把

bug#31

修复完了。于是你修改了

log.txt

文件里的内容,加上了一行

Fixed bug#31.

,并commit这次的修改,此时的图对应如下:

Git轻松入门2:分支篇

现在,你决定把对

bug#31

的修复应用到

master

分支中来,于是你切换回

master

分支,然后再次调用了

$ git merge

命令:

Git轻松入门2:分支篇

你发现这次提示的和之前在合并

bug#11

分支时提示的不太一样。因为此时,你想合并的

bug#31

指向的最新提交

C4

并不是

master

C3

的直接后继(换句话说,

C3

不能顺着一条路走到

C4

)。所以Git没法再那么通过简单的移动指针来完成合并了。

Git会找到

C3

C4

的共同祖先

C2

,然后做一个三方合并。

那么什么是三方合并呢?

例子1:A是B和C的共同祖先。B相对A的改动是删掉了3,C相对A的改动是增加了1。那么B和C合并的结果就是123。

Git轻松入门2:分支篇

例子2:A是B和C的共同祖先。B相对A的改动是删掉了1,C相对A的改动是增加了3。那么B和C合并的结果就是23。

Git轻松入门2:分支篇

所以简单来说,三方合并就是把B方和C方相对于共同祖先A方的改动分别应用到合并结果上。

刚才,

C3

相对于

C2

的改动是修改了

Scheduling.txt

文件的内容,而

C4

C2

log.txt

文件里的内容,将这两项改动都应用到合并结果中,就得到了一个既修改了

Scheduling.txt

又修改了

log.txt

C5

Git轻松入门2:分支篇

遇到冲突时的合并

有时候合并操作不会如此顺利。 如果你在两个不同的分支中,对同一个文件进行了不同的修改,Git 就没法干净的合并它们。

例如:你在

bug#31

分支中在

README.md

文件中添加了一行

I like Git.

;在

master

分支中对

README.md

文件添加了一行

Git is good.

,然后再执行

$ git merge

Git轻松入门2:分支篇

在两个分支中,你都对

README.md

文件进行了修改,因此就会产生合并冲突。

打开

README.md

文件会看到如下内容,其中

<<<<<<< HEAD

=======

之间的内容是

HEAD

指向分支里的内容,即

master

=======

>>>>>>> bug#31

之间的是

bug#31

分支里的内容。

Git轻松入门2:分支篇

你手动修改了这个文件,修改后的内容如下。

Git轻松入门2:分支篇

在Git轻松入门1:本地仓库篇,我们提到过,文件修改后,需要执行

$ git add

$ git commit

两个步骤。所以现在,你同样需要执行这两个步骤,而当你敲完命令,你会发现提示合并成功。

Git轻松入门2:分支篇

总结

总结一下今天出现过的几个Git命令:

# 列出该仓库存在的分支,当前分支的前面会带有*号
$ git branch

# 创建分支
$ git branch [branch-name] 

# 切换分支
$ git checkout [branch-name]

# 创建分支并立刻切换到该分支下
$ git checkout -b [branch-name]

# 删除分支
$ git branch -d [branch-name]

# 合并分支
$ git merge [branch-name]
           

分支的作用在于将工作切分开来,使得工作可以多线独立发展。以上是本讲关于分支命令的概括。此外,本讲还介绍了Git采取的3种合并策略:Fast-forward(直接移动指针),recursive strategy(采取三方合并)以及merge conflict(手动修改存在冲突的文件)。

参考

  1. http://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging
  2. https://www.zhihu.com/question/30200228
  3. https://www.liaoxuefeng.com/wiki/896043488029600/900003767775424
  4. https://www.runoob.com/git/git-branch.html

有问题欢迎大家在评论区留言,转载请注明出处。