Git中合并多个提交的方法总结

2022-05-04 49点热度 0人点赞 0条评论

同时发布于「破壳AI个人网站」、微信公众号:「破壳Ai」。

为了保持分支提交历史的清晰、独立,我们经常需要将几个提交合并成一个;但 Git 没有专门为合并提交提供相应的命令,为解决这个问题,我专门研究了几种方法来实现 提交的合并;如下:

概念

为了方便下文的描述,这里先定义几个概念;

若干个连续的提交 称为 提交段,即,一段提交的意思;也称 提交范围 ,在没有个歧义的情况下,也可简称 范围

提交段中最开始(最早)的那个提交 称为 起始点

提交段中最晚的那个提交 称为 结束点

方式1:修复最后一次提交

通过给 commit 命令添加 --amend 选项,可以修改最后一次的提交;它是将当前变更与最后一次提交的变更合并,并创建一个新的提交对象,然后用这个新的提交对象替换掉最后一次提交;

git commit --amend [-m <提交说明>]

示例:

假设最后一次提交是 C2,如下图所示:

执行 git commit --amend 命令后:

方式2:用 reset 重置

思路

先用 reset 命令 重置到 需要被合并的提交的起始点的父提交;被还原的提交默认会被放置在暂存区中,然后再手动提交暂存区的内容,从而实现将被还原的所有提交合并成一个;

步骤

  1. 用 reset 命令 重置到 需要被合并的提交的起始点的父提交;
  • 语法: git reset [--mixed | --soft] <起始点的父提交> ;重围最后的n个提交,也可用 git reset [--mixed | --soft] HEAD~n

示例: git reset --soft aa29fdgit reset HEAD~3

  1. 用重新提交被还原的提交:git commit -m <提交说明>

方式3:用交互式 rebase 合并

思路

交互式的 rebase 命令,可以在变基的过程中更改提交,应用这个特性,我们可以将一系列的提交变基到它们原来所在的基上,而不是新的基上,从而可以实现对一系统列提交进行更改的操作;

步骤

  1. 用交互式 rebase 命令对 需要被合并的提交 进行变基操作;
  • 语法: git rebase -i <起始点的父提交> ; 合并最后的n个提交,也可用 git rebase -i HEAD~n
  • 示例: git rebase -i aa29fdgit rebase -i HEAD~3

然后会弹出如下交互式界面:

说明,在互动界面中:

  • # 开头的是注释,前面不以 # 开头的是命令,默认都是 pick 命令,表示选中其后面的 提交。
  • 这些命令会被从上到下执行;
  • 可以对这些命令重新排序;
  • 如果删除一行,则对应的提交将会丢失;然而如果删除了全部内容,变基操作将会终止;
  • 空提交会被注释掉;

所有的命令如下:

  • pick <提交> | p <提交>:选中提交;
  • reword <提交> | r <提交>:选中提交,并且修改提交说明;
  • edit <提交> | e <提交>:选中提交,但在执行当前提交时会暂停,此时允许你修改这个提交;
  • squash <提交> | s <提交>:选中提交,但会将当前提交合并到上一个提交中去;
  • fixup <提交> | f <提交>:与squash相同,但不会保存当前提交的提交说明;
  • exec <命令> | x <提交>:使用 shell 运行命令
  • break | b:在此处停止(使用 git rebase --continue 继续变基)
  • drop <提交> | d <提交> :删除提交
  • label <label> | l <label> :为当前HEAD打上标记
  • reset <label> | t <label> :重围HEAD到该标记
  • merge [-C <提交> | -c <提交>] <label> [# oneline]:创建一个合并提交,并使用原始的合并提交说明(如果没有指定原始提交,使用注释部分的 oneline 作为提交说明)。使用 -c <提交> 可以编辑提交说明;
  1. 将需要合并的提交前端的命令改成 squash(或 s) 和 fixup(或 f),然后即同交互式界面;在交互式界面中,只有 squash 和 fixup 命令可以用来合并提交。如下图所示:

  1. 修改完成后,退出交互式界面(vim输入 :wq 保存并退出),然后按照交互式界面中设定好的命令顺序进行 rebase 操作;

方式4:创建新分支并用 rebase 合并

如果被合并的提交段并不在分支的末端,而是在分支的中间,如下图:

我们也可以用交互式rebase的方法进行合并,只是需要在 交互式界面中 对不需要被合并的提交应用 pick 命令,但如果 被合并的提交是距当前HEAD很久远的提交,交互式界面中就会出现太多不相关的提交,便利查找想要合并的提交变更困难,我有一个方法可以简化这种操作,如下:

思路

先基于被合并的提交段的终点提交创建一个临时的用于合并提交的分支A,则需要被合并的提交就会在在分支A的未端,然后在分支A上使用其它合并提交段的方法(如:方式1、方式2、方式3 等等)对提交进行合并,合并完成后,再将原分支中 终点提交 之后的所有提交变基到 分支A 上;

步骤

高清版的动画请见合并中间提交段动画-高清.gif 提取码:MI8K

  1. 基于需要被合并的提交段的终点提交 创建 新的临时分支T,并切换到该新分支上 git checkout -b 分支T <终点提交>
  2. 用其它合并提交段的方法(如:方式1、方式2、方式3 等等)在 分支T 上对需要被合并的提交进行合并操作;
  3. 切换到 原来的分支 ,并通过命令 git rebase --onto 分支T <终点提交> 将原分支上 被合并的提交段 的终点提交 之后的所有提交 变基到 分支T上。

方式5:用 rebase 的 autosquash 合并

这种方法与方式3:用交互式rebase合并的原理是一样的,只是不用手动更改交互式界面中的命令为 squashfixup 了;它会自动根据提交说明中命令标识来在 交互式rebase 界面中自动自动更改相应的命令;

使用方法

  1. 在进行提交时,如果这次提交需要与之前的某个提交合并,则使用 git commit --fixup=<合并的目标提交> 或者 git commit --squash=<合并的目标提交>; 这会生成一个带有标识的的提交;
  • 合并的目标提交: 指的是 需要与哪了提交进行合并;
  • squash: 标识当前提交需要合并到指定的提交中去;
  • fixup: 标识当前提交需要合并到指定的提交中去,但合并后不会保留当前提交的提交说明;
  1. 在需要合并的时候,执行命令 git rebase -i --autosquash <起始点的父提交> ,这时会弹出一个与 方式3:用交互式rebase合并 中的第1步的一样的交互式界面,并且上一步中被标识的提交会被自动修改成 fixupsquash

  2. 中设定好的命令顺序进行 rebase 操作;

注意:git rebase合并多次commit及可能遇到的问题

相关文章

订阅博客,及时获取文章更新邮件通知

close

订阅博客,及时获取文章更新邮件通知

古月弧

保持专注,持续进步。

文章评论