[英]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 ,它使事情复杂化了。 我在这里有什么选择吗?
只需使用git rebase --interactive master
。 原因见下文。
编辑:我没有注意到,在主题行中,您只想获得一次提交,这意味着还有另一种方法。
您有多种选择。 如果有的话,你有太多的选择:
-n
创建一个新分支并挑选提交,以便它们被预先压缩。git rebase -i
并使用 --onto 小心地将“提交樱桃的内容”部分与“放置副本的位置”部分--onto
。git rebase -i
而无需那种小心,并删除无关的pick
命令,如果有的话(但这里不会有)。git reset --soft
和git 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
之后构建一些新的提交系列——提交I
是master
上的最后一个提交——通过使用现有提交JKL
和N
的内容,而不是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
需要的是:
--onto master
将提供该 ID; 和--onto
论点。 Git不会复制此提交,也不会通过从此提交开始并向后工作(上图中向左; git log --graph
在顶部而不是在右侧绘制一个带有较新提交的图形) git log --graph
你会跳过“向下”连接的提交)。
我们需要 Git不复制的提交是提交I
, H
,以及它们之前的所有内容。 所以我们可以提供git rebase
,其 hash ID 为I
或名称master
:
git rebase --onto master master
每当--onto
和剩余参数名称相同时,我们实际上不需要--onto
,因此这简化为:
git rebase master
无论是否交互,这种没有-r
选项的 rebase 会完全放弃合并提交。 因此,要复制的提交列表将按该顺序为J
、 K
、 L
和N
。
如果没有--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
来找到正确的点。 如果你想计算提交,由于合并提交,这很棘手:一条路径上有五个提交,另一条路径有两个提交——只有N
和M
~
走哪条路? (这是学生的另一个练习。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.