当前位置: 首页 > article >正文

【Git】二、分支管理详解

文章目录

  • Ⅰ. 理解分支
  • Ⅱ. 理解HEAD指针
  • Ⅲ. 创建、切换、合并、删除分支
    • 1、创建分支 -- `git branch [name]`
    • 2、切换分支 -- `git checkout`
    • 3、合并分支 -- `git merge`
    • 4、删除分支 -- `git branch -d <branch-name>`
  • Ⅳ. 合并冲突
  • Ⅴ. 分支管理策略
    • 一、分支合并模式
    • 二、分支策略
  • Ⅵ. bug分支 -- `git stash` && 合并策略
  • Ⅶ. 删除临时分支 -- `git branch -D [name]`
  • 小结

在这里插入图片描述

Ⅰ. 理解分支

​ 分支是什么呢,其实 分支就像是分身术,想象一下,我们学编程语言的时候,如果能进行分身,也就是分支,此时本体去学 c++,而分身去 java,甚至再分身去学 php……

​ 当我们多个分身都学完了,再全部合体,此时我们本体就同时学会了多种语言,是不是很吊!

在这里插入图片描述

​ 分支就是这个道理!那 git 中的分支在哪里呢❓❓❓

​ 其实我们已经接触过了,但是当时没有细讲,还记得吗,在版本库中,有一个 HEAD 指针指向 master 分支(其实这个 master 分支不一定是主干分支,但是 master 分支通常是默认的主分支名称),它就相当于是本体,然后此时创建了多个分支出来去各自完成代码的编写等操作,这相当于影分身!最后我们将多个分支融合,其实就是合体的过程!

​ 在 git 中,分支可以看作是一个指向某个提交记录的指针(提交都是放在 .git/objects/ 中管理的),它指向当前工作目录中的版本。当你创建一个新的分支时,这个分支实际上是从当前分支分离出来的一个新的指针。

​ 因此,在某种程度上,每个分支都可以看作是一条主干

​ 再来理解一遍,HEAD 严格来说不是指向提交,而是指向 mastermaster 才是指向提交的,所以,HEAD 指向的就是当前分支

在这里插入图片描述

​ 说了这么多废话,下面我们先来看一下 master 分支:

在这里插入图片描述

​ 首先 HEAD 所指的就是 master 分支的开头,也就是哈希值为 c82c……6f6 的节点,而这个节点其中通过 parent 指针连接到 ac00……f34 节点上,其实这是前一个节点,相当于一条时间线上,这些节点是按顺序排布的,而 master 指向最新的那个节点,如下图所示:

​ 此时我们是可以创建新分支的,还能融合分支等操作,差不多如下图所示:

在这里插入图片描述

​ 而我们接下来就要讲如何进行分支的创建、切换等一系列管理分支的操作!

Ⅱ. 理解HEAD指针

​ 在 git 中,HEAD 是一个特殊的指针,它指向当前所在的分支或提交。作用是跟踪当前工作目录的状态,并确定下一次提交将基于哪个分支或提交

git 中进行提交时,实际上是将新的 提交的索引 添加 HEAD 所指的分支上。而当 创建一个新的分支时,我们要注意使用指令的不同,HEAD 的指向也是不同的,可能是指向当前分支,也可能是指向新的分支,这个是要时刻注意的,因为如果错误地在其它分支上提交了东西,那么分支就会变乱的,需要花时间去 “修补” 它!

​ 除了指向当前分支或提交,HEAD 也可以指向一个提交的哈希值。这种情况是处于一个 “分离头指针” 的状态,这意味着你不在任何分支上,而是直接基于某个提交进行开发和修改。

​ 除此之外,HEAD 还可以指向一个标签,这种情况下,你处于一个标签的 “分离头指针” 状态。

​ 简单地说,HEAD 指针指向的分支就是当前正在工作的分支,可以参考上面的图片!理解 HEAD 指针的作用是很重要的,因为下面我们创建分支、切换分支等操作的时候,如果不清楚 HEAD 指针的指向,那么很可能导致几条分支都凌乱了,那是非常麻烦的!

Ⅲ. 创建、切换、合并、删除分支

​ 首先我们得先知道当前我们本地仓库中有哪些分支,这时候就要用到 git branch 指令查看,如下所示:

[liren@VM-8-7-centos gitcode]$ git branch
* master

master 前面的 星号,表示的是当前 HEAD 指针的指向,在 master 前面表示当前 HEAD 指向的就是 master 分支,这里因为只有一个分支,所以看起来不是那么的明显,下面创建其它分支之后我们就会看得更清晰!

