【Git版本控制 02】分支管理

目录

一、创建分支

二、切换分支

三、合并分支

四、删除分支

五、合并冲突

六、分支策略

七、bug分支


一、创建分支

bash 复制代码
# 当前仓库只有 master 一个主分支
# 可通过 git branch 是进行分支管理的命令,可通过不同参数对分支进行查看、创建、删除

(base) [root@localhost gitcode]# cat .git/HEAD
ref: refs/heads/master
(base) [root@localhost gitcode]# cat .git/refs/heads/master
84b615bfb313b40010c263cbadc67f24ce1ed1d3
(base) [root@localhost gitcode]# git branch
* master
(base) [root@localhost gitcode]# git branch dev
(base) [root@localhost gitcode]# git branch
  dev
* master
(base) [root@localhost gitcode]# ls .git/refs/heads/
dev  master
(base) [root@localhost gitcode]# cat .git/refs/heads/*
84b615bfb313b40010c263cbadc67f24ce1ed1d3
84b615bfb313b40010c263cbadc67f24ce1ed1d3
(base) [root@localhost gitcode]# 

# * 表示当前 HEAD 指向的分支是 master 分支
# git branch 只能查看本地分支,git branch -r 可查看远程分支

二、切换分支

bash 复制代码
(base) [root@localhost gitcode]# git checkout dev
切换到分支 'dev'
(base) [root@localhost gitcode]# cat .git/HEAD
ref: refs/heads/dev
(base) [root@localhost gitcode]# git branch
* dev
  master
(base) [root@localhost gitcode]# 
bash 复制代码
# 在新分支上修改文件内容

(base) [root@localhost gitcode]# vim file1
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
write sth. for new branch: dev
(base) [root@localhost gitcode]# git add .
(base) [root@localhost gitcode]# git commit -m "modify file1 for dev"
[dev 088ce6d] modify file1 for dev
 1 file changed, 1 insertion(+)
(base) [root@localhost gitcode]# git checkout master
切换到分支 'master'
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
(base) [root@localhost gitcode]# 


# 为什么 dev分支 和 master分支 上同一个文件的内容不一样呢?
# 我们可以看到 dev分支和 master分支 上两者指向的提交是不一样的

(base) [root@localhost gitcode]# cat .git/refs/heads/dev
088ce6d478daaadbd94870ceebd47bd05bf1b4e1
(base) [root@localhost gitcode]# cat .git/refs/heads/master
84b615bfb313b40010c263cbadc67f24ce1ed1d3
(base) [root@localhost gitcode]# 

三、合并分支

bash 复制代码
# 先切回到 master分支,再通过 git merge 合并 dev分支

(base) [root@localhost gitcode]# git checkout master
切换到分支 'master'
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
(base) [root@localhost gitcode]# git merge dev
更新 84b615b..088ce6d
Fast-forward
 file1 | 1 +
 1 file changed, 1 insertion(+)
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
write sth. for new branch: dev
(base) [root@localhost gitcode]# 

Fast-forward代表"快进模式",也就是直接把master指向dev的当前提交,所以合并速度非常快。

四、删除分支

合并完成后, dev分⽀ 对于我们来说就没⽤了,那么 dev分⽀ 就可以被删除掉,注意如果当前正处于某分⽀下,就不能删除当前分⽀。

bash 复制代码
(base) [root@localhost gitcode]# git branch
* dev
  master
(base) [root@localhost gitcode]# git branch -d dev
error: 无法删除您当前所在的分支 'dev'。
(base) [root@localhost gitcode]# git checkout master
切换到分支 'master'
(base) [root@localhost gitcode]# git branch -d dev
已删除分支 dev(曾为 088ce6d)。
(base) [root@localhost gitcode]# git branch
* master
(base) [root@localhost gitcode]# 

因为创建、合并和删除分⽀⾮常快,所以Git⿎励你使⽤分⽀完成某个任务,合并后再删掉分⽀,这和直接在master分⽀上⼯作效果是⼀样的,但过程更安全。

五、合并冲突

在实际分⽀合并的时候,并不是想合并就能合并成功的,有时候可能会遇到代码冲突的问题。

bash 复制代码
# git checkout -b 可以创建并跳转到新分支
# 分别在 dev1分支 和 master分支上对file1文件修改并提交

(base) [root@localhost gitcode]# git checkout -b dev1
切换到一个新分支 'dev1'
(base) [root@localhost gitcode]# git branch
* dev1
  master
(base) [root@localhost gitcode]# vim file1
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
write sth. for new branch: dev1
(base) [root@localhost gitcode]# git add .
(base) [root@localhost gitcode]# git commit -m "modify file1 for dev1"
[dev1 77f1455] modify file1 for dev1
 1 file changed, 1 insertion(+), 1 deletion(-)
