【问题标题】:git rebase "--preserve-merges --onto" doesn't preserve mergesgit rebase "--preserve-merges --onto" 不保留合并
【发布时间】:2012-03-01 17:58:43
【问题描述】:

使用 git v1.7.1 我正在尝试同时使用 --preserve-merges--onto 功能进行变基。最终结果似乎没有合并提交,因此看起来是线性的。我宁愿保留合并提交,原因与人们经常使用 --preserve-merges 的原因相同(更容易看到在逻辑上是独立功能并在其自己的分支中开发的提交组)。

我的主分支(rebase 的目的地)很无聊:

A-B-C

我要从中获取的功能分支具有已合并到其中的子功能分支。喜欢:

     X - Y
   /      \
V-W ------ Z

其中 Z 是合并提交,它是要从中获取的功能分支的头部,而 X 和 Y 位于子功能分支上。

我正在使用:git rebase --preserve-merges --onto C V Z

我想结束:

         X - Y
        /     \
A-B-C-W ------ Z

但我得到的是:

A-B-C-W-X-Y

由于 Z 是无冲突的合并,因此代码的最终状态是正确的,但历史并没有我想要的那样富有表现力。

有没有办法得到我想要的?

编辑地址@Bombe: 我编写了一个 bash 脚本来构建我的示例。在我的系统(带有 git 1.7.1 的 RHEL 6.2)上,这说明了我的问题。

#! /bin/bash
# start a new empty repo
git init
# make some commits on the master branch
git checkout master
touch A.txt; git add A.txt; git commit -m "add A.txt"; git tag Atag
touch B.txt; git add B.txt; git commit -m "add B.txt"; git tag Btag
touch C.txt; git add C.txt; git commit -m "add C.txt"; git tag Ctag
# now build the feature branch
# start at Btag (more or less arbitrary; point is it's before C)
git checkout Btag
git checkout -b feature
touch V.txt; git add V.txt; git commit -m "add V.txt"; git tag Vtag
touch W.txt; git add W.txt; git commit -m "add W.txt"; git tag Wtag
# now a subfeature
git checkout -b subfeature
touch X.txt; git add X.txt; git commit -m "add X.txt"; git tag Xtag
touch Y.txt; git add Y.txt; git commit -m "add Y.txt"; git tag Ytag
# merge the subfeature into the feature
# preserves branch history with --no-ff
git checkout feature
git merge --no-ff subfeature
# the merge commit is our Z
git tag Ztag
# one more commit so that merge isn't the tip (for better illustration of Z missing later)
touch postZ.txt; git add postZ.txt; git commit -m "add postZ.txt"; git tag postZtag
# now do the rebase
git rebase --preserve-merges --onto Ctag Vtag
# optionally move the master branch forward to the top of feature branch
git checkout master
git merge feature

在我得到变基之前:

        X-Y
       /   \
    V-W-----Z-postZ
   / 
A-B-C

变基后我得到:

        X-Y
       /   \
    V-W-----Z-postZ
   / 
A-B-C-W'-X'-Y'-postZ'

注意 Y' 和 postZ' 之间缺少 Z'。

【问题讨论】:

    标签: git rebase


    【解决方案1】:

    非常感谢 Bombe 和一位离线朋友指出这对某些人确实有效。有了这个灵感,我现在可以回答我自己的问题了。

    简短回答:1.7.5.2 之前的 git 版本会出现这种不良行为。

    长答案:在 git 自己的源代码库中,于 2011 年 4 月 28 日提交 c192f9c865dbdae48c0400d717581d34cd315fb8 明确解决了这个问题。

    引用提交信息(作者 Andrew Wong):

    git-rebase--interactive.sh: preserve-merges fails on merges created with no-ff
    
    'git rebase' uses 'git merge' to preserve merges (-p).  This preserves
    the original merge commit correctly, except when the original merge
    commit was created by 'git merge --no-ff'.  In this case, 'git rebase'
    will fail to preserve the merge, because during 'git rebase', 'git
    merge' will simply fast-forward and skip the commit.  For example:
    
                   B
                  / \
                 A---M
                /
        ---o---O---P---Q
    
    If we try to rebase M onto P, we lose the merge commit and this happens:
    
                     A---B
                    /
        ---o---O---P---Q
    
    To correct this, we simply do a "no fast-forward" on all merge commits
    when rebasing.  Since by the time we decided to do a 'git merge' inside
    'git rebase', it means there was a merge originally, so 'git merge'
    should always create a merge commit regardless of what the merge
    branches look like. This way, when rebase M onto P from the above
    example, we get:
    
                       B
                      / \
                     A---M
                    /
        ---o---O---P---Q
    

    解决方案:获取新版本的 git,如果需要,从源代码构建。

    顺便说一句,我用git bisect 来解决这个问题。很棒的工具。

    【讨论】:

      【解决方案2】:

      我遇到了这个问题。注意我的 git 版本,它是 1.7.10.2。

      我正在将提交范围(由其 SHA1 哈希标识)重新设置到分支上,并且还缺少最后一次合并提交。

      我的解决方案是将 W 重新设置为 X 到 C 上(不使用 --preserve-merges),然后将 Y、Z 和 postZ 重新设置到 X' 上(使用 --preserve-merges)。

      希望这会有所帮助。

      【讨论】:

        【解决方案3】:

        我刚刚尝试重现您的情况,我可以报告--preserve-merges 似乎正在像宣传的那样工作。在提交 Z 时,只需发出:

        git rebase --preserve-merges --onto C V
        

        这就是我所做的,它保留了合并提交。

        【讨论】:

        • 我已经编辑了原始帖子以提供重现我的问题的步骤。我确定你是对的,但我看不出我做错了什么。
        • 而且我确实有一个大于 1.7.5.2 的版本。 :)
        猜你喜欢
        • 2014-02-17
        • 2014-10-29
        • 2021-09-13
        • 2018-03-13
        • 2015-05-12
        • 1970-01-01
        • 2015-10-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多