git分支合并

在工作开发时,常用git作为版本控制。开发的过程中,一般不在主分支上开发,会拉出一个功能分支(feature)进行开发。功能开发完成后,再通过git merge把功能分支上的代码合并到主分支中。

有时我们在功能分支上提交了很多冗余的commit,我们想要把这些commit合并到一起,提交到主分支中。这时可以使用git rebase命令,进行变基,把冗余的commit合并到一起。

merge

git merge的常用选项参数

  • git merge --abort

    该命令仅仅在合并后导致冲突时才使用。git merge --abort将会抛弃合并过程并且尝试重建合并前的状态。但是,当合并开始时如果存在未commit的文件,git merge --abort在某些情况下将无法重现合并前的状态。(特别是这些未commit的文件在合并的过程中将会被修改时)。

  • git merge --ff

    --ff是指fast-forward命令。当使用fast-forward模式进行合并时,将不会创造一个新的commit节点。默认情况下,git-merge采用fast-forward模式。

  • git merge --no-ff

    即使可以使用fast-forward模式,也要创建一个新的合并节点。这是当git merge在合并一个tag时的默认行为。

  • git merge --squash

    --squash 当一个合并发生时,从当前分支和对方分支的共同祖先节点之后的对方分支节点,一直到对方分支的顶部节点将会压缩在一起,使用者可以经过审视后进行提交,产生一个新的节点。

演示示例

创建一个仓库

1
2
3
git init
git add .
git commit -m "init"

image-20221209154718302

切出分支用于开发

1
git checkout -b dev

在dev分支中进行开发,并做提交。

1
2
3
4
#更改文件
git add . && git commit -m 'dev 1'
#更改文件
git add . && git commit -m 'dev 2'

image-20221209182554332

使用默认参数合并分支

1
2
git checkout master
git merge dev # --ff是指fast-forward命令。当使用fast-forward模式进行合并时,将不会创造一个新的commit节点。默认情况下,git-merge采用fast-forward模式。

image-20221209182832407

1
2
3
4
#更改文件
git add . && git commit -m 'dev 3'
#更改文件
git add . && git commit -m 'dev 4'

image-20221209185709214

使用参数--no-ff合并分支

1
2
git checkout master
git merge --no-ff dev # 合并时创建一个新的节点,同时可以修改commit信息。

命令执行后会出现修改commit信息的编辑框,如果不需要编辑,直接退出即可。

image-20221209185825137

合并后的状态

image-20221209190614795

演示合并冲突如何解决

1
2
3
4
5
6
7
8
9
#更改文件
git add . && git commit -m 'dev 5'
#更改文件
git add . && git commit -m 'dev 6'
git checkout master
#更改文件
git add . && git commit -m 'master 1'
#更改文件
git add . && git commit -m 'master 2'

image-20221209191239581

1
git merge dev

因为有冲突,合并失败,输出信息如下

1
2
3
Auto-merging a.txt
CONFLICT (content): Merge conflict in a.txt
Automatic merge failed; fix conflicts and then commit the result.

使用git status 命令,输出如下

image-20221209191733982

这时需要我们手动解决缺陷,然后再提交

image-20221209191825697

1
2
git add .
git commit -m "merge conflict"

image-20221209191950579

1
2
3
4
5
git checkout -b dev2
#更改文件
git add . && git commit -m 'dev2 1'
#更改文件
git add . && git commit -m 'dev2 2'

image-20221209195113622

使用参数--squash合并分支

1
2
git checkout master
git merge --squash dev2
1
git status

image-20221209195347526

1
git commit -m "merge --squash"

image-20221209195607400

rebase

rebase的使用方法很多,这里只展示在合并时常用的做法,即把dev分支rebase到master分支上。

常用的命令做法是:在dev分支上,执行git rebase -i master,即可把dev分支变基到master分支上。-i命令表示可以编辑commit信息。可对commit做的编辑操作如下

命令 缩写 含义
pick p 保留该commit
reword r 保留该commit,但需要修改该commit的注释
edit e 保留该commit, 但我要停下来修改该提交(不仅仅修改注释)
squash s 将该commit合并到前一个commit
fixup f 将该commit合并到前一个commit,但不要保留该提交的注释信息
exec e 执行shell命令(不常用)
drop d 丢弃该commit

演示示例

初始化仓库

image-20221209233657138

1
git checkout -b dev

开发好的dev分支

image-20221209234240952

1
git rebase -i master

命令执行后出现如下编辑框,可以看到默认对commit的操作是保留所有commit

image-20221209234552819

编辑之后如下,保留dev 1;合并dev 2, dev 3;修改dev 4;合并dev 5,dev 6,但是不波流commit信息,丢弃dev7 dev8,;保留 dev9

image-20221209234720025

编辑,退出之后是这样

image-20221209234841691

修改了 dev 4 reword的提交信息之后

出现这个,是有冲突

image-20221209235108250

image-20221209235134850

解决冲突,git add

合并完成之后的log git log

image-20221209235720112

总结

git merge:当需要保留详细的合并信息的时候建议使用,特别是需要将分支合并进入master分支时

git rebase:当发现自己修改某个功能时,频繁进行了git commit提交时,发现其实过多的提交信息没有必要时使用,分支多,内容多时也可以考虑使用