【Git 小妙招】走进 Git 的分支管理(万字图文讲解)

2023-12-13 12:39:42


前言

本文开始介绍 Git 的杀手级功能之?:分?。本文涉及分?创建,切换,合并,删除的整个?命周期,灵活进?各种场景下的分?管理,学习常见分?管理策略。

分?在实际中有什么?呢?假设你准备开发?个新功能,但是需要两周才能完成,第?周你写了50%的代码,如果?刻提交,由于代码还没写完,不完整的代码库会导致别?不能?活了。如果等代码全部写完再?次提交,?存在丢失每天进度的巨??险。

现在有了分?,就不?怕了。你创建了?个属于你??的分?,别?看不到,还继续在原来的分?上正常?作,?你在??的分?上?活,想提交就提交,直到开发完毕后,再?次性合并到原来的分?上,这样,既安全,?不影响别??作。

并且 Git ?论创建、切换和删除分?,Git 在1秒钟之内就能完成!?论你的版本库是1个?件还是1万个?件。

关注收藏, 开始学习吧🧐


1. 理解分支

分?就像是科幻电影里面的平行宇宙,当你正在电脑前努?学习 C++ 的时候,另?个你正在另?个平?宇宙?努?学习 JAVA。

如果两个平?宇宙互不?扰,那对现在的你也没啥影响。不过,在某个时间点,两个平?宇宙合并了,结果,你既学会了 C++ ?学会了 JAVA!

在这里插入图片描述
在版本回退?,你已经知道,每次提交,Git 都把它们串成?条时间线,这条时间线就可以理解为是?个分?。截?到?前,只有?条时间线,在 Git ?,这个分?叫主分?,即 master 分?。

再来理解?下 HEAD,HEAD 严格来说不是指向提交,?是指向 master,master 才是指向提交的,所以,HEAD 指向的就是当前分?。

在这里插入图片描述
每次提交,master 分?都会向前移动?步,这样,随着你不断提交,master 分?的线也越来越?,? HEAD 只要?直指向 master 分?即可指向当前分?。

通过查看当前的版本库,我们也能清晰的理出思路:

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat .git/HEAD
ref: refs/heads/master
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat .git/refs/heads/master
3c163abc60fe42216426b883671725e1d4c8c8b3

在这里插入图片描述

2. 创建分支

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

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git branch
* master
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git branch dev
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git branch
  dev
* master

