如何一次变基多个分支?

问题描述 投票:0回答:6

我目前正在从事一个使用 SVN 作为存储库的项目。在本地,我对不想提交到存储库的代码进行了几次“实验”。因此,我在 SVN 工作目录之上本地使用 git,并使用多个分支进行不同的“实验”。所以它看起来例如像这样。

C0 ---- C7 (master)
 \
  \---- C1 ---- C2 ---- C4 (exp1)
   \     \       \
    \     \       \---- C3 (exp2)
     \     \
      \     \---- C5 (exp3)
       \
        \---- C6 (exp4)

在分支上

master
我想要未受污染的 SVN 存储库,即 C0 是 SVN 存储库修订版 x,C7 是 SVN 存储库修订版 x + n。

是否可以轻松地将所有

exp
分支一次性重新设置到 C7 上,使得树如下图所示?

C0 ---- C7 (master)
         \
          \---- C1' ---- C2' ---- C4' (exp1)
           \     \         \
            \     \         \---- C3' (exp2)
             \     \
              \     \---- C5' (exp3)
               \
                \---- C6' (exp4)

我想使用 rebase,因为我不想修改本地 SVN Checkout 的状态,并且希望将我的更改构建在 SVN 修订之上。

我还对在 SourceTree 内工作而无需使用 shell 的解决方案感兴趣。

git atlassian-sourcetree
6个回答
35
投票

你无法一步获得这一点。最好的情况是你一根一根地移动每个分支;这将是顺序:

git rebase --onto master exp1
git rebase --onto c2' c2 exp2
git rebase --onto c1' c1 exp3
git rebase --onto master exp4

关键是从旧树中的每个分支点(例如上面的 c2)到新树(例如上面的 c2')进行变基。


8
投票

我只想提一下,GoZoner 的序列在第一行(和最后一行)有一个错误。

exp1
不是上游,而是你想要变基的分支。

为了启动序列,您需要将 master 作为上游,即

git rebase --onto master master exp1
或短,没有
--onto
则为
git rebase master exp1
。 问题中示例的总正确序列将是:

git rebase master exp1
git rebase --onto c2' c2 exp2
git rebase --onto c1' c1 exp3
git rebase master exp4

7
投票

正如 GoZoner 回答的那样,无法使用裸 git 命令来执行此操作,但可以通过结合各种 git 管道命令的脚本来支持这种变基。

我写了一个工作示例,你可以在 github 上找到它


6
投票

您可以通过一个小技巧来重新设置多个分支/树的基础。

  1. 创建一个 DUMMY_BRANCH 例如在主人的位置
  2. 合并您想要移入 DUMMY_BRANCH 的所有分支(使用
    --no-ff
    合并)- 更新来自 @kdb@franckspike
  3. 的评论
  4. 将 DUMMY_BRANCH 重新设置为您想要的新点,并将
    --preserve-merges
    选项添加到您的重新设置命令中
  5. 手动变基后,每个人都会分支到变基提交(例如,对于 C4
    git reset --hard [Commit-hash of C4' (exp1)]
  6. 当您移动所有分支后,删除重新定位的 DUMMY_BRANCH

2
投票

这不能直接在 git 中完成,但可以使用 git-assembler 实现自动化。

引用我在https://stackoverflow.com/a/62835799/2792879中的类似答案,这里是指向rebasing本地分支

文档中示例的直接链接

0
投票

自 git v2.44 起,有一个新的实验性功能 git replay 允许使用命令相对轻松地完成此操作(基于您的示例):

git replay --onto C7 C0..exp1 C0..exp2 C0..exp3 C0..exp4 | git update-ref --stdin

甚至还有一个更简单的语法(但我没有成功使用它):

git replay --onto C7 ^C0 exp1 exp2 exp3 exp4 | git update-ref --stdin

备注:

  • 该命令不使用工作目录来操作
  • 因此目前无法处理冲突(即,如果遇到冲突并返回不同于 0 的退出代码,则不执行任何操作)
  • 如果已应用提交,则正在创建空提交
  • replay
    命令不会更新引用,而只是创建 git 对象并在控制台中输出引用更新,需要以适合
    git update-ref --stdin
    的格式完成,从而有效地进行引用更新。
  • 如果检出重播的一个分支,则可能需要同步工作目录。因此,最好有一个干净的工作目录或从另一个签出的分支启动它。
© www.soinside.com 2019 - 2024. All rights reserved.