(base) [root@localhost gitcode]# git checkout master
切换到分支 'master'
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
write sth. for new branch: dev
(base) [root@localhost gitcode]# vim file1
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
write sth. for new branch: master
(base) [root@localhost gitcode]# git add .
(base) [root@localhost gitcode]# git commit -m "modify file1 for master"
[master b7534ec] modify file1 for master
 1 file changed, 1 insertion(+), 1 deletion(-)
(base) [root@localhost gitcode]# 

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

bash 复制代码
(base) [root@localhost gitcode]# git branch
  dev1
* master
(base) [root@localhost gitcode]# git merge dev1
自动合并 file1
冲突(内容):合并冲突于 file1
自动合并失败,修正冲突然后提交修正的结果。
(base) [root@localhost gitcode]# git status
# 位于分支 master
# 您有尚未合并的路径。
#   (解决冲突并运行 "git commit")
#
# 未合并的路径:
#   (使用 "git add <file>..." 标记解决方案)
#
#       双方修改:     file1
#
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
<<<<<<< HEAD
write sth. for new branch: master
=======
write sth. for new branch: dev1
>>>>>>> dev1
(base) [root@localhost gitcode]# 

Git会⽤ <<<<<<<,=======,>>>>>>> 来标记出不同分⽀的冲突内容,此时我们必须要⼿动调整冲突代码,并需要再次提交修正后的结果!!

bash 复制代码
(base) [root@localhost gitcode]# vim file1
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
write sth. for new branch: master
write sth. for new branch: dev1
(base) [root@localhost gitcode]# git add .
(base) [root@localhost gitcode]# git commit -m "modify file1 for master and dev1"
[master 0dc19d0] modify file1 for master and dev1
(base) [root@localhost gitcode]# git status
# 位于分支 master
无文件要提交,干净的工作区
(base) [root@localhost gitcode]# 
bash 复制代码
# 用带参数的 git log 也可以看到分支合并情况

(base) [root@localhost gitcode]# git log --graph --pretty=oneline --abbrev-commit
*   0dc19d0 modify file1 for master and dev1
|\  
| * 77f1455 modify file1 for dev1
* | b7534ec modify file1 for master
|/  
* 088ce6d modify file1 for dev
* 84b615b delete file3
* 0f28717 delete file4
* c31b56a modigy: add vertion2
* 167def0 modify: add vertion1
* 7df1e32 modify: file1
* f2e9210 Add three files
* fc3a350 Add first file
(base) [root@localhost gitcode]# 
bash 复制代码
# 分支使用完最好删除掉

(base) [root@localhost gitcode]# git branch -d dev1
已删除分支 dev1(曾为 77f1455)。
(base) [root@localhost gitcode]# git branch
* master
(base) [root@localhost gitcode]# 

六、分支策略

通常合并分⽀时,如果可能,Git会采⽤ Fast forward 模式。

在这种 Fast forward 模式下,删除分⽀后,查看分⽀历史时,会丢掉分⽀信息,看不出来最新提交到底是 merge 进来的还是正常提交的。

但在合并冲突部分,我们也看到通过解决冲突问题,会再进⾏⼀次新的提交。

那么这就不是 Fast forward 模式了,这样的好处是,从分⽀历史上就可以看出分⽀信息。

Git ⽀持我们强制禁⽤ Fast forward 模式,那么就会在 merge 时⽣成⼀个新的 commit ,这样,从分⽀历史上就可以看出分⽀信息。

bash 复制代码
# 新建 dev2分支 并在新分支上修改 file1

(base) [root@localhost gitcode]# git checkout -b dev2
切换到一个新分支 'dev2'
(base) [root@localhost gitcode]# vim file1
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
write sth. for new branch: master
write sth. for new branch: dev1
write sth. for new branch: dev2
(base) [root@localhost gitcode]# git add .
(base) [root@localhost gitcode]# git commit -m "modify file1 for dev2"
[dev2 13c3c71] modify file1 for dev2
 1 file changed, 1 insertion(+)
(base) [root@localhost gitcode]#
bash 复制代码
# 使用 git -merge --no-ff 合并分支会提交一个新的 commit