在这里插入图片描述
当我们创建新的分?后,Git 新建了?个指针叫 dev,* 表?当前 HEAD 指向的分?是 master 分?。另外,可以通过?录结构发现,新的 dev 分?:

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# ls .git/refs/heads/
dev  master
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat .git/refs/heads/*
3c163abc60fe42216426b883671725e1d4c8c8b3
3c163abc60fe42216426b883671725e1d4c8c8b3

在这里插入图片描述

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

在这里插入图片描述

?张图总结:

在这里插入图片描述

3. 切换分支

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

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git checkout dev
Switched to branch 'dev'
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git branch
* dev
  master
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat .git/HEAD
ref: refs/heads/dev

在这里插入图片描述
在这里插入图片描述
我们发现 HEAD 已经指向了 dev,就表?我们已经成功的切换到了 dev 上!

接下来,在 dev 分?下修改 ReadMe ?件,新增??内容,并进??次提交操作:

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# vim ReadMe
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git add .
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git commit -m "modify ReadMe"
[dev a3aa828] modify ReadMe
 1 file changed, 1 insertion(+)
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat ReadMe
hello git
hello git
hello world
hello version1
hello version2
hello version3
write aaa for new branch

在这里插入图片描述

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

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git checkout master
Switched to branch 'master'
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat ReadMe
hello git
hello git
hello world
hello version1
hello version2
hello version3

切换回 master 分?后,发现ReadMe?件中新增的内容不?了!!!赶紧再切回 dev 看看:

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git checkout dev
Switched to branch 'dev'
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat ReadMe
hello git
hello git
hello world
hello version1
hello version2
hello version3
write aaa for new branch

可以看出,在 dev 分?上,内容还在。为什么会出现这个现象呢?我们来看看 dev 分?和 master 分?指向,发现两者指向的提交是不?样的:

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat .git/refs/heads/dev 
a3aa828d6180a7ac269314f29eb5650a70b0c28c
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat .git/refs/heads/master 
3c163abc60fe42216426b883671725e1d4c8c8b3

看到这?就能明?了,因为我们是在 dev 分?上提交的,? master 分?此刻的提交点并没有变,此时的状态如图如下所?:

在这里插入图片描述

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

4. 合并分支

为了在 master 主分?上能看到新的提交,就需要将 dev 分?合并到 master 分?,使用 git merge 操作,?例如下:

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git branch
* dev
  master

# 切换到 master 上进行
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git checkout master 
Switched to branch 'master'

# 合并 dev 分支
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git merge dev
Updating 3c163ab..a3aa828
Fast-forward
 ReadMe | 1 +
 1 file changed, 1 insertion(+)
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat ReadMe
hello git
hello git
hello world
hello version1
hello version2
hello version3
write aaa for new branch

在这里插入图片描述
git merge 命令?于合并指定分?到当前分?。合并后,master 就能看到 dev 分?提交的内容了。此时的状态如图如下所?:

在这里插入图片描述

在这里插入图片描述

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

当然,也不是每次合并都能 Fast-forward,我们后?会讲其他?式的合并。

5. 删除分支

合并完成后, dev 分?对于我们来说就没?了, 那么 dev 分?就可以被删除掉,使用 git branch -d 命令,注意如果当前正处于某分?下,就不能删除当前分?,如:

在这里插入图片描述

?可以在其他分?下删除当前分?,如:

在这里插入图片描述

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

在这里插入图片描述

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

6. 合并冲突

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

为了演?这问题,创建?个新的分? dev1 ,并切换??标分?,我们可以使? git checkout -b dev1 ?步完成创建并切换的动作,?例如下:

在这里插入图片描述

dev1 分?下修改 ReadMe ?件,更改?件内容如下,并进??次提交,如:

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# vim ReadMe
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat ReadMe
hello git
hello git
hello world
hello version1
hello version2
hello version3
write bbb for new branch            # 将 aaa 改为 bbb
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git add .
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git commit -m "modify ReadMe"
[dev1 4d019b2] modify ReadMe
 1 file changed, 1 insertion(+), 1 deletion(-)

在这里插入图片描述

切换? master 分?,观察 ReadMe ?件内容:

在这里插入图片描述

我们发现,切回来之后,?件内容由变成了?的版本,这种现象很正常,我们现在也完全能理解。

此时在 master 分?上,我们对 ReadMe ?件再进??次修改,并进?提交,如下:

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git branch
  dev1
* master
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# vim ReadMe
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat ReadMe
hello git
hello git
hello world
hello version1
hello version2
hello version3
write ccc for new branch    # 将 bbb 修改为 ccc
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git add .
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git commit -m "modify ReadMe"
[master f7a9673] modify ReadMe
 1 file changed, 1 insertion(+), 1 deletion(-)

在这里插入图片描述
现在, master 分?和 dev1 分?各?都分别有新的提交,变成了这样:

在这里插入图片描述

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

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git merge dev1
Auto-merging ReadMe
CONFLICT (content): Merge conflict in ReadMe
Automatic merge failed; fix conflicts and then commit the result.
root@iZ0jlic9afdpgvpfnm8g32Z:~/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 会? <<<<<<<,=======,>>>>>>> 来标记出不同分?的冲突内容,如下所?:

在这里插入图片描述

此时我们必须要?动调整冲突代码,并需要再次提交修正后的结果!!(再次提交很重要,切勿忘记)

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# vim ReadMe
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat ReadMe
hello git
hello git
hello world
hello version1
hello version2
hello version3
write bbb for new branch
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git add .
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git commit -m "merge ReadMe"
[master 14d93a6] merge ReadMe

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

在这里插入图片描述

?带参数的 git log 也可以看到分?的合并情况,具体?家可以??搜索 git log 的?法:

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git log --graph --pretty=oneline --abbrev-commit
*   14d93a6 (HEAD -> master) merge ReadMe
|\  
| * 4d019b2 (dev1) modify ReadMe
* | f7a9673 modify ReadMe
|/  
* a3aa828 modify ReadMe
* 3c163ab deleted file5
* cda844e add version3
* 494c4f1 add version2
* 637f0c6 add version1
* 7c99a33 add modify ReadMe file
* 7e71984 add file5
* 4272545 add file
* 1659312 add 3 files
* aee9eed commit my first file

在这里插入图片描述

最后,不要忘记 dev1 分?使?完毕后就可以删除了:

在这里插入图片描述

7. 分支管理策略

通常合并分?时,如果可能,Git 会采? Fast forward 模式。还记得如果我们采? Fast forward 模式之后,形成的合并结果是什么呢?回顾?下:

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

但在合并冲突部分,我们也看到通过解决冲突问题,会再进??次新的提交,得到的最终状态为:

在这里插入图片描述

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

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git log --graph --pretty=oneline --abbrev-commit
*   14d93a6 (HEAD -> master) merge ReadMe
|\  
| * 4d019b2 (dev1) modify ReadMe
* | f7a9673 modify ReadMe
|/  
...

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

下?我们实战?下 --no-ff ?式的 git merge 。?先,创建新的分? dev2 ,并切换?新的分?:

在这里插入图片描述

修改 ReadMe ?件,并提交?个新的 commit :

在这里插入图片描述

切回 master 分?,开始合并:

在这里插入图片描述

请注意 --no-ff 参数,表?禁? Fast forward 模式。禁? Fast forward 模式后合并会创建?个新的 commit ,所以加上 -m 参数,把描述写进去。

合并后,查看分?历史:

在这里插入图片描述
可以看到,不使? Fast forward 模式,merge 后就像这样:

在这里插入图片描述

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

7.1 一个简单的分支策略(仅参考)

在实际开发中,我们应该按照?个基本原则进?分?管理:

?先,master 分?应该是?常稳定的,也就是仅?来发布新版本,平时不能在上??活;

那在哪?活呢??活都在 dev 分?上,也就是说,dev 分?是不稳定的,到某个时候,?如1.0版本发布时,再把 dev 分?合并到master上,在 master 分?发布1.0版本;

你和你的?伙伴们每个?都在 dev 分?上?活,每个?都有??的分?,时不时地往 dev 分?上合并就可以了。

所以,团队合作的分?看起来就像这样:

在这里插入图片描述

8. bug 分支

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

可现在 dev2 的代码在?作区中开发了?半,还?法提交,怎么办?例如:

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git branch
  dev2
* master
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git checkout dev2
Switched to branch 'dev2'
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# vim ReadMe
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat ReadMe
hello git
hello git
hello world
hello version1
hello version2
hello version
write bbb for new branch
a,b,c,d
i am coding...
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git status
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")

在这里插入图片描述

Git 提供了 git stash 命令,可以将当前的?作区信息进?储藏,被储藏的内容可以在将来某个时间恢复出来。

在这里插入图片描述
再? git status 查看?作区,就是?净的(除?有没有被 Git 管理的?件),因此可以放?地创建分?来修复 bug。

储藏 dev2 ?作区之后,由于我们要基于 master 分?修复 bug,所以需要切回 master 分?,再新建临时分?来修复 bug,?例如下:

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git checkout master
Switched to branch 'master'
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git checkout -b fix_bug
Switched to a new branch 'fix_bug'
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# vim ReadMe
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat ReadMe
hello git
hello git
hello world
hello version1
hello version2
hello version
write bbb for new branch
a,b,c,d,e
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git add ReadMe
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git commit -m "fix bug"
[fix_bug 3c8ad5a] fix bug
 1 file changed, 1 insertion(+), 1 deletion(-)

在这里插入图片描述

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

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git checkout master
Switched to branch 'master'
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git merge --no-ff -m "merge fix_bug branch" fix_bug
Merge made by the 'ort' strategy.
 ReadMe | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat ReadMe
hello git
hello git
hello world
hello version1
hello version2
hello version
write bbb for new branch
a,b,c,d,e
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git branch -d fix_bug
Deleted branch fix_bug (was 3c8ad5a).

?此,bug 的修复?作已经做完了,我们还要继续回到 dev2 分?进?开发。切换回 dev2 分?:

在这里插入图片描述

看到?作区是?净的,刚才的?作现场存到哪去了?? git stash list 命令看看:

在这里插入图片描述

?作现场还在,Git 把 stash 内容存在某个地?了,但是需要恢复?下,如何恢复现场呢?我们可以使? git stash pop 命令,恢复的同时会把 stash 也删了,?例如下:

在这里插入图片描述

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

在这里插入图片描述
另外,恢复现场也可以采? git stash apply 恢复,但是恢复后,stash内容并不删除,你需要? git stash drop 来删除;

你也可以进行多次 stash,恢复的时候,先? git stash list 查看,然后恢复指定的 stash,?命令 git stash apply stash@{0} , 这部分请读者??查看使?。

恢复完代码之后我们便可以继续完成开发,开发完成后便可以进?提交,例如:

root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# vim ReadMe
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# cat ReadMe
hello git
hello git
hello world
hello version1
hello version2
hello version
write bbb for new branch
a,b,c,d
i am coding...Done!
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git add .
root@iZ0jlic9afdpgvpfnm8g32Z:~/gitcode# git commit -m "modify ReadMe"
[dev2 6ed3cb6] modify ReadMe
 1 file changed, 1 insertion(+)

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

在这里插入图片描述
master 分??前最新的提交,是要领先于新建 dev2 时基于的 master 分?的提交的,所以我们在 dev2 中当然看不?修复 bug 的相关代码。

我们的最终?的是要让 master 合并 dev2 分?的,那么正常情况下我们切回 master 分?直接合并即可,但这样其实是有?定?险的。

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

此时的状态为:

在这里插入图片描述

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

在这里插入图片描述
在这里插入图片描述

对应的实操演?如下,要说明的是,以下演?的 merge 操作,没有使? --no-ff ,但上述的图?是禁? Fast forward 了模式后得出的,主要是为了?便解释问题。

1. dev 合并 master

在这里插入图片描述

2. 发生冲突

在这里插入图片描述

3. 解决冲突并重新提交

在这里插入图片描述

4. 切回 master

在这里插入图片描述

5. master 合并 dev2 (无需解决冲突)

在这里插入图片描述

6. 删除 dev2 分支

在这里插入图片描述

9. 删除临时分支

软件开发中,总有?穷?尽的新的功能要不断添加进来。

添加?个新功能时,你肯定不希望因为?些实验性质的代码,把主分?搞乱了,所以,每添加?个新功能,最好新建?个分?,我们可以将其称之为 feature 分?,在上?开发,完成后,合并,最后,删除该 feature 分?。

可是,如果我们今天正在某个 feature 分?上开发了?半,被产品经理突然叫停,说是要停?新功能的开发。虽然??了,但是这个 feature 分?还是必须就地销毁,留着??了。这时使?传统的 git branch -d 命令删除分?的?法是不?的。演?如下:

1. 新增并切换到 dev3 分支

在这里插入图片描述

2. 开始开发新功能并提交

在这里插入图片描述

3. 此时新功能叫停

4. 切回 master 准备删除 dev3

在这里插入图片描述

5. 常规删除 dev3 分支时失败

在这里插入图片描述

直接使?传统的删除分?的?法不?,按照提?,有了如下?式:

在这里插入图片描述

删除成功!


总结

? 本文介绍了 Git 的一个杀手级功能 — 分?。涉及到分?创建,切换,合并,删除的整个?命周期,灵活进?各种场景下的分?管理,学习常见分?管理策略,读者可收藏后进行反复阅读,建议跟着文章一起实践操作一下。
? 想了解更多知识, 请持续关注博主, 本人会不断更新学习记录, 跟随我一起不断学习 -> 跳转Git专栏.
? 感谢你们的耐心阅读, 博主本人也是一名学生, 也还有需要很多学习的东西. 写这篇文章是以本人所学内容为基础, 日后也会不断更新自己的学习记录, 我们一起努力进步, 变得优秀, 小小菜鸟, 也能有大大梦想, 关注我, 一起学习.

再次感谢你们的阅读, 你们的鼓励是我创作的最大动力!!!!!

文章来源:https://blog.csdn.net/qq_60366454/article/details/134949599
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。