繁体   English   中英

Git:当中间有合并时如何变基为 1 次提交?

[英]Git: How to rebase into 1 commit when there's a merge in the middle?

我在一个特性分支feature-1上,它不在master

我的提交历史是:

`Adding rehX project`,                     // <-- my first commit
`Adding factory resets for rehX `,                      // <-- my second commit
`Setting regulatory values for rehX `,                  // <-- my third commit
'Merging in master and resolving conflicts'  / / <--- my fourth commit was merging in `master`
'Adding last minute request from QA'.        // <-- my unexpected 5th commit

当我不合并master时,我通常使用git rebase -interactive HEAD~(number of commits)这样我就可以将所有提交压缩到初始提交中。

现在我合并了 master ,它使事情复杂化了。 我在这里有什么选择吗?

TL;博士

只需使用git rebase --interactive master 原因见下文。

编辑:我没有注意到,在主题行中,您只想获得一次提交,这意味着还有另一种方法。

长的

您有多种选择。 如果有的话,你有太多的选择:

  • 您可以创建一个新分支并一次选择一个提交。
  • 您可以使用-n创建一个新分支并挑选提交,以便它们被预先压缩。
  • 您可以使用git rebase -i并使用 --onto 小心地将“提交樱桃的内容”部分与“放置副本的位置”部分--onto
  • 您可以使用git rebase -i而无需那种小心,并删除无关的pick命令,如果有的话(但这里不会有)。
  • 或者,要将所有内容转换为单个提交,请使用git reset --softgit commit

请注意,这些选项中的前四个最终以相同的方式工作,因此这实际上只是个人喜好问题。 无论您使用哪种方法,您都不会复制现有的合并。 事实上,rebase不能复制合并,尽管新奇的--rebase-merges ( -r ) 选项将提供/声称这样做。 它没有:它只是再次运行git merge以进行的合并。 如果你想自己做,你可以在使用前两种(手动模式,手动樱桃采摘)方法时自己做。

让我们从您所拥有的绘图开始:

          ----------------M--N   <-- feature-1 (HEAD)
         /               /
...--H--I   <-- master  /
         \             /
          J-----K-----L

大写字母代表提交 hash ID。 名称feature-1是您当前的分支名称,如括号中附加的HEAD所示,提交N是您当前的提交,其主题行是Adding last minute request from QA

(练习:以更简单的方式重新绘制此图。在纸上或白板上可能非常简单。不过,请检查您是否在master上进行了我没有绘制的提交。如果有,请尝试所有这些这样的提交。)

你需要的是在提交I之后构建一些新的提交系列——提交Imaster上的最后一个提交——通过使用现有提交JKLN的内容,而不是M的内容,因为我们计划完全放弃合并.

对于单个替换提交的特殊情况

为了只创建一个新的提交来保留提交N的现有 state ,我们需要做的就是使用git reset当前分支名称移回。 请注意,我们想要一个git reset --soft ,它使 Git 的索引和当前工作树 state 不受干扰。 结果是:

          ----------------M--N   [abandoned]
         /               /
...--H--I   <-- master, / feature-1 (HEAD)
         \             /
          J-----K-----L

也就是说,现在两个分支名称 select 现有提交I

我们现在可以运行git commit 这会从 Git 的索引中的任何内容进行新的提交,正如git status应该显示的那样,应该与当前提交匹配:我们将有标记为staged for commit 的文件,并且没有被称为not staged for commit的文件。 (如果我们确实有一些这样的文件,我们可以git add它们。)

这个git commit的一个缺点是我们必须重新构建整个提交消息。 如果这是一个问题,可以先保存其他每条提交消息(例如,将git log重定向到文件)。 与变基方法不同,没有内置的简单方法可以组合现有的提交消息。

最终结果是一个新的提交,原始的一系列提交很难找到; 我们可以像这样绘制一个新的提交:

...--H--I   <-- master
         \
          O   <-- feature-1 (HEAD)

请注意,这仅适用于“进行一次新提交”的情况。 如果您想将两个提交合并为一个,但将其他提交分开,则不能使用此快捷方式。

对于所有变基案例(包括手动挑选“变基”)

git rebase需要的是:

  • 复制 go 的位置的 hash ID:-- --onto master将提供该 ID;
  • 复制的提交的 hash ID。 这是来自非--onto论点。

Git不会复制此提交,也不会通过从此提交开始并向后工作(上图中向左; git log --graph在顶部而不是在右侧绘制一个带有较新提交的图形) git log --graph你会跳过“向下”连接的提交)。

我们需要 Git复制的提交是提交IH ,以及它们之前的所有内容。 所以我们可以提供git rebase ,其 hash ID 为I或名称master

git rebase --onto master master

每当--onto和剩余参数名称相同时,我们实际上不需要--onto ,因此这简化为:

git rebase master

无论是否交互,这种没有-r选项的 rebase 会完全放弃合并提交。 因此,要复制的提交列表将按该顺序为JKLN

如果没有--interactive , Git 将尝试自行复制每个提交。 使用--interactive , Git 会放置一个指令表,然后您可以对其进行编辑,将一些pick更改为squash或其他任何内容。

Git 然后离开指令表:对于每个pick , Git 运行git cherry-pick 对于每个squash , Git 运行git commit --amend一组精心挑选的 arguments。 如果您使用单独git cherry-pick命令自己执行此操作,您可以提前计划并使用-n运行其中一些命令:这会稍微提高计算机效率,但主要是浪费时间,因为计算机资源便宜而人力成本高。

因此,对于这个特定的变基,您所需要的只是与通常所做的相同的交互式变基:但不要尝试计算HEAD~ number的提交,只需使用分支名称master来找到正确的点。 如果你想计算提交,由于合并提交,这很棘手:一条路径上有五个提交,另一条路径有两个提交——只有NM ~走哪条路? (这是学生的另一个练习。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM