Git merge 与 rebase

在使用 git 进行版本管理的项目中,当完成一个特性的开发并将其合并到 master 分支时,会有两种方式:

  • git merge
  • git rebase

git rebase 与 git merge都有相同的作用,都是将一个分支的提交合并到另一分支上,但是在原理上却不相同。

准备工作

为了更好地观察执行 git merge 和 git rebase 之后发生的现象,我们首先做一些准备工作。

  1. 创建一个项目仓库,然后在其中构建两条分支,分别是 master, feature,feature 是特性分支。
  2. 分别在master,feature上增加几次提交。feature的提交表示开发时,实现某个模块后的提交。master的提交表示,当一个迭代开发完后,将feature合并到master。

具体步骤如下:

  1. git init 初始化仓库
  2. 新建一个文件 readme.md,git add . git commit -m ‘init’,完成第一次commit
  3. 创建feature分支
  4. 在readme.md添加内容add feature1,接着git add . git commit -m ‘add feature1’,重复此步骤,每添加一行commit一次,直到git commit -m ‘add feature3’。
  5. 切换master分支,在在readme.md添加内容add master1,接着git add . git commit -m ‘add master1’,直到git commit -m ‘add master3’

此时 Git Graph 如下:
Git merge 与 rebase_第1张图片
master 分支内容是这样的:
在这里插入图片描述
feature 分支内容是这样的:
在这里插入图片描述
现在我们根据当前分支情况,分别使用git merge 与 git rebase,看看有什么不同的现象。

git merge

可将当前仓库拷贝一份,分别演示git merge 与 git rebase。

将 feature 合并到 master:

  1. 切换 master:git checkout master
  2. 将 feature 合并到当前分支(即 master 分支):git merge feature

可以看到,出现冲突了
Git merge 与 rebase_第2张图片
解决冲突:

  1. 保留双方更改(Accept Both Changes)
  2. git add . git commit -m 'Merge branch ‘feature’
  3. 若想取消合并,使用 git merge --abort,取消合并,状态会回到合并之前

Git Graph:
Git merge 与 rebase_第3张图片
可以看到多了一次合并的历史。

根据上图,总结 git merge 有如下特点:

  • 只处理一次冲突
  • 引入了一次合并的历史记录,合并后的所有 commit 会按照提交时间从旧到新排列

merge 为什么会生成合并历史

merge不一定生成一次合并的历史,这取决于当前分支与指定分支的位置。
Git merge 与 rebase_第4张图片
合并bugfix分支到master分支时,如果master分支的状态没有被更改过,即 bugfix分支的历史记录包含master分支所有的历史记录 123456a

所以通过把master分支的位置移动到bugfix的最新分支上,就完成合并

如果master分支的历史记录在创建bugfix分支后又有新的提交,如下情况:
Git merge 与 rebase_第5张图片
这时候使用git merge的时候,会生成一个新的提交,并且master分支的HEAD会移动到新的分支上,如下:
Git merge 与 rebase_第6张图片
从上面可以看到,会把两个分支的最新快照以及二者最近的共同祖先进行三方合并,合并的结果是生成一个新的快照

git rebase

与 git merge 一致,git rebase 的目的也是将一个分支的更改并入到另外一个分支中去。

$ git rebase feature 
error: could not apply 5118ae5... add  master1
Resolve all conflicts manually, mark them as resolved with
"git add/rm ", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 5118ae5... add  master1
Auto-merging index.txt
CONFLICT (content): Merge conflict in index.txt

Administrator@DESKTOP-VJLOHAL MINGW64 /e/gitTest (master|REBASE 1/3)
$

可以看到产生冲突了。
Git merge 与 rebase_第7张图片
解决冲突:

  1. 解决冲突内容;
  2. git add .
  3. git rebase --continue

重复着个步骤3次,即可完成变基。master|REBASE 1/3 表示变基进度。最终 Git Graph 如下:
Git merge 与 rebase_第8张图片
如上图所示,他的主要特点如下:

  1. 改变当前分支从 master 上拉出分支的位置
  2. 没有多余的合并历史的记录,且合并后的 commit 顺序不一定按照 commit 的提交时间排列
  3. 可能会多次解决同一个地方的冲突(有 squash 来解决)

看得出来,feature 分支上的所有提交信息都会被合并到 master 分支上了,这些信息对我们来说不是必要的,我们在 masetr 分支上往往只需要知道合并进来了什么新的功能即可,这些多余的信息可以通过 git rebase 的交互模式进行整合。

git rebase 的交互模式

打开变基的交互模式只需要传入一个参数 -i 即可,同时还需要指定对哪些提交进行处理,如:

git rebase -i HEAD~6

上述命令指定了对当前分支的最近6次提交(也可以指定commit id)进行操作。下面我们使用上面这行命令将 feature 分支的提交合并。
Git merge 与 rebase_第9张图片
这里可以有多重操作,我们使用squash,将add feature2与add feature3合并掉。最终 Git Graph 如下:
Git merge 与 rebase_第10张图片
可以看到master上已经没有add feature2与add feature3 提交记录了

使用交互模式追加提交代码

以master分支为例,假设在commit add master3之后,我想在之前的某个提交追加代码,此时便可使用rebase -i 来追加提交。

Git Graph :
Git merge 与 rebase_第11张图片
提交信息:
Git merge 与 rebase_第12张图片
假设我要将第4行的内容追加到add master1,而不是commit一条新记录。

步骤如下:

  1. 找到add master1的前一个提交的commit id
  2. git stash,git rebase -i commit_id(在当前分支变基)

若不 stash 追加内容,则会报错:

error: cannot rebase: You have unstaged changes.
error: Please commit or stash them.

开始变基:

Administrator@DESKTOP-VJLOHAL MINGW64 ~/Desktop/rebase (master)
$ git stash
Saved working directory and index state WIP on master: c997e79 add master3

Administrator@DESKTOP-VJLOHAL MINGW64 ~/Desktop/rebase (master)
$ git rebase -i 29ab01886266b0a9637aacdc4c5827ffacb8874f

出现交互界面,选择edit,wq保存退出。
Git merge 与 rebase_第13张图片
提示如下:
Git merge 与 rebase_第14张图片
git stash pop 弹出修改,可以看到产生冲突了。
Git merge 与 rebase_第15张图片
继续变基:

  1. 解决冲突内容;
  2. git add .
  3. git rebase --continue / git commit --amend

重复以上步骤 3 次即可完成变基。

关于 git commit --maned 的用法

git commit --amend 修改git提交记录用法详解

扩展:我的提交信息(commit message)写错了怎么办?
参考答案:如果你的提交信息(commit message)写错了且这次提交(commit)还没有推(push), 你可以通过下面的方法来修改提交信息(commit message):git commit --amend --only -m 'fix: 新的提交信息'

你可能感兴趣的:(Git,git)