假设我有以下场景:
o (master)
/ o--o (WIP1)
/ /
o--o--o--o--o--o (WIP2)
(X) \
o--o (WIP3)
是否有一个 git 命令创建一个新分支,以便它包含分支 X 之后的子树?我想执行“大型变基”,我希望三个 WIP 分支基于 master。
我知道我可以通过一些 Bash 脚本来做到这一点,但我想知道如何使用 git 命令来做到这一点。
我已将此问题标记为重复。我会写下我解释 的另一个答案,但使用你的例子。
我用于此类用例的方法是将所有要移动的分支合并到 1 个公共人工节点中,然后使用带有--preserve-merges
选项的 rebase 命令。合并所有分支将公开 1 个端点,该端点将用作rebase --onto
. 起点通常很明显,要移动的子树的原点。
合并以获取子树端点时,应明确避免冲突。因此,应指示合并命令使用-Xours
选项自动解决它们。合并结果并不重要,因为这些人为的合并节点将在 rebase 之后被丢弃。
建议创建一个新的分支包,以免丢失原始引用。在上面的示例中,将执行以下命令:
$ git checkout -b pack WIP1 # create new branch at 'WIP1'
$ git merge -s recursive -Xours WIP2 # merges WIP2 into pack (node p2)
$ git merge -s recursive -Xours WIP3 # merges WIP3 into pack
下面可以看到树会变成什么。通过合并创建了两个新的人工节点 p2和pack 。
o (master)
/
/ (WIP1) (p2)
/ o-----o-----o----o (pack)
/ / / /
o--o--o--o-----o-----o / (WIP2)
(X) \ /
o------------o (WIP3)
现在是时候重新设置基准了。由于现在所有分支( pack )都有一个公共端点,因此很容易移动整个子树:
$ git rebase --preserve-merges --onto master X pack
产生这个:
(WIP1') (p2')
o-----o-----o----o (pack')
(master) / / /
o----o----o--o--o-----o-----o / (WIP2')
(X) \ /
o------------o (WIP3')
现在是时候重新排列参考了。我不知道为什么,在某些情况下引用被移动,而在其他情况下则没有。为每个参考 WIP1、WIP2、WIP3 或您需要的任何内容键入此内容:
$ git checkout WIP1
$ git reset --hard <WIP1' hash>
最后,摆脱为生成公共子树末端节点而创建的人工提交。
$ git branch -D pack
$ git branch -D p2 # if there is any
所以最终的树是:
(WIP1')
o-----o
(master) /
o----o----o--o--o-----o-----o (WIP2')
(X) \
o------------o (WIP3')
o (master)
/ o--o (WIP1)
/ /
o--p--p--o--o--o (WIP2)
(X) (Y)
\
o--o (WIP3)
这应该是一个(您可以在“如何将某些提交移动到 git 中的另一个分支?rebase --onto
”中看到一个示例):
git rebase --onto master X WIP1
git rebase --onto master X WIP2
git rebase --onto master X WIP3
p'--p'--o--o (WIP2)
/
o-----o-----p--p--o--o--o (WIP1)
(X) (master) (Y')
\
p''--p''--o--o (WIP3)
所以第一次变基是可以的,但是你需要得到 Y SHA,并且:
git rebase --onto Y' Y WIP2
git rebase --onto Y' Y WIP3
使用git-branchless
这套工具,您可以直接变基子树:
$ git move -b WIP1 -d master
免责声明:我是作者。
如果您想坚持使用基本 Git,您可以使用此答案中的方法,但使用新--rebase-merges
选项。做一个虚拟的合并提交:
$ git checkout WIP1
$ git merge WIP2 WIP3
...add all conflicts and resolve...
然后以交互方式执行变基。生成的变基计划将是您想要的,除了您应该删除最后一个merge
命令:
$ git rebase -i master --rebase-merges
...example editor contents below...
label onto
# Branch WIP1
reset abc123
pick abc456
pick abc789
label abcdef
reset onto
pick bcd123
pick bcd456
pick bcd789
## REMOVE THIS LINE:
# merge -C abcdef