​ 另外这里重新介绍一个 git log 指令中非常好用的选项,就是帮助我们在查看日志的时候,以时间线的形式打印出不同分支的提交记录!

​ 整个指令就是这样子的:git log --graph --abbrev-commit

[liren@VM-8-7-centos gitcode]$ git log --graph --abbrev-commit 
* commit c82c67b
| Author: lirendada <2916776007@qq.com>
| Date:   Mon Jul 10 16:16:14 2023 +0800
| 
|     change readme
|  
* commit ac00e61
| Author: lirendada <2916776007@qq.com>
| Date:   Mon Jul 10 15:10:04 2023 +0800
| 
|     add file5
|  
* commit ced585b
……

​ 因为现在我们只有一个分支,所以看起来效果不是很明显!

1、创建分支 – git branch [name]

​ 使用 git branch [name] 就可以创建一个分支。下面我们创建一个叫做 dev 的分支出来:

[liren@VM-8-7-centos gitcode]$ git branch dev
[liren@VM-8-7-centos gitcode]$ git branch 
  dev
* master
[liren@VM-8-7-centos gitcode]$

​ 现在我们就可以看到星号当前还是在 master 分支上的,也就是说此时 HEAD 指向的还是 master 分支,我们可以花个示意图来看看:

在这里插入图片描述

​ 如何验证此时 masterdev 的索引都是之前 master 的最新提交呢,此时很好验证,就是看看索引一不一样嘛,如下所示:

