在 Git 中,如何在不挑选新分支的情况下对历史中具有多个合并提交的分支进行 rebase + squash

Posted

技术标签:

【中文标题】在 Git 中,如何在不挑选新分支的情况下对历史中具有多个合并提交的分支进行 rebase + squash【英文标题】:In Git, How can I rebase + squash a branch that has multiple merge commits in it's history without cherry-picking onto a totally new branch 【发布时间】:2020-11-23 19:37:21 【问题描述】:

问题

我希望能够将最初从 master 分支出来的分支与 master 的多个合并一起使用,以便它在 master 上显示为单个提交。我们这样做是为了获取开发人员的分支并在 master 中生成干净的历史记录(一旦经过测试)。

我知道如何做到这一点,方法是从 master 的尖端创建一个新分支(即“master”指针)并在其上进行挑选(根据需要解决冲突,但应该可以使用 rebase 命令)只是(不应该吗?)。这里的假设是 master 本身没有被 rebase。

作为一个例子,我想以下面的历史为例,下面是分支主 和分支涂鸦:

原始历史

  *  commit K, branch doodle, merge commit (conflicts)
 /|
* |  commit J, branch master, 
| |
| *  commit I, branch doodle
* |  commit H, branch master
| |
| *  commit G, branch doodle,merge commit (conflicts)
|/|
| *  commit F, branch doodle
* |  commit E, branch master
| |
| *  commit D, branch doodle,merge commit (no conflicts)
|/|
* |  commit C, branch master
| *  commit B, Branch doodle 
|/
*    commit A, Branch master

并将其转换为 master 上的以下历史记录,其中 doodle 上的整个提交链被压缩并重新定位到 master 的 HEAD 上,如下所示。由于分支 doodle 的负责人已提交 K,并且 master 和 doodle 之间的所有冲突都已解决,因此执行以下操作应该像单个命令一样简单。也不会与已发表的大师的历史相混淆。

期望的历史记录

*    commit L, branch master,(squash commit B,D,F,G,I,K)
|
*    commit J, branch master
|
*    commit H, branch master
|
*    commit E, branch master
|
*    commit C, branch master
|
*    commit A, branch master

另一种方法是生成如下所示的历史记录,而不是 squash 在合并回master之前提交B',F',G'I',J',K'。这种方法 然而,下面似乎添加了一个额外的步骤,rebase 应该能够 处理(尽管解决冲突)。

替代历史

| *  commit K', branch doodle (possible conflict resolution)
| |
| *  commit I', branch doodle (possible conflict resolution)
| |
| *  commit G', branch doodle (possible conflict resolution)
| |
| *  commit F', branch doodle (possible conflict resolution)
| | 
| *  commit B', branch doodle (possible conflict resolution)
|/
*    commit K, branch master
|
*    commit H, branch master
| 
*    commit E, branch master
|
*    commit C, branch master
| 
*    commit A, Branch master

我的尝试

目前,我正在创建一个新的分支,从主提示和樱桃采摘 B、F 和我到它。这可行,但比我认为必要的要复杂,因为我必须重新解决合并冲突。现在,我知道rebase--rebase-merges 标志。但是,由于某种原因,我无法让--rebase-merges 产生“欲望历史”甚至替代历史。我可能会错误地选择带有rebase -i HEAD~N --rebase-merges 的提交。

问题

如何轻松地从原始历史转变为想要的历史?

另外,如果原始历史中的 master 在最后一次合并到 doodle 后有一些额外的提交,这种方法是否允许在拉入 master 之前解决冲突?

【问题讨论】:

【参考方案1】:

这很容易用reset --soft完成

git checkout doodle
git reset --soft master
git commit -m "doodle, as a single commit"

没有麻烦。如果有更多提交到 master 中,但 不是 doodle 的一部分,则在执行此操作之前合并。

【讨论】:

我确实有一个我遗漏的小细节,但我没有意识到这很容易。我留下的细节是我通常将另一个分支上的所有提交(在我的示例中是涂鸦)压缩在一起,以便我将原始时间/日期和第一次提交的作者留在原处,以便在时间/分支开始的日期。问题:是否可以执行其他命令来获取先前作者在 doodle 上的第一次提交的提交详细信息,并将其应用于您上面在 anwser eftshit0 中显示的新提交。 嗯....我猜你可以写一个小脚本来处理这些细节。获取 master outside 的第一个修订版很简单...然后获取该修订版的名称和电子邮件不会那么困难...然后您可以使用 --author 当您重置后执行提交。 @EmceeBC 您可以做的另一件事是从 master 中创建一个新分支,然后选择您想要的第一个提交。然后运行此答案,但将“master”替换为新分支。然后更改提交以修改所有更改。

以上是关于在 Git 中,如何在不挑选新分支的情况下对历史中具有多个合并提交的分支进行 rebase + squash的主要内容,如果未能解决你的问题,请参考以下文章

我分享了我的提交历史?

Git 如何从特定的提交中创建一个新的分支

Git 如何从特定的提交中创建一个新的分支

Git:如何在不丢失当前分支的情况下克隆项目?

Git 可以在不丢失历史记录的情况下重组我的文件夹吗?

彻底清除git所有历史提交记录使其为“新”库