Git分支管理

1.Git分支管理

在版本回退⾥,每次提交,Git都把它们串成⼀条时间线,这条时间线就可以理解为是⼀个分⽀。截⽌到⽬前,只有⼀条时间线,在Git⾥,这个分⽀叫主分⽀,即 master 分⽀。
再来理解⼀下HEAD,HEAD 严格来说不是指向提交,⽽是指向master,master才是指向提交的,所以,HEAD 指向的就是当前分⽀。

每次提交,master分⽀都会向前移动⼀步,这样,随着你不断提交,master分⽀的线也越来越⻓,⽽HEAD只要⼀直指向master分⽀即可指向当前分⽀。
通过查看当前的版本库,我们也能清晰的理出思路:

[wmh@hcss-ecs-1036 gitcode]$ cat .git/HEAD
ref: refs/heads/master
[wmh@hcss-ecs-1036 gitcode]$ cat .git/refs/heads/master
5476bdeb12510f7cd72ac4766db7988925ebd302

创建分支

Git ⽀持我们查看或创建其他分⽀,在这⾥我们来创建第⼀个⾃⼰的分⽀ dev ,对应的命令为:

[wmh@hcss-ecs-1036 gitcode]$ git branch #查看当前本地所有分⽀
* master
[wmh@hcss-ecs-1036 gitcode]$ git branch dev #新建分⽀ dev
[wmh@hcss-ecs-1036 gitcode]$ git branch
dev
* master
当我们创建新的分⽀后,Git 新建了⼀个指针叫 dev, * 表⽰当前 HEAD 指向的分⽀是 master 分
⽀。另外,可以通过⽬录结构发现,新的 dev 分⽀:
[wmh@hcss-ecs-1036 gitcode]$ ls .git/refs/heads/
dev master
[wmh@hcss-ecs-1036 gitcode]$ cat .git/refs/heads/*
5476bdeb12510f7cd72ac4766db7988925ebd302
5476bdeb12510f7cd72ac4766db7988925ebd302

发现⽬前 dev 和 master 指向同⼀个修改。并且也可以验证下 HEAD ⽬前是指向 master 的。

[wmh@hcss-ecs-1036 gitcode]$ cat .git/HEAD
ref: refs/heads/master

⼀张图总结:

切换分支
那如何切换到 dev 分⽀下进⾏开发呢?使⽤ git checkout 命令即可完成切换,⽰例如下:

[wmh@hcss-ecs-1036 gitcode]$ git checkout dev
Switched to branch 'dev'
[wmh@hcss-ecs-1036 gitcode]$ git branch
* dev
master
[wmh@hcss-ecs-1036 gitcode]$ cat .git/HEAD
ref: refs/heads/dev


我们发现 HEAD 已经指向了 dev,就表⽰我们已经成功的切换到了 dev 上!
接下来,在 dev 分⽀下修改 ReadMe ⽂件,新增⼀⾏内容,并进⾏⼀次提交操作:

[wmh@hcss-ecs-1036 gitcode]$ vim ReadMe
[wmh@hcss-ecs-1036 gitcode]$ cat ReadMe
hello bit
write aaa for new branch
[wmh@hcss-ecs-1036 gitcode]$ git add .
[wmh@hcss-ecs-1036 gitcode]$ git commit -m"modify ReadMe"
[dev 3740dce] modify ReadMe
1 file changed, 1 insertion(+)

现在,dev 分⽀的⼯作完成,我们就可以切换回 master 分⽀:

[wmh@hcss-ecs-1036 gitcode]$ git checkout master
Switched to branch 'master'
[wmh@hcss-ecs-1036 gitcode]$ cat ReadMe
hello bit

切换回 master 分⽀后,发现ReadMe⽂件中新增的内容不⻅了!!!赶紧再切回 dev 看看:
[wmh@hcss-ecs-1036 gitcode]$ git checkout dev
Switched to branch 'dev'
[wmh@hcss-ecs-1036 gitcode]$ cat ReadMe
hello bit
write aaa for new branch
在 dev 分⽀上,内容还在。为什么会出现这个现象呢?我们来看看 dev 分⽀和 master 分⽀指向,发现两者指向的提交是不⼀样的:
[wmh@hcss-ecs-1036 gitcode]$ cat .git/refs/heads/dev
bdaf528ffbb8e05aee34d37685408f0e315e31a4
[wmh@hcss-ecs-1036 gitcode]$ cat .git/refs/heads/master
5476bdeb12510f7cd72ac4766db7988925ebd302
看到这⾥就能明⽩了,因为我们是在dev分⽀上提交的,⽽master分⽀此刻的提交点并没有变,此时的状态如图如下所示:

当切换到 master 分⽀之时,HEAD 就指向了 master,当然看不到提交了!

合并分支
为了在 master 主分⽀上能看到新的提交,就需要将 dev 分⽀合并到 master 分⽀,⽰例如下:

[wmh@hcss-ecs-1036 gitcode]$ git branch
* dev
master
[wmh@hcss-ecs-1036 gitcode]$ git checkout master # 切换到 master 上进⾏合并
Switched to branch 'master'
[wmh@hcss-ecs-1036 gitcode]$ git merge dev # 合并 dev 分⽀
Updating 16623e1..3740dce
Fast-forward
ReadMe | 1 +
1 file changed, 1 insertion(+)
[wmh@hcss-ecs-1036 gitcode]$ cat ReadMe
hello bit
write aaa for new branch
git merge 命令⽤于合并指定分⽀到当前分⽀。合并后,master 就能看到 dev 分⽀提交的内容
了。此时的状态如图如下所⽰。

Fast-forward 代表"快进模式",也就是直接把master指向dev的当前提交,所以合并速度⾮常快。
当然,也不是每次合并都能 Fast-forward。
删除分支
合并完成后, dev 分⽀对于我们来说就没⽤了, 那么dev分⽀就可以被删除掉,注意如果当前正处于某分⽀下,就不能删除当前分⽀,如:
[wmh@hcss-ecs-1036 gitcode]$ git branch
* dev
master
[wmh@hcss-ecs-1036 gitcode]$ git branch -d dev
error : Cannot delete branch 'dev' checked out at '/home/hyb/gitcode'

⽽可以在其他分⽀下删除当前分⽀,如:
[wmh@hcss-ecs-1036 gitcode]$ git checkout master
Switched to branch 'master'
[wmh@hcss-ecs-1036 gitcode]$ git branch -d dev
Deleted branch dev (was bdaf528).
[wmh@hcss-ecs-1036 gitcode]$ git branch

* master

此时的状态如图如下所⽰:


因为创建、合并和删除分⽀⾮常快,所以Git⿎励你使⽤分⽀完成某个任务,合并后再删掉分⽀,这和直接在master分⽀上⼯作效果是⼀样的,但过程更安全.
合并冲突
可是,在实际分⽀合并的时候,并不是想合并就能合并成功的,有时候可能会遇到代码冲突的问题。为了演⽰这问题,创建⼀个新的分⽀ dev1 ,并切换⾄⽬标分⽀,我们可以使⽤ git checkout -
b dev1 ⼀步完成创建并切换的动作,⽰例如下:

[wmh@hcss-ecs-1036 gitcode]$ git checkout -b dev1
Switched to a new branch 'dev1'
[wmh@hcss-ecs-1036 gitcode]$ git branch
* dev1
master

在 dev1 分⽀下修改 ReadMe ⽂件,更改⽂件内容如下,并进⾏⼀次提交,如:
[wmh@hcss-ecs-1036 gitcode]$ cat ReadMe
hello bit
write bbb for new branch # 将 aaa 该为 bbb
[wmh@hcss-ecs-1036 gitcode]$ git add .
[wmh@hcss-ecs-1036 gitcode]$ git commit -m"modify ReadMe"
[dev1 0854245] modify ReadMe
1 file changed, 1 insertion(+), 1 deletion(-)

切换⾄ master 分⽀,观察 ReadMe ⽂件内容:

[wmh@hcss-ecs-1036 gitcode]$ git checkout master
Switched to branch 'master'
[wmh@hcss-ecs-1036 gitcode]$ cat ReadMe
hello bit
write aaa for new branch
我们发现,切回来之后,⽂件内容由变成了⽼的版本,这种现象很正常,我们现在也完全能理解。
此时在 master 分⽀上,我们对 ReadMe ⽂件再进⾏⼀次修改,并进⾏提交,如下:
[wmh@hcss-ecs-1036 gitcode]$ git branch
dev1
* master
[wmh@hcss-ecs-1036 gitcode]$ vim ReadMe
[wmh@hcss-ecs-1036 gitcode]$ cat ReadMe
hello bit
write ccc for new branch
[wmh@hcss-ecs-1036 gitcode]$ git add .
[wmh@hcss-ecs-1036 gitcode]$ git commit -m"modify ReadMe"
[master c10f6d0] modify ReadMe
1 file changed, 1 insertion(+), 1 deletion(-)

现在, master 分⽀和 dev1 分⽀各⾃都分别有新的提交,变成了这样:


这种情况下,Git 只能试图把各⾃的修改合并起来,但这种合并就可能会有冲突,如下所⽰:

[wmh@hcss-ecs-1036 gitcode]$ git merge dev1
Auto-merging ReadMe
CONFLICT (content): Merge conflict in ReadMe
Automatic merge failed; fix conflicts and then commit the result.
[wmh@hcss-ecs-1036 gitcode]$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: ReadMe
no changes added to commit (use "git add" and/or "git commit -a")
发现 ReadMe ⽂件有冲突后,可以直接查看⽂件内容,要说的是 Git 会⽤ <<<<<<<,=======,
>>>>>>> 来标记出不同分⽀的冲突内容,如下所⽰:
[wmh@hcss-ecs-1036 gitcode]$ cat ReadMe
hello bit
<<<<<<< HEAD
write ccc for new branch

write bbb for new branch
>>>>>>> dev1
此时我们必须要⼿动调整冲突代码,并需要再次提交修正后的结果!!(再次提交很重要,切勿忘
记)
[wmh@hcss-ecs-1036 gitcode]$ cat ReadMe
hello bit
write bbb for new branch
[wmh@hcss-ecs-1036 gitcode]$ git add .
[wmh@hcss-ecs-1036 gitcode]$ git commit -m"merge ReadMe"
[master 2976afc] merge ReadMe

到这⾥冲突就解决完成,此时的状态变成了:

分支管理策略
通常合并分⽀时,如果可能,Git 会采⽤ Fast forward 模式。还记得如果我们采⽤ Fast
forward 模式之后,形成的合并结果是什么呢?

在这种 Fast forward 模式下,删除分⽀后,查看分⽀历史时,会丢掉分⽀信息,看不出来最新提
交到底是 merge 进来的还是正常提交的。
但在合并冲突部分,我们也看到通过解决冲突问题,会再进⾏⼀次新的提交,得到的最终状态为:

那么这就不是 Fast forward 模式了,这样的好处是,从分⽀历史上就可以看出分⽀信息。例如我
们现在已经删除了在合并冲突部分创建的 dev1 分⽀,但依旧能看到 master 其实是由其他分⽀合并得到:

hyb@139-159-150-152:~/gitcode$ git log --graph --pretty=oneline --abbrev-commit
* 2976afc (HEAD -> master) merge ReadMe
|\
| * c594fd1 modify ReadMe
* | c10f6d0 modify ReadMe
|/
Git ⽀持我们强制禁⽤ Fast forward 模式,那么就会在 merge 时⽣成⼀个新的 commit ,这样,
从分⽀历史上就可以看出分⽀信息。
bug分支
假如我们现在正在 dev2 分⽀上进⾏开发,开发到⼀半,突然发现 master 分⽀上⾯有 bug,需要
解决。在Git中,每个 bug 都可以通过⼀个新的临时分⽀来修复,修复后,合并分⽀,然后将临时分⽀删除。
可现在 dev2 的代码在⼯作区中开发了⼀半,还⽆法提交,怎么办?
Git 提供了 git stash 命令,可以将当前的⼯作区信息进⾏储藏,被储藏的内容可以在将来某个时
间恢复出来。
[wmh@hcss-ecs-1036 gitcode]$ git stash
Saved working directory and index state WIP on dev2: 41b082f modify ReadMe
[wmh@hcss-ecs-1036 gitcode]$ git status
On branch dev2
nothing to commit, working tree clean
⽤ git status 查看⼯作区,就是⼲净的(除⾮有没有被 Git 管理的⽂件),因此可以放⼼地创建分
⽀来修复bug。
储藏 dev2 ⼯作区之后,由于我们要基于master分⽀修复 bug,所以需要切回 master 分⽀,再新
建临时分⽀来修复 bug,⽰例如下:
[wmh@hcss-ecs-1036 gitcode]$ git checkout master # 切回 master
Switched to branch 'master'
[wmh@hcss-ecs-1036 gitcode]$ git checkout -b fix_bug # 新建并切换到 fix_bug 分⽀
Switched to a new branch 'fix_bug'
[wmh@hcss-ecs-1036 gitcode]$ vim ReadMe
[wmh@hcss-ecs-1036 gitcode]$ cat ReadMe
hello bit
write bbb for new branch
a,b,c,d ,e # 修复 bug-- 忘记写 e
[wmh@hcss-ecs-1036 gitcode]$ git add ReadMe # 重新 add , commit
[wmh@hcss-ecs-1036 gitcode]$ git commit -m"fix bug"
[fix_bug 4bbc0c4] fix bug
1 file changed, 1 insertion(+), 1 deletion(-)

修复完成后,切换到 master 分⽀,并完成合并,最后删除 fix_bug 分⽀。

⾄此,bug 的修复⼯作已经做完了,我们还要继续回到 dev2 分⽀进⾏开发。切换回 dev2 分⽀
[wmh@hcss-ecs-1036 gitcode]$ git checkout dev2
Switched to branch 'dev2'
[wmh@hcss-ecs-1036 gitcode]$ git status
On branch dev2
nothing to commit, working tree clean

⼯作区是⼲净的,刚才的⼯作现场存到哪去了?⽤ git stash list 命令看看:
[wmh@hcss-ecs-1036 gitcode]$ git stash list
stash@{0}: WIP on dev2: 41b082f modify ReadMe
⼯作现场还在,Git 把 stash 内容存在某个地⽅了,但是需要恢复⼀下,如何恢复现场呢?我们可以使⽤ git stash pop 命令,恢复的同时会把 stash 也删了,⽰例如下:
[wmh@hcss-ecs-1036 gitcode]$ git stash pop
On branch dev2
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: ReadMe
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (4f873250b3503687b5efd26196776aee7e3724c2)

再次查看的时候,我们已经发现已经没有现场可以恢复了。

但我们注意到了,修复 bug 的内容,并没有在 dev2 上显⽰。此时的状态图为:


Master 分⽀⽬前最新的提交,是要领先于新建 dev2 时基于的 master 分⽀的提交的,所以我们
在 dev2 中当然看不⻅修复 bug 的相关代码。
我们的最终⽬的是要让 master 合并 dev2 分⽀的,那么正常情况下我们切回 master 分⽀直接合
并即可,但这样其实是有⼀定⻛险的。
是因为在合并分⽀时可能会有冲突,⽽代码冲突需要我们⼿动解决(在 master 上解决)。我们⽆法保证对于冲突问题可以正确地⼀次性解决掉,因为在实际的项⽬中,代码冲突不只⼀两⾏那么简单,有可能⼏⼗上百⾏,甚⾄更多,解决的过程中难免⼿误出错,导致错误的代码被合并到 master 上。 此时的状态为:


解决这个问题的⼀个好的建议就是:最好在⾃⼰的分⽀上合并下 master ,再让 master 去合并
dev ,这样做的⽬的是有冲突可以在本地分⽀解决并进⾏测试,⽽不影响 master 。此时的状态
为:

相关推荐
贩卖纯净水.2 小时前
白月光git
git·github
爱吃瓜的猹z6 小时前
git reset 几点疑问
git·源代码管理
悟空201613 小时前
001、Git开发流程规范
git
Li小李同学Li13 小时前
git学习【持续更新中。。。】
git·学习·elasticsearch
晨春计14 小时前
【git】
android·linux·git
念幽15 小时前
Git常用命令
git
神技圈子15 小时前
【git系列】git中的那些迷惑的术语以及概念详解
git
benben04416 小时前
Photoshop使用方法大全
git
ou.cs17 小时前
git 删除远程分支的几种写法
git
atlanteep17 小时前
Linux·权限与工具-git与gdb
linux·git