【问题标题】:How do I rebase a chain of local git branches?如何重新设置本地 git 分支链?
【发布时间】:2014-01-17 01:11:53
【问题描述】:

假设我有一个本地 git 分支链,如下所示:

       master    branch1   branch2
          |         |         |
o----o----o----A----B----C----D

我将上游更改拉入主分支:

              branch1   branch2
                 |         |
            A----B----C----D
           /
o----o----o----o
               |
            master

现在我 rebase branch1,给我这个:

                        branch2
                           |
            A----B----C----D
           /          
o----o----o----o----A'---B'
               |         |
            master    branch1

请注意,由于分支 1 的变基,提交 A 和 B 已被重写为 A' 和 B'。

这是我的问题:现在我想重新设置分支 2。显而易见的语法是git rebase branch1 branch2,但这绝对行不通。我想要它做的只是在 branch1 上重新应用 C 和 D,但它会尝试协调 A 和 A' 并认为它们是冲突的。

这确实有效:

git rebase --onto branch1 branch2^^ branch2

这假设我知道 branch2 在之前的 branch1 ref 之外恰好有 2 次提交。

由于git rebase --onto 有效,是否有一个 1 行 git 命令将在新重新设置的分支 1 之上重新设置分支 2,这样我就不必确切知道分支 2 中有多少提交? (我想为中间参数指定一些魔术 ref 而不是 branch2^^。)

或者还有其他我忽略的方法吗?

我最感兴趣的是一种可以很好地扩展到极端情况的解决方案,而不仅仅是两个分支 - 假设我有更像 5 个本地分支的东西,全部相互链接,我想将所有这些分支重新组合在一起.

【问题讨论】:

  • branch1 基础上重新设置master 时是否有冲突?在一般情况下,git rebase branch1 branch2 会按预期工作,但在某些情况下可能不会,例如,当您在 master 之上重新定位 branch1 时必须解决冲突。

标签: git rebase


【解决方案1】:

单行:

git rebase --onto branch1 branch1tmp branch2

这应该在branch1 上创建一个branch1tmp 之前 重新定位branch1

git checkout branch1
git branch branch1tmp
git rebase master
git rebase --onto branch1 branch1tmp branch2

话虽如此,请检查 ORIG_HEAD 引用的内容。
来自git rebase man page

ORIG_HEAD 设置为在重置之前指向分支的尖端。

所以检查一下这是否可行(并更好地扩展):

git checkout branch1
git rebase master
git rebase --onto branch1 ORIG_HEAD branch2
git rebase --onto branch2 ORIG_HEAD branch3
...

【讨论】:

  • 谢谢! ORIG_HEAD 看起来是最自然的方式。
【解决方案2】:
git rebase master branch1
git rebase --onto HEAD ORIG_HEAD branch2
git rebase --onto HEAD ORIG_HEAD branch3
# ...
git rebase --onto HEAD ORIG_HEAD branchN

我有一个 git 别名脚本来执行此操作:

rebase-chain = "!f() { \
  for i in ${@}; do \
    git rebase --onto HEAD ORIG_HEAD $i; \
  done; \
}; f"

这可以使工作流程如下:

git rebase master branch1 # start with a normal rebase
git rebase-chain branch2 branch3 branch4 ... branchN

奖金

假设您有bash-completion 对应git

__git_complete "git rebase-chain" _git_branch

【讨论】:

  • 有趣的别名脚本。 +1
【解决方案3】:

这个问题是Modify base branch and rebase all children at once的一个子集

我最近开始使用git-chain,这是一个解决这个问题的工具。

基本上你指定一个链

git chain setup -c myfeature master branch1 branch2

一旦这条链建立起来,你就可以从master 拉取提交,然后你可以运行git chain rebase -c myfeature,该工具会为你计算出所有的引用并重新调整所有内容。

作为一个额外的好处,它还可以计算和处理对branch1branch2 的任何修改或新提交。

【讨论】:

    【解决方案4】:

    我希望git checkout branch2 ; git rebase -i master 直接在编辑器中向我显示branch1,然后当我保存编辑器时,branch1 会相应更新。所以我可以直接在git rebase -i 中将提交从branch2 移动到branch1 并拥有那个“棒”。也许带有“--rebase-branches”之类的东西。

    所以啊,我分担你的痛苦。

    我所做的就是模仿这个缺失的功能的 hack。我经常发现,在创建长寿分支的过程中,我不断积累应该在“这个”分支之前进入 master 的东西。修复编码标准违规,发现和修复明显错误,现有代码的文档更新等。这就是我使用您的branch1 的目的。然后实际上是我的新功能一部分的提交进入branch2

    所以我要做的不是创建branch1 分支,而是创建一个branch1 伪分支“标记” - 稍后我将使用git rebase 丢弃它的微小提交。我像这样创建它:

    touch marker.master
    git add marker.branch1
    git commit -m "*** BRANCH1 ***" marker.branch1
    

    现在,当我创建提交时,我混合了应该在这个分支之前进入 master 的提交和这个实际分支的“新”提交。

    到了清理/变基的时候,我git rebase -i master。现在我的*** BRANCH1 *** 提交在提交列表中很明显,我可以将发往branch1 的提交移到该“行”上方。

    因为我没有实际的branch1 分支,所以git rebase master 完全符合我的要求,它将branch2 和我的branch1 伪分支标记作为一个单元移动。

    当我完成变基并准备推送时,我手动记下*** BRANCH1 *** 的提交 ID,比如abcdef1,然后:

    git checkout -b branch1 abcdef1^
    

    然后:

    git checkout branch2
    git rebase -i branch1
    

    并删除 abcdef1 提交。

    这样我可以在git rebase -i 期间轻松地在我的branch1branch2 分支之间移动提交,并且只在最后实际创建一个真正的git branch1 分支。

    但是哦,我真的很希望 git rebase -i 为我做这件事!

    【讨论】:

      【解决方案5】:

      git-branchless 工具套件可以巧妙地解决这个问题:

      $ git move -s A -d master
      

      免责声明:我是作者。

      这将变基A,以及它的所有后代,以及指向任何这些提交的任何分支。请参阅documentation for git move

      【讨论】:

        猜你喜欢
        • 2022-01-09
        • 1970-01-01
        • 2011-09-29
        • 1970-01-01
        • 2015-04-02
        相关资源
        最近更新 更多