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;DR
只需使用git rebase --interactive master
。原因见下文。
编辑:我没有注意到,在主题行中,您只想获得 一个 提交,这意味着还有一种方法。
多头
您有多种选择。如果有的话,你有太多选项:
- 您可以创建一个新分支,一次选择一个提交。
- 您可以创建一个新分支并使用
-n
挑选提交,以便它们被预先压缩。
- 您可以使用
git rebase -i
并使用 --onto
. 小心地将“提交到 cherry pick 的内容”部分与“放置副本的位置”部分分开
- 您可以使用
git rebase -i
而无需那种小心,并删除无关的 pick
命令,如果有的话(但这里不会)。
- 或者,要将所有内容变成 单个 提交,请使用
git reset --soft
和 git commit
。
请注意,这些选项中的前四个最终以相同的方式工作,所以这实际上只是个人喜好的问题。无论您使用哪种方法,都不会复制现有的合并。事实上,变基 不能 复制合并,尽管新奇的 --rebase-merges
(-r
) 选项将提供/声称这样做。它没有:它只是 运行s git merge
再次进行 new 合并。如果你想自己做,你可以在使用前两种(手动模式,手动操作的 cherry-pick)方法时自己做。
让我们从您所拥有的绘图开始:
----------------M--N <-- feature-1 (HEAD)
/ /
...--H--I <-- master /
\ /
J-----K-----L
大写字母代表提交哈希 ID。 名称 feature-1
是您的 当前分支名称 ,如括号中所附的 HEAD
所示,并提交 N
是您的 当前提交 ,即主题行为 Adding last minute request from QA
.
的提交
(练习:以更简单的方式重新绘制此图。在纸上或白板上,它可以非常简单。不过,请检查您是否在 master
上提交了我没有绘制的内容。如果您确实有这样的提交,请尝试所有这些。)
您需要在提交 I
之后构建一些新的提交系列——提交 I
是 last 在 [=30 上的提交=]—使用现有提交 J-K-L
和 N
的内容,但不使用 M
的内容,因为我们计划完全放弃合并。
对于单个替换提交的特殊情况
要使 仅保留提交 N
的现有状态的新提交,我们需要做的就是使用 git reset
移动 当前分支名称返回。请注意,我们想要一个 git reset --soft
,它使 Git 的索引和当前工作树状态都不受干扰。结果是:
----------------M--N [abandoned]
/ /
...--H--I <-- master, / feature-1 (HEAD)
\ /
J-----K-----L
也就是说,现在两个分支名称 select 现有提交 I
.
我们现在可以 运行 git commit
。这会根据 Git 索引中的任何内容进行新提交,正如 git status
应该显示的那样 - 应该与 当前提交相匹配: 我们将有文件标记为 已暂存提交 ,并且没有正在调用的文件 未暂存提交 。 (如果我们确实有一些这样的文件,如果需要,我们可以 git add
它们。)
此 git commit
的一个缺点是我们必须重新构建整个提交消息。如果这是一个问题,可以先保存每个其他提交消息(例如,git log
重定向到一个文件)。但是,与变基方法不同,没有内置的简单方法来组合现有的提交消息。
最终结果是一个新的提交,原来的一系列提交很难找到;我们可以像这样绘制一个新的提交:
...--H--I <-- master
\
O <-- feature-1 (HEAD)
请注意,这仅适用于“进行一次新提交”的情况。如果您想将两个提交合并为一个,但将其他提交分开,则不能使用此快捷方式。
对于所有变基案例(包括手动选择“变基”)
git rebase
需要的是:
- 副本所在位置的哈希 ID:
--onto master
将提供;和
- 提交的哈希 ID 不 复制。这是来自非
--onto
论点。
Git 将 不会 复制此提交,也不会从此提交开始并向后工作(向左,在上图中;git log --graph
绘制了一个图表,其中较新的提交位于顶部,而不是右侧,因此使用 git log --graph
您将跳过“向下”连接的提交。
我们需要 Git 而不是 复制的提交是提交 I
、H
以及它们之前的所有内容。所以我们可以为 git rebase
提供哈希 ID I
,或者名称 master
:
git rebase --onto master master
每当 --onto
和剩余的参数名称 相同的提交 ,我们实际上并不需要 --onto
,所以这简化为:
git rebase master
无论是否交互,这种变基——没有 -r
选项——drops 完全合并提交。因此,要复制的提交列表将依次为 J
、K
、L
和 N
。
如果没有 --interactive
,Git 将尝试自己复制每个提交。使用 --interactive
,Git 提出一条指令 sheet,然后您可以对其进行编辑,将一些 pick
更改为 squash
或其他内容。
Git 然后关闭指令 sheet:对于每个 pick
,Git 运行s git cherry-pick
。对于每个 squash
、Git 运行 一个 git commit --amend
和一个精心选择的参数集。如果你自己使用单独的 git cherry-pick
命令来执行此操作,你可以提前计划并 运行 其中一些使用 -n
:这稍微提高了计算机效率,但主要是浪费时间,因为计算机资源很便宜,人力很贵。
所以,对于这个特殊的变基,你所需要的只是你通常会做的相同的交互式变基:而不是试图计算HEAD的提交~ <em>数</em>
,直接用分支名master
找对点就行了。如果你想计算提交,这很棘手,因为合并提交:有五个提交一个路径,两个 提交 - 只是 N
和 M
- 另一个。 ~
走哪条路? (这是学生的另一项练习。)
我在 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;DR
只需使用git rebase --interactive master
。原因见下文。
编辑:我没有注意到,在主题行中,您只想获得 一个 提交,这意味着还有一种方法。
多头
您有多种选择。如果有的话,你有太多选项:
- 您可以创建一个新分支,一次选择一个提交。
- 您可以创建一个新分支并使用
-n
挑选提交,以便它们被预先压缩。 - 您可以使用
git rebase -i
并使用--onto
. 小心地将“提交到 cherry pick 的内容”部分与“放置副本的位置”部分分开
- 您可以使用
git rebase -i
而无需那种小心,并删除无关的pick
命令,如果有的话(但这里不会)。 - 或者,要将所有内容变成 单个 提交,请使用
git reset --soft
和git commit
。
请注意,这些选项中的前四个最终以相同的方式工作,所以这实际上只是个人喜好的问题。无论您使用哪种方法,都不会复制现有的合并。事实上,变基 不能 复制合并,尽管新奇的 --rebase-merges
(-r
) 选项将提供/声称这样做。它没有:它只是 运行s git merge
再次进行 new 合并。如果你想自己做,你可以在使用前两种(手动模式,手动操作的 cherry-pick)方法时自己做。
让我们从您所拥有的绘图开始:
----------------M--N <-- feature-1 (HEAD)
/ /
...--H--I <-- master /
\ /
J-----K-----L
大写字母代表提交哈希 ID。 名称 feature-1
是您的 当前分支名称 ,如括号中所附的 HEAD
所示,并提交 N
是您的 当前提交 ,即主题行为 Adding last minute request from QA
.
(练习:以更简单的方式重新绘制此图。在纸上或白板上,它可以非常简单。不过,请检查您是否在 master
上提交了我没有绘制的内容。如果您确实有这样的提交,请尝试所有这些。)
您需要在提交 I
之后构建一些新的提交系列——提交 I
是 last 在 [=30 上的提交=]—使用现有提交 J-K-L
和 N
的内容,但不使用 M
的内容,因为我们计划完全放弃合并。
对于单个替换提交的特殊情况
要使 仅保留提交 N
的现有状态的新提交,我们需要做的就是使用 git reset
移动 当前分支名称返回。请注意,我们想要一个 git reset --soft
,它使 Git 的索引和当前工作树状态都不受干扰。结果是:
----------------M--N [abandoned]
/ /
...--H--I <-- master, / feature-1 (HEAD)
\ /
J-----K-----L
也就是说,现在两个分支名称 select 现有提交 I
.
我们现在可以 运行 git commit
。这会根据 Git 索引中的任何内容进行新提交,正如 git status
应该显示的那样 - 应该与 当前提交相匹配: 我们将有文件标记为 已暂存提交 ,并且没有正在调用的文件 未暂存提交 。 (如果我们确实有一些这样的文件,如果需要,我们可以 git add
它们。)
此 git commit
的一个缺点是我们必须重新构建整个提交消息。如果这是一个问题,可以先保存每个其他提交消息(例如,git log
重定向到一个文件)。但是,与变基方法不同,没有内置的简单方法来组合现有的提交消息。
最终结果是一个新的提交,原来的一系列提交很难找到;我们可以像这样绘制一个新的提交:
...--H--I <-- master
\
O <-- feature-1 (HEAD)
请注意,这仅适用于“进行一次新提交”的情况。如果您想将两个提交合并为一个,但将其他提交分开,则不能使用此快捷方式。
对于所有变基案例(包括手动选择“变基”)
git rebase
需要的是:
- 副本所在位置的哈希 ID:
--onto master
将提供;和 - 提交的哈希 ID 不 复制。这是来自非
--onto
论点。
Git 将 不会 复制此提交,也不会从此提交开始并向后工作(向左,在上图中;git log --graph
绘制了一个图表,其中较新的提交位于顶部,而不是右侧,因此使用 git log --graph
您将跳过“向下”连接的提交。
我们需要 Git 而不是 复制的提交是提交 I
、H
以及它们之前的所有内容。所以我们可以为 git rebase
提供哈希 ID I
,或者名称 master
:
git rebase --onto master master
每当 --onto
和剩余的参数名称 相同的提交 ,我们实际上并不需要 --onto
,所以这简化为:
git rebase master
无论是否交互,这种变基——没有 -r
选项——drops 完全合并提交。因此,要复制的提交列表将依次为 J
、K
、L
和 N
。
如果没有 --interactive
,Git 将尝试自己复制每个提交。使用 --interactive
,Git 提出一条指令 sheet,然后您可以对其进行编辑,将一些 pick
更改为 squash
或其他内容。
Git 然后关闭指令 sheet:对于每个 pick
,Git 运行s git cherry-pick
。对于每个 squash
、Git 运行 一个 git commit --amend
和一个精心选择的参数集。如果你自己使用单独的 git cherry-pick
命令来执行此操作,你可以提前计划并 运行 其中一些使用 -n
:这稍微提高了计算机效率,但主要是浪费时间,因为计算机资源很便宜,人力很贵。
所以,对于这个特殊的变基,你所需要的只是你通常会做的相同的交互式变基:而不是试图计算HEAD的提交~ <em>数</em>
,直接用分支名master
找对点就行了。如果你想计算提交,这很棘手,因为合并提交:有五个提交一个路径,两个 提交 - 只是 N
和 M
- 另一个。 ~
走哪条路? (这是学生的另一项练习。)