[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline  # 先查看一下日志,看看最新的提交记录
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme

[liren@VM-8-7-centos gitcode]$ cat .git/refs/heads/master # 查看master分支的索引,发现就是最新的提交记录
c82c67bb370034ef67d0bde191252742fcc7d6f6

[liren@VM-8-7-centos gitcode]$ cat .git/refs/heads/dev # 查看dev分支的索引,是和master一样的,说明此时指向同一个节点!
c82c67bb370034ef67d0bde191252742fcc7d6f6

💥💥💥注意:以上图片其实是采用 --no-ff 的方式来合并分支的,这样子画出来更便于理解,而实际情况是这样子的:

在这里插入图片描述

​ 但是为了便于理解,我们都采用之前那种更像分支的方式来画图!我们后面会讲这两种方式的区别!

2、切换分支 – git checkout

​ 我们在之前的撤销修改操作中有接触过这个指令,但是作用却截然不同,撤销工作区修改的指令中必须得有双横线,即 git checkout -- [filename],而我们这里用来切换分支则不需要加上双横线,只需要跟上对应的分支名即可!

git checkout 命令用于 切换分支恢复文件检出提交 等操作。其常见用法如下:

切换分支:git checkout <branch-name>			   # 切换到指定的分支并更新工作目录
创建新分支:git checkout -b <new-branch-name>	   # 创建一个新的分支并切换到该分支
强制切换分支:git checkout -f <branch-name>	  # 强制切换到指定分支并丢弃所有未提交的更改

恢复文件:git checkout <file-name> 	 # 恢复指定文件的内容到最近的提交状态

检出提交:git checkout <commit>       # 将工作目录中的所有文件恢复到指定提交的状态,但不会创建新的分支

切换到标签:git checkout <tag-name>   # 切换到指定的标签并更新工作目录

​ 对于切换分支来说,我们常用的是第一个指令;而如果想一步到位,既要创建分支又想切换到该新分支上,那么就用第二条指令!

​ 需要注意的是,git checkout 命令会修改工作目录中的文件内容,因此在 使用该命令时需要注意备份重要的文件,并确保已提交或保存所有的更改

​ 下面我们就来演示一下如何将 HEAD 指针指向我们上面创建的 dev 分支:

[liren@VM-8-7-centos gitcode]$ git branch          # 切换前
  dev
* master

[liren@VM-8-7-centos gitcode]$ git checkout dev    # 切换分支
Switched to branch 'dev'

[liren@VM-8-7-centos gitcode]$ git branch          # 切换后
* dev
  master

​ 用图来表示的话,其实就是 HEAD 指针改变了指向 罢了,如下所示:

在这里插入图片描述

​ 为了测试是否两个分支上提交是互不影响的,下面我们对两个分支来进行测试:

[liren@VM-8-7-centos gitcode]$ git branch     # 先看看分支信息
* dev
  master
[liren@VM-8-7-centos gitcode]$ cat readme 	  # 然后看看即将修改的文本的内容
lirendada

[liren@VM-8-7-centos gitcode]$ echo "hello world" >> readme 		  # 向readme插入数据后进行提交
[liren@VM-8-7-centos gitcode]$ git add readme
[liren@VM-8-7-centos gitcode]$ git commit -m 'dev insert into readme'
[dev 1e0a028] dev insert into readme
 1 file changed, 1 insertion(+)
 
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline   # 查看日志,会发现多了提交记录更新成当前插入数据的提交记录了
1e0a028cf4c9ac4566c365e09cbb360bffa34afd dev insert into readme
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme

[liren@VM-8-7-centos gitcode]$ git checkout master 		 # 切换到master分支
Switched to branch 'master'
[liren@VM-8-7-centos gitcode]$ cat readme 				# 查看readme文件,发现还是原来的样子
lirendada
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline  # 查看日志发现没有dev分支的提交记录,说明已经独立了!
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme

​ 这里的操作,如果画图来表示的话,如下所示:

在这里插入图片描述

​ 可以看到此时 dev 分支的指向其实已经变了,但是 master 分支的指向还是不变,我们可以验证一下:

[liren@VM-8-7-centos gitcode]$ cat .git/refs/heads/master       # master的指向还是原来那个
c82c67bb370034ef67d0bde191252742fcc7d6f6

[liren@VM-8-7-centos gitcode]$ cat .git/refs/heads/dev  		# dev的指向就是新的版本提交
1e0a028cf4c9ac4566c365e09cbb360bffa34afd

​ 而 Fast-forward 方式的图如下所示:

在这里插入图片描述

3、合并分支 – git merge

git merge <branch-name> 命令用于 将两个或多个分支的历史记录合并成一个新的提交。因此需要仔细审查合并结果,确保合并后的代码能够正常工作,并保证项目的稳定性和可维护性。

​ 这个指令还支持一些选项,例如 --no-commit 选项可以在合并后不自动提交合并结果,--squash 选项可以将多个提交合并为一个单独的提交,等等。

​ 要注意的是,合并后的提交记录,是放到当前工作的分支上面去的

​ 下面我们就把之前的 master 分支和 dev 分支合并起来,然后将该提交记录放到 master 分支中去:

[liren@VM-8-7-centos gitcode]$ cat .git/refs/heads/dev   # 首先查看一下dev的记录索引
1e0a028cf4c9ac4566c365e09cbb360bffa34afd
[liren@VM-8-7-centos gitcode]$ cat readme 				# 看一下此时master分支下的readme中的内容
lirendada

[liren@VM-8-7-centos gitcode]$ git merge dev			# 合并分支
Updating c82c67b..1e0a028
Fast-forward
 readme | 1 +
 1 file changed, 1 insertion(+)
 
[liren@VM-8-7-centos gitcode]$ cat readme  # 合并后可以看到readme中就变成了新版本的内容了
lirendada
hello world
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline  # 并且查看日志也能看到当前提交日志和dev分支是一样的
1e0a028cf4c9ac4566c365e09cbb360bffa34afd dev insert into readme
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$ cat .git/refs/heads/master 	    # master的指向也变成了新的一次提交 
1e0a028cf4c9ac4566c365e09cbb360bffa34afd

我们可以看到合并分支时候,打印的内容中有一串叫做 Fast-forward 的东西,这是啥呢❓❓❓

​ 在 git merge 中,如果使用了 快进合并(Fast-forward Merge,则 当前分支的指针会直接指向被合并的分支的最新提交,而不会创建新的合并提交

​ 例如,假设你当前在 master 分支上,而 dev 分支是从 master 分支上分出来的,且在 dev 分支上有一些新的提交。如果你执行 git merge dev 命令,并且 dev 分支的历史记录可以直接被 master 分支所包含,那么 git merge 将会执行一个快进合并,直接将 master 分支指针指向 dev 分支的最新提交,而不会创建新的合并提交。

在这里插入图片描述

​ 后面我们会讲另一种合并方式也就是我们上面有提及到的 --no-ff,那种打印日志出来会更加好看一些,如下所示:

在这里插入图片描述

4、删除分支 – git branch -d <branch-name>

​ 合并完之后,如果被合并的分支已经不需要了,那么可以使用 git branch -d <branch-name> 来进行删除分支,因为我们合并完分支之后,那些被合并的分支并不会自动删除,需要我们手动去删除

注意事项:

  • 删除分支之前需要确认该分支的历史记录不再被其他分支所依赖,以免影响项目的稳定性和可维护性。
  • 当前工作分支是无法删除自己的!

​ 下面我们就把之前的 dev 分支删除:

[liren@VM-8-7-centos gitcode]$ git branch 
* dev
  master
[liren@VM-8-7-centos gitcode]$ git branch -d dev                      #当前工作分支是无法删除自己的
error: Cannot delete the branch 'dev' which you are currently on.

[liren@VM-8-7-centos gitcode]$ git checkout master       #切换为其它分支
Switched to branch 'master'
[liren@VM-8-7-centos gitcode]$ git branch -d dev		 #重新进行删除dev分支
Deleted branch dev (was 1e0a028).
[liren@VM-8-7-centos gitcode]$ git branch 			     #删除成功
* master

​ 此时的状态如下所示:

在这里插入图片描述

Ⅳ. 合并冲突

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

​ 为了演示这问题,创建一个新的分支 dev1 ,并切换至目标分支,我们可以使用上面提到过的 git checkout -b dev1 一步完成创建并切换的动作,实例如下:

[liren@VM-8-7-centos gitcode]$ git checkout -b dev1        # 创建和切换,一步到位!
Switched to a new branch 'dev1'
[liren@VM-8-7-centos gitcode]$ git branch 
* dev1
  master

​ 在 dev1 分支下修改 readme 文件,更改文件内容如下,并进行一次提交,如:

[liren@VM-8-7-centos gitcode]$ cat readme   # 当前是dev分支
lirendada
hello world
[liren@VM-8-7-centos gitcode]$ vim readme   # 使用编辑器将内容改变
[liren@VM-8-7-centos gitcode]$ cat readme 
lirendada
hello dev1
[liren@VM-8-7-centos gitcode]$ git add .    # 提交新内容
[liren@VM-8-7-centos gitcode]$ git commit -m 'modify readme:dev1'
[dev1 0cd9936] modify readme:dev1
 1 file changed, 1 insertion(+), 1 deletion(-)

​ 然后切换到 master 分支下,将其内容也稍加修改,保持和 dev1 修改内容中有一丝不同,并进行一次提交:

[liren@VM-8-7-centos gitcode]$ git checkout master    #切换为master分支
Switched to branch 'master'
[liren@VM-8-7-centos gitcode]$ cat readme 
lirendada
hello world
[liren@VM-8-7-centos gitcode]$ vim readme 			  #使用编辑器将内容改变
[liren@VM-8-7-centos gitcode]$ cat readme 
lirendada
hello master
[liren@VM-8-7-centos gitcode]$ git add .                               #提交新内容
[liren@VM-8-7-centos gitcode]$ git commit -m 'modify readme:master'    
[master c7bfef3] modify readme:master
 1 file changed, 1 insertion(+), 1 deletion(-)

​ 此时 dev1master 各自都有了新的提交,如下所示:

在这里插入图片描述

​ 下面我们将它们两个合并起来,合并到 master 分支上去:

[liren@VM-8-7-centos gitcode]$ git branch      
  dev1
* master
[liren@VM-8-7-centos gitcode]$ git merge dev1       # 合并分支
Auto-merging readme
CONFLICT (content): Merge conflict in readme
Automatic merge failed; fix conflicts and then commit the result.

[liren@VM-8-7-centos gitcode]$ cat readme           # 查看文本内容,发现奇奇怪怪的东西出现了!
lirendada
<<<<<<< HEAD
hello master
=======
hello dev1
>>>>>>> dev1

readme 文件中的 <<<<<<< HEAD======= 中间的内容是 master 分支中冲突的内容,而从 =======>>>>>>> dev1 中间的内容则是 dev1 分支中冲突的内容!

​ 为什么它们都写到了 readme 文件中呢❓❓❓

​ 仔细想想,git 可不知道我们在合并了两个文件中,长得非常相似的内容到底要留下哪个,所以 git 索性就将它们都写入到文件中,并且用标识边界给区分开,剩下的工作就需要我们自己手动去删掉不需要的内容是哪项

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

[liren@VM-8-7-centos gitcode]$ vim readme 
[liren@VM-8-7-centos gitcode]$ cat readme          # 调整冲突代码
lirendada
hello master
[liren@VM-8-7-centos gitcode]$ git add readme      # 重新提交修正后的内容
[liren@VM-8-7-centos gitcode]$ git commit -m 'merge, and modify readme'
[master 3800d19] merge, and modify readme

​ 此时我们可以通过 git log --graph --abbrev-commit 打印出分支线来看看变化,可以看到这次它们 不再是之前的 Fast forward 方式进行合并了,因为这次是因为合并冲突!

[liren@VM-8-7-centos gitcode]$ git log --graph --abbrev-commit 
*   commit 3800d19
|\  Merge: c7bfef3 0cd9936
| | Author: lirendada <2916776007@qq.com>
| | Date:   Tue Jul 11 15:51:59 2023 +0800
| | 
| |     merge, and modify readme
| |   
| * commit 0cd9936
| | Author: lirendada <2916776007@qq.com>
| | Date:   Tue Jul 11 15:31:41 2023 +0800
| | 
| |     modify readme:dev1
| |   
* | commit c7bfef3
|/  Author: lirendada <2916776007@qq.com>
|   Date:   Tue Jul 11 15:33:00 2023 +0800
|   
|       modify readme:master
………………

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

[liren@VM-8-7-centos gitcode]$ git branch -d dev1 
Deleted branch dev1 (was 0cd9936).
[liren@VM-8-7-centos gitcode]$ git branch 
* master

在这里插入图片描述

Ⅴ. 分支管理策略

一、分支合并模式

git merge 指令中,有三种主要的合并模式,它们分别是:

  1. Fast-forward 合并模式(默认模式):
    • 如果 被合并的分支的历史记录可以直接被当前分支所包含,那么 git merge 直接将当前分支的指针指向被合并分支的最新提交。这种模式下 不会创建新的合并提交
  2. 普通合并模式
    • 如果 被合并的分支的历史记录不能直接被当前分支所包含,那么 git merge 将会创建一个新的合并提交,用于记录两个分支的合并历史,包含了被合并分支和当前分支的所有历史记录。这种模式下 会创建一个新的合并提交
  3. 简单合并模式
    • 如果 被合并的分支只有一个提交和当前分支有共同的提交,那么 git merge 会将被合并分支的提交合并到当前分支上,并创建一个新的提交,但不会创建新的合并提交。这种模式下,被合并分支的历史记录将会被包含在当前分支的提交历史中

​ 💥需要注意的是,如果执行普通合并或简单合并,可能会出现合并冲突(Merge Conflict,需要手动解决冲突后再提交合并结果。

​ 所以在执行合并操作时,需要根据实际情况选择合适的合并模式,以免影响项目的稳定性和可维护性。

​ 其中这里的前两点我们在前面就遇到了,通常合并分支时,如果可能,Git 会采用 Fast forward 模式,因为它很快!

在这里插入图片描述

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

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

在这里插入图片描述

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

[liren@VM-8-7-centos gitcode]$ git log --graph --pretty=oneline --abbrev-commit
*   3800d19 merge, and modify readme
|\  
| * 0cd9936 modify readme:dev1
* | c7bfef3 modify readme:master
|/  
* 1e0a028 dev insert into readme
* c82c67b change readme
* ac00e61 add file5
* ced585b add file4
* 7eb10f5 add 3 files
* cdc96e6 first add file:readme
[liren@VM-8-7-centos gitcode]$ 

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

​ 下面我们实战以下 --no-ff 方式的 git merge

​ 首先,创建新的分支 dev2 ,并切换至新的分支:

[liren@VM-8-7-centos gitcode]$ git checkout -b dev2
Switched to a new branch 'dev2'
[liren@VM-8-7-centos gitcode]$ git branch 
* dev2
  master

​ 接着修改 readme 文件,并提交一个新的 commit :

[liren@VM-8-7-centos gitcode]$ cat readme 
lirendada
hello master
[liren@VM-8-7-centos gitcode]$ echo "add one line" >> readme 
[liren@VM-8-7-centos gitcode]$ cat readme 
lirendada
hello master
add one line
[liren@VM-8-7-centos gitcode]$ git add readme
[liren@VM-8-7-centos gitcode]$ git commit -m 'add one line: dev2'
[dev2 ab04ce4] add one line: dev2
 1 file changed, 1 insertion(+)

​ 切回 master 分支,开始合并:

[liren@VM-8-7-centos gitcode]$ git checkout master 
Switched to branch 'master'
[liren@VM-8-7-centos gitcode]$ git merge --no-ff -m 'merge with no fast forward' dev2   # 非ff合并需要生成一个合并提交,要有记录
Merge made by the 'recursive' strategy.
 readme | 1 +
 1 file changed, 1 insertion(+)
 
[liren@VM-8-7-centos gitcode]$ cat readme  # 可以看到已经合并成功,并且不是ff方式
lirendada
hello master
add one line
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline --graph --abbrev-commit 
*   1b27e08 merge with no fast forward
|\  
| * ab04ce4 add one line: dev2
|/  
*   3800d19 merge, and modify readme
|\  
| * 0cd9936 modify readme:dev1
* | c7bfef3 modify readme:master
|/  
* 1e0a028 dev insert into readme
* c82c67b change readme
* ac00e61 add file5
* ced585b add file4
* 7eb10f5 add 3 files
* cdc96e6 first add file:readme

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

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

二、分支策略

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

​ 首先,master 分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活,那在哪干活呢?

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

在这里插入图片描述

​ 你和你的同事每个人都在 dev 分支上干活,每个人都有自己的分支,时不时地往 dev 分支上合并就可以了。

​ 所以,团队合作的分支看起来就像这样:
在这里插入图片描述

Ⅵ. bug分支 – git stash && 合并策略

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

​ 可现在 dev2 的代码在工作区中开发了一半,还无法提交,怎么办❓❓❓

​ 例如:

[liren@VM-8-7-centos gitcode]$ git branch 
* dev2
  master
[liren@VM-8-7-centos gitcode]$ cat readme 
lirendada
hello master
add one line
i am coding...
[liren@VM-8-7-centos gitcode]$ git status
# On branch dev2
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	modified:   readme
#
no changes added to commit (use "git add" and/or "git commit -a")

​ 此时如果我们直接切换到 master 的话,dev2 中工作区和暂存区的文件就没了!

​ 为了不让 dev2 分支中开发了很久的文件就此消失。我们可以用 git stash 指令,将当前的工作区信息进行储藏,被储藏的内容可以在将来某个时间恢复出来。

[liren@VM-8-7-centos gitcode]$ git stash
Saved working directory and index state WIP on dev2: ab04ce4 add one line: dev2
HEAD is now at ab04ce4 add one line: dev2
[liren@VM-8-7-centos gitcode]$ git status       # 发现工作区和暂存区的内容都被拿走,存储起来了
# On branch dev2
nothing to commit, working directory clean

​ 其存储本质就是在 .git/refs 目录下创建了一个 stash 文件,里面放着此时分支存储的内容:

在这里插入图片描述

​ 其文件内部存的就是该存储文件的索引:

[liren@VM-8-7-centos gitcode]$ cat .git/refs/stash 
2c625bd178126e9e4e0efc67e7affdb1db3d43aa
[liren@VM-8-7-centos gitcode]$

​ 储藏 dev2 工作区之后,由于我们要基于 master 分支修复 bug,所以需要切回 master 分支,再 新建临时分支来修复 bug,一般这个临时分支我们给它命名为 fix_bug

可能有人就会问,为什么不直接在 master 分支上修改呢❓❓❓

​ 原因很简单,因为 master 分支是需要保持稳定的,就算其出了 bug,我们也不能直接在它上面动手脚,因为可能会改出更大的 bug,所以此时我们需要用临时分支来代替完成修改 bug 的工作!

​ 举个例子:

[liren@VM-8-7-centos gitcode]$ git branch       
  dev2
* master
[liren@VM-8-7-centos gitcode]$ cat readme 	 # 查看readme文件,发现最后一行少写了e,是个bug
lirendada
hello master
add one line
a, b, c, d, 
[liren@VM-8-7-centos gitcode]$ git checkout -b fix_bug	 # 创建出一个临时分支,并且切换过去
M	readme
Switched to a new branch 'fix_bug'
[liren@VM-8-7-centos gitcode]$ vim readme 	 # 进行修改和查看
[liren@VM-8-7-centos gitcode]$ cat readme 
lirendada
hello master
add one line
a, b, c, d, e
[liren@VM-8-7-centos gitcode]$ git add readme	 # 提交修改完的结果
[liren@VM-8-7-centos gitcode]$ git commit -m 'fix bug'
[fix_bug 1405e9d] fix bug
 1 file changed, 1 insertion(+)

​ 修复完成后,切换到 master 分支,并完成合并,记得 最好要使用 非fast forward 方式合并,最后删除 fix_bug 分支:

[liren@VM-8-7-centos gitcode]$ git checkout master    # 切换为master分支
Switched to branch 'master'
[liren@VM-8-7-centos gitcode]$ git merge --no-ff -m 'merge fix_bug' fix_bug   # 合并分支
Merge made by the 'recursive' strategy.
 readme | 1 +
 1 file changed, 1 insertion(+)
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline --graph --abbrev-commit   # 打印分支提交记录
*   658c712 merge fix_bug
|\  
| * 1405e9d fix bug
|/  
*   1b27e08 merge with no fast forward
|\  
| * ab04ce4 add one line: dev2
|/  
*   3800d19 merge, and modify readme
|\  
| * 0cd9936 modify readme:dev1
* | c7bfef3 modify readme:master
|/  
* 1e0a028 dev insert into readme
……
[liren@VM-8-7-centos gitcode]$ cat readme    # 查看内容,看到已经改过来了
lirendada
hello master
add one line
a, b, c, d, e
[liren@VM-8-7-centos gitcode]$ git branch -d fix_bug    # 删除临时分支
Deleted branch fix_bug (was 1405e9d).

​ 至此,bug 的修复工作已经做完了!

​ 但是我们还要继续回到 dev2 分支进行开发,所以切换回 dev2 分支:

[liren@VM-8-7-centos gitcode]$ git checkout dev2 
Switched to branch 'dev2'
[liren@VM-8-7-centos gitcode]$ git status 
# On branch dev2
nothing to commit, working directory clean

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

[liren@VM-8-7-centos gitcode]$ git stash list 
stash@{0}: WIP on dev2: ab04ce4 add one line: dev2

​ 可以看到工作现场还在,Git 是把 stash 内容存在 .git/refs/stash 中了,但是需要恢复一下,如何恢复现场呢❓❓❓

​ 我们可以使用 git stash pop 命令,恢复的同时会把 stash 也删了,实例如下:

[liren@VM-8-7-centos gitcode]$ git stash pop
# On branch dev2
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <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} (2c625bd178126e9e4e0efc67e7affdb1db3d43aa)

​ 另外,恢复现场也可以采用 git stash apply 恢复,但是恢复后,stash 内容并不删除,此时需要用 git stash drop 来删除,如下所示:

[liren@VM-8-7-centos gitcode]$ git stash list
stash@{0}: WIP on dev2: ab04ce4 add one line: dev2
[liren@VM-8-7-centos gitcode]$ git stash apply     #恢复现场,但不删除stash内容
# On branch dev2
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	modified:   readme
#
no changes added to commit (use "git add" and/or "git commit -a")
[liren@VM-8-7-centos gitcode]$ git stash list
stash@{0}: WIP on dev2: ab04ce4 add one line: dev2
[liren@VM-8-7-centos gitcode]$ git stash drop 		#手动删除
Dropped refs/stash@{0} (76e4351a0cdf678e1efbef6396a2462d9c36d729)
[liren@VM-8-7-centos gitcode]$ git stash list
[liren@VM-8-7-centos gitcode]$

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

[liren@VM-8-7-centos gitcode]$ cat readme     #查看内容,假设此时已经开发完
lirendada
hello master
add one line
i am coding... Done!!! 
[liren@VM-8-7-centos gitcode]$ git add readme                   #提交
[liren@VM-8-7-centos gitcode]$ git commit -m 'modify readme'
[dev2 7f3aebd] modify readme
 1 file changed, 1 insertion(+)

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

在这里插入图片描述

master 分支目前最新的提交,是要领先于新建 dev2 时基于的 master 分支的提交的,所以我们 dev2 中当然看不见修复 bug 的相关代码

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

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

在这里插入图片描述

​ 解决这个问题的一个好的建议就是:最好在 dev2 分支上先试探性地合并下 master ,如果没问题的话,再让 master 去合并 dev2,这样做的好处是有冲突的话可以在 dev2 中解决并进行测试,而不影响 master 分支 。此时的状态为:

在这里插入图片描述

在这里插入图片描述

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

[liren@VM-8-7-centos gitcode]$ git branch     # 确保当前是dev2分支
* dev2
  master
[liren@VM-8-7-centos gitcode]$ git merge master   # 合并master分支到dev2分支下
Auto-merging readme
CONFLICT (content): Merge conflict in readme
Automatic merge failed; fix conflicts and then commit the result.

[liren@VM-8-7-centos gitcode]$ cat readme 	 # 查看错误内容
lirendada
hello master
add one line
<<<<<<< HEAD
i am coding... Done!!!
=======
a, b, c, d, e
>>>>>>> master
[liren@VM-8-7-centos gitcode]$ vim readme 		# 修改错误内容
[liren@VM-8-7-centos gitcode]$ cat readme 		# 查看修改后内容
lirendada
hello master
add one line
a, b, c, d, e
i am coding... Done!!!
[liren@VM-8-7-centos gitcode]$ git add readme	 # 重新提交
[liren@VM-8-7-centos gitcode]$ git commit -m 'merge master'
[dev2 8b781ad] merge master
[liren@VM-8-7-centos gitcode]$ git status 
# On branch dev2
nothing to commit, working directory clean

[liren@VM-8-7-centos gitcode]$ git checkout master 	 # 切换到master分支
Switched to branch 'master'
[liren@VM-8-7-centos gitcode]$ git merge dev2 		 # 合并dev2分支
Updating 658c712..8b781ad
Fast-forward
 readme | 1 +
 1 file changed, 1 insertion(+)
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
nothing to commit, working directory clean
[liren@VM-8-7-centos gitcode]$ git branch -d dev2 	 # 删除dev2分支
Deleted branch dev2 (was 8b781ad).

Ⅶ. 删除临时分支 – git branch -D [name]

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

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

​ 可是,如果我们今天正在某个 feature 分支上开发了一半,被产品经理突然叫停,说是要停止新功能的开发。虽然白干了,但是这个 feature 分支还是必须就地销毁,留着没用了。

​ 这时使用传统的 git branch -d 命令删除分支的方法是不行的。因为 -d 选项只有在合并了分支以后才能用来删除指定分支

[liren@VM-8-7-centos gitcode]$ git checkout -b dev     # 创建并切换到dev分支开发新模块
Switched to a new branch 'dev'
[liren@VM-8-7-centos gitcode]$ touch newfile
[liren@VM-8-7-centos gitcode]$ echo "i am iron man" >> newfile
[liren@VM-8-7-centos gitcode]$ cat newfile 
i am iron man

[liren@VM-8-7-centos gitcode]$ git add newfile      # 提交更改
[liren@VM-8-7-centos gitcode]$ git commit -m 'give a new file'
[dev bf27408] give a new file
 1 file changed, 1 insertion(+)
 create mode 100644 newfile
 
[liren@VM-8-7-centos gitcode]$ git checkout master   # 此时要求删除dev分支,则切换到master分支
Switched to branch 'master'
[liren@VM-8-7-centos gitcode]$ git branch -d dev 	 # 进行删除,发现失败,并且提示说要用-D选项去删除
error: The branch 'dev' is not fully merged.
If you are sure you want to delete it, run 'git branch -D dev'.

​ 根据提示,我们得用 git branch -D dev 去删除 dev 分支,如下所示:

[liren@VM-8-7-centos gitcode]$ git branch -D dev
Deleted branch dev (was bf27408).
[liren@VM-8-7-centos gitcode]$ git branch 
* master
[liren@VM-8-7-centos gitcode]$ 

在这里插入图片描述

小结

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

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

​ 并且 Git 无论创建、切换和删除分支,Git1 秒钟之内就能完成!无论你的版本库是1个文件还是1万个文件。
在这里插入图片描述


http://www.kler.cn/a/533804.html

相关文章:

  • 四.4 Redis 五大数据类型/结构的详细说明/详细使用( zset 有序集合数据类型详解和使用)
  • 穷举vs暴搜vs深搜vs回溯vs剪枝系列一>黄金矿工
  • 深度剖析八大排序算法
  • 【BUUCTF杂项题】荷兰宽带数据泄露、九连环
  • 18.[前端开发]Day18-王者荣耀项目实战(一)
  • SpringAI 人工智能
  • 2024年12月 Scratch 图形化(三级)真题解析 中国电子学会全国青少年软件编程等级考试
  • 记录一下 在Mac下用pyinstallter 打包 Django项目
  • 自己实现的一个缓存数据库(搞着玩) .net Core/6/8/9
  • 【C语言高级特性】位操作(二):应用场景
  • python开发:爬虫示例——GET和POST请求处理
  • vue2-给data动态添加属性
  • WPS中解除工作表密码保护(忘记密码)
  • 手写MVVM框架-实现v-model(单向绑定)
  • rabbitMQ数据隔离
  • 1 HBase 基础
  • PHP 中 `foreach` 循环结合引用使用时可能出现的问题
  • 【C++】STL——vector的使用
  • 【自然语言处理(NLP)】生成词向量:ELMo(Embedded from Language Models)原理及应用
  • 硬件电路基础
  • 每日Attention学习20——Group Shuffle Attention
  • DeepSeek-V3 大模型哪些地方超越了其他主流大模型
  • 中国通信企业协会 通信网络安全服务能力评定 风险评估二级要求准则
  • 保姆级教程Docker部署Zookeeper官方镜像
  • FPGA学习篇——Verilog学习1
  • Shell条件变量替换