Rebase 一个合并的分支
Rebase a merged branch
我在 git 回购中有如下分支。
_d_e_f__(branch A)
(Master)_a_b_c__/
\_g_h_i__
(branch B)
之后,从 A 创建一个新的分支 C,并将 B 合并到 C git checkout A && git checkout -b C && git merge B
_d_e_f__(branch A)
(Master)_a_b_c__/ \__________(branch C)
\_g_h_i__/
(branch B)
现在,假设主分支添加了一个新提交,我想将所有分支(A、B、C)变基到主分支中的新提交。这样做的正确方法是什么?我尝试了以下方法,一切正常,除了当我检查图表时,但是,从分支 B 到 C 的合并在变基后似乎没有集成。
git checkout A
git rebase master
git checkout B
git rebase master
git checkout C
git rebase --onto A f
从图表中我可以看出,一个分离的提交(m)是为将B合并到C而创建的。
_m__C
A___/
master_____/
\B
TL;DR:Consider using Graphite。我自己没有使用过 Graphite,但请阅读下面的文字,看看它是否符合您的目标,然后查看链接的项目,可能 是一种开箱即用的方法这个。
您可以使用 (1) 新奇的 --rebase-merges
选项和 (2) 随后的分支名称更新来实现您的目标。 这取决于您的最终目标,在我撰写此答案时,根据您的问题,我并不完全清楚这个目标。
执行此操作的命令序列为:
git checkout branch-C
git rebase --rebase-merges master
git log --graph # to find hash IDs below
git branch -f master <hash1>
git branch -f branch-A <hash2>
git branch -f branch-B <hash3>
只有 运行ning git log
在 git rebase --rebase-merges
完成后才能发现这两个哈希 ID。
这里有几点需要注意:
Rebase 通过 复制 提交来工作,就像 git cherry-pick
一样。 (--rebase-merges
确实在内部使用 git cherry-pick
的变基类型;其他一些人有时会使用替代命令,这些命令可能 运行 更快,但在某些情况下效果不佳。)
每个复制的提交都与每个原始提交“做同样的事情”,并重新使用其原始提交的日志消息,但有一个新的、不同的哈希 ID。
cherry-pick 命令不能 复制合并提交,因此--rebase-merges
选项甚至不会尝试这样做。相反,将作为输入的提交复制到原始合并后,rebase-merges 代码 运行 是一个全新的 git merge
命令来创建新的合并。
因为这是一个全新的合并,所以在 原始 合并期间采取的任何特殊操作都将丢失。当且仅当您启用了 git rerere
时,才会保留以前的冲突解决方案(Git 的即将发布的版本就是这种情况,但大多数现有版本和旧版本都不是这种情况)。您使用的任何特殊标志,例如 -X ours
或 -X theirs
,都将丢失。
这意味着我们开始说:
D-----E-----F <-- branch-A
/ \
A--B--C <-- master M--N--O <-- branch-C (HEAD)
\ /
G-----H-----I <-- branch-B
其中 branch-A 指向提交 F
,branch-C
指向提交 O
,branch-B
指向提交 I
,master
指向提交 C
.
我们check out branch-C
在开始rebase之前,使用--rebase-merges
,这样Git会产生一组指令列表要复制/合并的提交。这套说明是这样写的:
- 移至
C
作为独立 HEAD。
- 复制
D
、E
和 F
。
- 保存新副本的哈希 ID
F'
。
- Return 到起点
C
.
- 复制
G
、H
和 I
。
- 保存新副本的哈希 ID
I'
。
- 检查
F'
并执行 I'
的合并(使 M'
)。
- 复制
N
、O
和 P
。
有一个隐含的最终指令将名称 branch-C
移动到指向此处所做的最后一次提交。1 如果您将 --interactive
添加到此变基,您将看到说明 sheet 的文本版本,Git 将允许您对其进行编辑。如果不是,Git 就开始工作,使用指令 sheet,即使没有 --interactive
它也会生成和解释该指令,因为 rebase 可能 停止在中间。如果是这样,您可能稍后会恢复它,为此它需要保存这些说明。 (rebase 还保留了一个 运行ning“已经完成的事情和接下来要做的事情”,以配合待办事项说明;这里的确切机制取决于 rebase 代码,并且随着时间的推移而改变。)
如果一切顺利,在所有指令——包括最终和隐含的“移动分支名称”步骤——执行后的最终结果是:
D-----E-----F <-- branch-A
/ \
C <-- master M--N--O ???
/ \ /
| G-----H-----I <-- branch-B
/
A--B
\
| D'----E'----F'
\ / \
C' M'-N'-O' <-- branch-C (HEAD)
\ /
G'----H'----I'
也就是说,这个git rebase --rebase-merges
已经完成所有需要的复制,因为master
、branch-A
和branch-B
只需要在复制完成后指向提交C'
、F'
和I'
即可。
不幸的是,Git 本身并没有内置任何东西来处理所有这些。 Graphite 可能。
1我在写这篇文章的时候突然想到,最好把它作为一个明确的说明。这仍然可以在将来完成 Git.
我在 git 回购中有如下分支。
_d_e_f__(branch A)
(Master)_a_b_c__/
\_g_h_i__
(branch B)
之后,从 A 创建一个新的分支 C,并将 B 合并到 C git checkout A && git checkout -b C && git merge B
_d_e_f__(branch A)
(Master)_a_b_c__/ \__________(branch C)
\_g_h_i__/
(branch B)
现在,假设主分支添加了一个新提交,我想将所有分支(A、B、C)变基到主分支中的新提交。这样做的正确方法是什么?我尝试了以下方法,一切正常,除了当我检查图表时,但是,从分支 B 到 C 的合并在变基后似乎没有集成。
git checkout A
git rebase master
git checkout B
git rebase master
git checkout C
git rebase --onto A f
从图表中我可以看出,一个分离的提交(m)是为将B合并到C而创建的。
_m__C
A___/
master_____/
\B
TL;DR:Consider using Graphite。我自己没有使用过 Graphite,但请阅读下面的文字,看看它是否符合您的目标,然后查看链接的项目,可能 是一种开箱即用的方法这个。
您可以使用 (1) 新奇的 --rebase-merges
选项和 (2) 随后的分支名称更新来实现您的目标。 这取决于您的最终目标,在我撰写此答案时,根据您的问题,我并不完全清楚这个目标。
执行此操作的命令序列为:
git checkout branch-C
git rebase --rebase-merges master
git log --graph # to find hash IDs below
git branch -f master <hash1>
git branch -f branch-A <hash2>
git branch -f branch-B <hash3>
只有 运行ning git log
在 git rebase --rebase-merges
完成后才能发现这两个哈希 ID。
这里有几点需要注意:
Rebase 通过 复制 提交来工作,就像
git cherry-pick
一样。 (--rebase-merges
确实在内部使用git cherry-pick
的变基类型;其他一些人有时会使用替代命令,这些命令可能 运行 更快,但在某些情况下效果不佳。)每个复制的提交都与每个原始提交“做同样的事情”,并重新使用其原始提交的日志消息,但有一个新的、不同的哈希 ID。
cherry-pick 命令不能 复制合并提交,因此
--rebase-merges
选项甚至不会尝试这样做。相反,将作为输入的提交复制到原始合并后,rebase-merges 代码 运行 是一个全新的git merge
命令来创建新的合并。因为这是一个全新的合并,所以在 原始 合并期间采取的任何特殊操作都将丢失。当且仅当您启用了
git rerere
时,才会保留以前的冲突解决方案(Git 的即将发布的版本就是这种情况,但大多数现有版本和旧版本都不是这种情况)。您使用的任何特殊标志,例如-X ours
或-X theirs
,都将丢失。
这意味着我们开始说:
D-----E-----F <-- branch-A
/ \
A--B--C <-- master M--N--O <-- branch-C (HEAD)
\ /
G-----H-----I <-- branch-B
其中 branch-A 指向提交 F
,branch-C
指向提交 O
,branch-B
指向提交 I
,master
指向提交 C
.
我们check out branch-C
在开始rebase之前,使用--rebase-merges
,这样Git会产生一组指令列表要复制/合并的提交。这套说明是这样写的:
- 移至
C
作为独立 HEAD。 - 复制
D
、E
和F
。 - 保存新副本的哈希 ID
F'
。 - Return 到起点
C
. - 复制
G
、H
和I
。 - 保存新副本的哈希 ID
I'
。 - 检查
F'
并执行I'
的合并(使M'
)。 - 复制
N
、O
和P
。
有一个隐含的最终指令将名称 branch-C
移动到指向此处所做的最后一次提交。1 如果您将 --interactive
添加到此变基,您将看到说明 sheet 的文本版本,Git 将允许您对其进行编辑。如果不是,Git 就开始工作,使用指令 sheet,即使没有 --interactive
它也会生成和解释该指令,因为 rebase 可能 停止在中间。如果是这样,您可能稍后会恢复它,为此它需要保存这些说明。 (rebase 还保留了一个 运行ning“已经完成的事情和接下来要做的事情”,以配合待办事项说明;这里的确切机制取决于 rebase 代码,并且随着时间的推移而改变。)
如果一切顺利,在所有指令——包括最终和隐含的“移动分支名称”步骤——执行后的最终结果是:
D-----E-----F <-- branch-A
/ \
C <-- master M--N--O ???
/ \ /
| G-----H-----I <-- branch-B
/
A--B
\
| D'----E'----F'
\ / \
C' M'-N'-O' <-- branch-C (HEAD)
\ /
G'----H'----I'
也就是说,这个git rebase --rebase-merges
已经完成所有需要的复制,因为master
、branch-A
和branch-B
只需要在复制完成后指向提交C'
、F'
和I'
即可。
不幸的是,Git 本身并没有内置任何东西来处理所有这些。 Graphite 可能。
1我在写这篇文章的时候突然想到,最好把它作为一个明确的说明。这仍然可以在将来完成 Git.