# Git教程 - 4 分支
# 1 工作树
git 在每次提交代码的时候,都会创建一个节点,通过一个一个节点来记录代码的状态。
举个例子:
我们进行了4次提交,那么就会创建4个节点(下面的节点名称是我自己起的),每一提交就会在链式结构的后面追加节点。
每次的提交的信息都保存在节点中。
在实际的开发中,这些节点会构成一个树状结构,会存在分叉,可能会形成如下的结构,叫工作树。
所以我们之前提交完代码提示 working tree clean
。
只是默认情况下只会存在一个分支,就是 master 分支。
# 2 创建分支
为什么需要多个分支呢?
如果我们只有一个分支,那么现在线上发布的版本存在bug,但是当前的分支上,已经开发了很多的新功能,而且没有完成测试,那怎么办呢?
其实正常的情况,应该是 master 分支始终是一个随时可以发布的,是线上版本的分支,而我们还维护一个分支叫 develop 分支,在这个分支上开发最新的功能,如果此时有线上发布的版本有bug,那么我们就切换到 master 分支上进行修改,然后发布 master 分支上的代码。新功能开发测试完成,再将 develop分支合并到 master 分支。
所以我们可以创建多个分支来管理代码,每个分支之间是相互独立的(相当于平行宇宙),在一个分支上修改代码不会影响其他分支。
注意,这里简化了,后面再讲
Git flow
工作流。
我们可以使用如下指令进行分支的查看、创建、删除。
git branch # 查看有哪些分支
git branch 分支名 # 创建分支
git branch -d 分支名 # 删除分支
2
3
举个例子:
我们也可以在 VSCode 的终端执行指令,这样修改和提交代码更方便一些。
# 4 切换分支
在 VSCode 窗口最下面下的状态栏,显示的分支名称为 main 表示当前在 main 分支上。
main分支就是master分支,因为 master 这个词在过去被视为与奴隶制度有关联的词汇(主从master和 slave),跟种族歧视有关系,不够政治正确,于是改名了,简直日了狗,那个,那个,那个怎么说呢,简直吃饱了撑的。
所以在下面 master分支 就是 main 分支,main 分支就是 master 分支 。
重新再次创建 develop 分支。
我们可以使用 git branch 命令查看分支,当前在什么分支,就会在前面显示 *
号
现在使用如下指令切换分支:
git switch 分支名 # 切换分支
举个栗子:切换到 develop 分支:
可以看到切换到了 develop 分支上。
git switch
是 git 新版本才有的命令(从 2.23 开始),在旧版本中使用 git checkout
。
使用 git switch
的地方可以使用 git checkout
替代。
# 5 创建并切换分支
我们也可以使用如下指令,创建分支的同时切换到该分支上:
git switch -c 分支名 # 创建并切换分支
# 或使用checkout
git checkout -b develop
2
3
举个栗子:重新创建并切换到 develop 分支
# 6 分支的简单使用
比如我们的 master 分支已经发布到了生产环境,准备开发新功能,这个时候,我们开发新功能需要在 develop 分支上开发,不能在master分支,因为如果只有一个master分支,我们在上面添加了新代码,生产环境又突然发现bug,那就没办法了。
正常的操作是:master分支用于生产环境,开发新功能在develop分支,此时发现生产环境有bug,我们需要切换到master分支进行修改,修改完成,发布master分支即可。
但是其实我们切换到 master 分支修改bug的时候,还需要重新创建一个 bug 分支,在bug分支上修改bug,修改完成,再将bug分支的代码合并到 master 分支,然后再发布master分支。
为什么这样做呢?
其实这也是保持 master 分支随时是一个可以发布的状态,如果我们在master分支修改代码,代码修改到一半,此时的 master 分支就不是一个可以运行的状态了。而且如果我们在 master 分支上正在修改 bug1,修改到一半,发现了bug2 更严重,现在要先修改bug2,那么修改bug1的代码怎么办,难道删掉吗?而我们修改bug,先创建bug1分支,此时要修改bug2,我们重新切换到 master 分支,再创建 bug2 分支来修改bug2即可。
下面简单演示一下:
例如,我们现在项目下有一个 1.txt,经历了四次编辑,每次增加了一个bug
这是第一次写的bug
这是第二次写的bug
这是第三次写的bug
这是第四次写的bug
2
3
4
提交的记录如下:
此时的工作树是这样的:
这里的 master 和 HEAD 是什么呢?
master 就是指 master 分支,master 分支指向 C4,表示当前 master 分支上的最新提交是 C4 节点。
HEAD 表示当前看到的代码在哪里,HEAD 也指向 C4,表示看到的就是C4 时候的代码。如果我们将 HEAD 指向 C3,就可以看到 C3 时候的代码,也就是看到历时版本了,待会再讲。
然后,我们准备开发新功能,创建 develop 分支,并切换到 develop 分支:
git switch -c develop
此时的工作树会变成如下:
此时创建了 develop 分支,develop 分支也是指向 C4 节点的。
然后我们修改 1.txt,注意,现在我们是在 develop 分支修改。
修改 1.txt 为如下:
这是第一次写的bug
develop分支开发第一个新功能
这是第二次写的bug
这是第三次写的bug
这是第四次写的bug
2
3
4
5
然后暂存并提交,这次提交称它为 C5 节点。
使用 Git Graph 看到的提交记录如下:
此时的工作树会变成这样:
此时 develop 分支在 C5 节点,master 分支还在C4 节点,因为现在我们看到的代码是 C5 的,所以此时 HEAD 指向了 C5。
HEAD 就像是眼睛,看到哪里的代码就是指向哪里。
此时使用 git log
命令,也可以看到 (HEAD -> develop)
。
此时发现 master 分支有 bug 了,但是不能在master 分支修改,需要创建 bug 分支修改。
所以首先切换到 master 分支:
git switch master # 看你的主分支是main还是master
此时的工作树会变成这样:
因为现在切换到了 master 分支,master 分支在 C4,所以此时看到的是 C4 的代码,所以 HEAD 也指向了 C4;
此时发现在 develop 分支上添加的 1.txt 的内容不见了,因为添加的内容在 C5,内容变成了:
这是第一次写的bug
这是第二次写的bug
这是第三次写的bug
这是第四次写的bug
2
3
4
然后在 master 分支创建 bug1 分支,并切换到 bug1 分支进行修改bug。
git switch -c bug1
现在是有三个分支了:main、develop、bug1
修改 1.txt,此时是在 bug1 分支修改。修改内容为如下:
修改第一个bug
这是第二次写的bug
这是第三次写的bug
这是第四次写的bug
2
3
4
然后暂存并提交,这次提交称它为 C6 节点。
此时的提交记录如下:
此时的工作树如下:
因为现在看到的是 C6 状态的代码,所以 HEAD 指向 C6。
然后发现bug1没有修改好,需要再次修改,然后又继续在bug1分支修改并暂存提交。
1.txt 修改为如下:
修改第一个bug
再次修改第一个bug
这是第二次写的bug
这是第三次写的bug
这是第四次写的bug
2
3
4
5
此时的提交记录如下:
此时的工作树如下:
我们此时在bug1分支上提交了两次代码。
# 7 合并分支
现在代码修改完成了,怎么发布修改的代码呢?
因为我们是在主分支(master)上发布代码,所以需要将bug1分支上修改的内容合并到 master 分支。
所以现在要合并分支。
将 bug1 分支合并到 master 分支,需要先切换到 master 分支。
git switch main # main 就是 master,看你本地的主分支的名称
此时的 master 分支的内容变成了 C4,1.txt 内容为:
这是第一次写的bug
这是第二次写的bug
这是第三次写的bug
这是第四次写的bug
2
3
4
然后将 bug1 分支合并 到 main 分支,使用如下指令:
git merge bug1
可以看到执行结果显示 Fast-forward
,表示快速合并。
此时成功的 bug1分支修改的内容合并到 master 分支了, 1.txt 内容变为:
修改第一个bug
再次修改第一个bug
这是第二次写的bug
这是第三次写的bug
这是第四次写的bug
2
3
4
5
此时的工作树如下:
此时 master 、 bug1 、HEAD 都指向了 C7,看到的就是 C7 的代码。
什么是 Fast-forward
快速合并呢?
就是master分支的节点都在bug1分支节点的前面,合并的时候,master分支的指针沿着节点从C4移动到C7即可。
快速合并后,代码是已经 commit 了,合并后不用 commit。
合并完成,bug1 分支没用了,可以删除bug1 分支了。
git branch -d bug1
此时的工作树如下:
通过 Git Graph 也能看到树的结构。
# 8 处理冲突
好了,我们现在再次切换到 develop 分支,然后再次修改 develop 分支,修改完成,暂存提交 1.txt。
develop 分支的 1.txt 内容如下:
这是第一次写的bug
develop分支开发第一个新功能
这是第二次写的bug
develop分支开发第二个新功能
这是第三次写的bug
这是第四次写的bug
2
3
4
5
6
此时的提交记录如下:
Git Graph 显示的时候,哪个分支是最新的提交,该分支是直线显示。
我自己重新画一下,工作树结构如下:
现在 develop 分支开发完成了,要将代码合并到 master 分支上。
和刚才的操作一样,要先切换到 master 分支,然后将 develop 分支合并到 master分支。
git switch main
git merge develop
2
可以看到,出问题了,没有快速合并,因为 C7 和 C8 不能通过移动指针就可以到达了。
日志显示 1.txt
自动合并失败,需要处理冲突才能提交。这是因为 1.txt, master 分支在 C4 的基础上进行修改,develop 也是在 C4 的基础上进行修改,现在要合并,就出现冲突了。
合并前,master 分支上的 1.txt 内容是:
修改第一个bug
再次修改第一个bug
这是第二次写的bug
这是第三次写的bug
这是第四次写的bug
2
3
4
5
develop 分支上的 1.txt 内容是:
这是第一次写的bug
develop分支开发第一个新功能
这是第二次写的bug
develop分支开发第二个新功能
这是第三次写的bug
这是第四次写的bug
2
3
4
5
6
上面刚才执行了 git merge develop
,此时打开 1.txt,变为了:
<<<<<<< HEAD
修改第一个bug
再次修改第一个bug
=======
这是第一次写的bug
develop分支开发第一个新功能
>>>>>>> develop
这是第二次写的bug
develop分支开发第二个新功能
这是第三次写的bug
这是第四次写的bug
2
3
4
5
6
7
8
9
10
11
这是什么鬼?
莫慌!这里的:
<<<<<<< HEAD
=======
2
这中间的内容表示的是 master 分支的修改,因为刚才是在 master 分支,HEAD 和 master 指向的都是 C7 节点。
而
=======
>>>>>>> develop
2
这中间的内容表示的是 develop 分支的修改。
就是上面这两块区域的代码发生冲突。
现在需要手动修改 1.txt,可以随意修改,修改为自己想要的结果就好了。例如我修改完成的 1.txt 内容如下:
修改第一个bug
再次修改第一个bug
develop分支开发第一个新功能
这是第二次写的bug
develop分支开发第二个新功能
这是第三次写的bug
这是第四次写的bug
2
3
4
5
6
7
合并冲突完成,就可以将文件加入暂存,提交到仓库即可。
如果有多个文件冲突,就需要处理多个文件的冲突,冲突都处理完成,再提交。
上面合并的时候,是自动合并失败,有时候虽然不是快速合并,但是自动合并成功了,也就是虽然是多个分支修改了代码,但是修改代码的地方不在一个文件或不在一个文件的地方,自动合并是可能成功的,那么就不需要处理冲突了,直接提交就可以。
此时的工作树变为:
master 、develop 分支和 HEAD 都指向了 C9 。
使用 VSCode,也可以使用可视化的操作进行暂存和提交,提交的时候,甚至帮你写好了合并的日志(当然可以随便改)。
← 03-VSCode中操作git 05-变基 →