(base) [root@localhost gitcode]# git checkout master
切换到分支 'master'
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
write sth. for new branch: master
write sth. for new branch: dev1
(base) [root@localhost gitcode]# git merge --no-ff -m "merge with no-ff: dev2" dev2
Merge made by the 'recursive' strategy.
 file1 | 1 +
 1 file changed, 1 insertion(+)
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
write sth. for new branch: master
write sth. for new branch: dev1
write sth. for new branch: dev2
(base) [root@localhost gitcode]# git log --graph --pretty=oneline --abbrev-commit
*   cb70524 merge with no-ff: dev2
|\  
| * 13c3c71 modify file1 for dev2
|/  
*   0dc19d0 modify file1 for master and dev1
|\  
| * 77f1455 modify file1 for dev1
* | b7534ec modify file1 for master
|/  
* 088ce6d modify file1 for dev
* 84b615b delete file3
* 0f28717 delete file4
* c31b56a modigy: add vertion2
* 167def0 modify: add vertion1
* 7df1e32 modify: file1
* f2e9210 Add three files
* fc3a350 Add first file
(base) [root@localhost gitcode]# 

可以看出,在 --no-ff 模式下,merge后的分支图为:

所以在合并分⽀时,加上 --no-ff 参数就可以⽤普通模式合并,合并后的历史有分⽀,能看出来曾经做过合并,⽽ fast forward 合并就看不出来曾经做过合并。

分支管理原则

  1. master分⽀应该是⾮常稳定的,也就是仅⽤来发布新版本,平时不能在上⾯⼲活;
  2. ⼲活都在dev分⽀上,也就是说,dev分⽀是不稳定的,到某个时候,⽐如1.0版本发布时,再把dev分⽀合并到master上,在master分⽀发布1.0版本;

七、bug分支

假如我们现在正在 dev2 分⽀上进⾏开发,开发到⼀半,突然发现 master 分⽀上⾯有bug,需要解决。在Git中,每个bug都可以通过⼀个新的临时分⽀来修复,修复后,合并分⽀,然后将临时分⽀删除。

可现在 dev2 的代码在⼯作区中开发了⼀半,还⽆法提交,怎么办?

bash 复制代码
(base) [root@localhost gitcode]# git checkout dev2
切换到分支 'dev2'
(base) [root@localhost gitcode]# vim file1
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
write sth. for new branch: master
write sth. for new branch: dev1
write sth. for new branch: dev2
this is a bug ...
(base) [root@localhost gitcode]# git status
# 位于分支 dev2
# 尚未暂存以备提交的变更:
#   (使用 "git add <file>..." 更新要提交的内容)
#   (使用 "git checkout -- <file>..." 丢弃工作区的改动)
#
#       修改:      file1
#
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
(base) [root@localhost gitcode]# 
bash 复制代码
# Git提供了 git stash 命令可以将当前工作区信息进行储藏
# 被储藏的内容可以在将来的某个时间恢复出来

(base) [root@localhost gitcode]# git stash
Saved working directory and index state WIP on dev2: 13c3c71 modify file1 for dev2
HEAD 现在位于 13c3c71 modify file1 for dev2
(base) [root@localhost gitcode]# git status
# 位于分支 dev2
无文件要提交,干净的工作区
(base) [root@localhost gitcode]# 
bash 复制代码
# 储藏 dev2 ⼯作区之后,由于我们要基于master分⽀修复bug,
# 所以需要切回 master 分⽀,再新建临时分⽀来修复bug

(base) [root@localhost gitcode]# git checkout master
切换到分支 'master'
(base) [root@localhost gitcode]# git checkout -b fix_bug
切换到一个新分支 'fix_bug'
(base) [root@localhost gitcode]# vim file1
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
write sth. for new branch: master
write sth. for new branch: dev1
write sth. for new branch: dev2
fix a bug here!
(base) [root@localhost gitcode]# git add .
(base) [root@localhost gitcode]# git commit -m "fix a bug"
[fix_bug 1ec9fbd] fix a bug
 1 file changed, 1 insertion(+)
(base) [root@localhost gitcode]#  
bash 复制代码
# 修复完成后,切换到 master 分⽀,并完成合并,最后删除 fix_bug 分⽀

(base) [root@localhost gitcode]# git checkout master
切换到分支 'master'
(base) [root@localhost gitcode]# git merge --no-ff -m "merge fix_bug branch" fix_bug
Merge made by the 'recursive' strategy.
 file1 | 1 +
 1 file changed, 1 insertion(+)
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
write sth. for new branch: master
write sth. for new branch: dev1
write sth. for new branch: dev2
fix a bug here!
(base) [root@localhost gitcode]# git branch -d fix_bug
已删除分支 fix_bug(曾为 1ec9fbd)。
(base) [root@localhost gitcode]#
bash 复制代码
# bug的修复⼯作已经做完了,我们还要继续回到 dev2 分⽀进⾏开发。
# ⼯作区是⼲净的,需要恢复现场
# git stash list 查看工作现场列表
# git stash pop  恢复工作现场

(base) [root@localhost gitcode]# git checkout dev2
切换到分支 'dev2'
(base) [root@localhost gitcode]# git status
# 位于分支 dev2
无文件要提交,干净的工作区
(base) [root@localhost gitcode]# git stash list
stash@{0}: WIP on dev2: 13c3c71 modify file1 for dev2
(base) [root@localhost gitcode]# git stash pop
# 位于分支 dev2
# 尚未暂存以备提交的变更:
#   (使用 "git add <file>..." 更新要提交的内容)
#   (使用 "git checkout -- <file>..." 丢弃工作区的改动)
#
#       修改:      file1
#
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
丢弃了 refs/stash@{0} (f9841933f9d2d3112f4262fc0e5c9f882fea7fd7)
(base) [root@localhost gitcode]# git stash list
(base) [root@localhost gitcode]#
bash 复制代码
# 恢复完代码之后我们便可以继续完成开发,开发完成后便可以进⾏提交
# 但是修复bug的内容并没有在dev2中显示

(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
write sth. for new branch: master
write sth. for new branch: dev1
write sth. for new branch: dev2
this is a bug ...
(base) [root@localhost gitcode]# git add .
(base) [root@localhost gitcode]# git commit -m "modify file1 for dev2"
[dev2 030cb5d] modify file1 for dev2
 1 file changed, 1 insertion(+), 1 deletion(-)
(base) [root@localhost gitcode]# 

Master 分⽀⽬前最新的提交,是要领先于新建 dev2 时基于的 master 分⽀的提交的,所以我们

在 dev2 中当然看不⻅修复bug的相关代码。

我们的最终⽬的是要让 master 合并 dev2 分⽀的,那么正常情况下我们切回 master 分⽀直接合

并即可,但这样其实是有⼀定⻛险的。

因为在合并分⽀时可能会有冲突,⽽代码冲突需要我们⼿动解决(在 master 上解决)。我们⽆法保证对于冲突问题可以正确地⼀次性解决掉,因为在实际的项⽬中,代码冲突不只⼀两⾏那么简单,有可能⼏⼗上百⾏,甚⾄更多,解决的过程中难免⼿误出错,导致错误的代码被合并到master 上。

解决这个问题的⼀个好的建议就是:最好在⾃⼰的分⽀上合并下 master ,再让 master 去合并

dev ,这样做的⽬的是有冲突可以在本地分⽀解决并进⾏测试,⽽不影响 master 。

bash 复制代码
# dev2 合并 master

(base) [root@localhost gitcode]# git branch
* dev2
  master
(base) [root@localhost gitcode]# git merge master
自动合并 file1
冲突(内容):合并冲突于 file1
自动合并失败,修正冲突然后提交修正的结果。
(base) [root@localhost gitcode]# 
bash 复制代码
# 发生冲突,将冲突解决并重新提交

(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
write sth. for new branch: master
write sth. for new branch: dev1
write sth. for new branch: dev2
<<<<<<< HEAD
this is a bug ...
=======
fix a bug here!
>>>>>>> master
(base) [root@localhost gitcode]# vim file1
(base) [root@localhost gitcode]# cat file1
hello git
hello world
add vertion1
add vertion2
write sth. for new branch: master
write sth. for new branch: dev1
write sth. for new branch: dev2
i am coding ... done!
(base) [root@localhost gitcode]# git add .
(base) [root@localhost gitcode]# git commit -m "merge master"
[dev2 9604340] merge master
(base) [root@localhost gitcode]# git status
# 位于分支 dev2
无文件要提交,干净的工作区
(base) [root@localhost gitcode]# 
bash 复制代码
# 切回master,合并dev2

(base) [root@localhost gitcode]# git checkout master
切换到分支 'master'
(base) [root@localhost gitcode]# git merge dev2
更新 1bcd87b..9604340
Fast-forward
 file1 | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
(base) [root@localhost gitcode]# git status
# 位于分支 master
无文件要提交,干净的工作区
(base) [root@localhost gitcode]# git branch -d dev2
已删除分支 dev2(曾为 9604340)。
(base) [root@localhost gitcode]# 
相关推荐
唔知小罗27 分钟前
git config是做什么的?
git
不是鱼6 小时前
新人程序猿必备的git技能(超实用基础版)
git·github
Exclusive_Cat9 小时前
Git的使用(基础语句)
git
江上清风山间明月9 小时前
git撤销、回退某个commit的修改
git·commit·版本·撤销·回退·特定
cui_win10 小时前
Redis高可用-主从复制
redis·git·github·主从复制·哨兵
Anlici13 小时前
大厂怎么用Git命令
git
谎言西西里13 小时前
Git入门指南:掌握基本概念与日常操作
git·github
程序员buddha14 小时前
git版本工具使用教程
git
tian-ming19 小时前
技术栈2:Git分布式版本控制工具
git
算你狠 - ZGX20 小时前
Git - 日志
git