git rebase“ - preserve-merges --onto”不保留合并 [英] git rebase "--preserve-merges --onto" doesn't preserve merges

查看:788
本文介绍了git rebase“ - preserve-merges --onto”不保留合并的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

ABC



我想从中获取的特性分支具有已合并到其中的子特性分支。像:

  X  -  Y 
/ \
VW ------ Z

其中Z是一个合并提交,它是要从中提取的特征分支的头部,而X和Y是在一个子功能分支上。



我正在使用: git rebase --preserve-merges --onto CVZ



我想结束:

  X -  Y 
/ \
ABCW ------ Z

但是,我得到了:

  ABCWXY 

因为Z是无冲突的合并,所以代码的最终状态是正确的,但是历史并不像我想的那样富有表现力。



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

编辑到地址@Bombe
I已经写了一个bash脚本来构建我的例子。在我的系统(RHEL 6.2 with git 1.7.1)中,这证明了我的问题。

 #! / bin / bash 
#启动一个新的空回购
git init
#在master分支上进行一些提交
git checkout master
touch A.txt; git add A.txt; git commit -madd A.txt; git tag Atag
touch B.txt; git add B.txt; git commit -madd B.txt; git tag Btag
touch C.txt; git add C.txt; git commit -madd C.txt; git tag Ctag
#现在构建功能分支
#开始于Btag(或多或少是任意的;点是它在C之前)
git checkout Btag
git checkout -b功能
touch V.txt; git add V.txt; git commit -madd V.txt; git tag Vtag
touch W.txt; git add W.txt; git commit -madd W.txt; git标签Wtag
#现在是子功能
git checkout -b子功能
touch X.txt; git add X.txt; git commit -madd X.txt; git标签Xtag
touch Y.txt; git add Y.txt; git commit -madd Y.txt; git tag Ytag
#将子功能合并到功能中
#保留分支历史记录--no-ff
git结帐功能
git合并--no-ff子功能
#合并提交是我们的Z
git标签Ztag
#多一个提交,以便合并不是提示(为了更好地说明Z丢失后)
touch postZ.txt; git add postZ.txt; git commit -madd postZ.txt; git tag postZtag
#现在执行rebase
git rebase --preserve-merges --onto Ctag Vtag
#可选地将主分支转移到功能分支的顶部
git checkout master
git合并功能

在获得rebase之前:

  XY 
/ \
VW ----- Z-postZ
/
ABC

我得到rebase后:

  XY 
/ \
VW ----- Z-postZ
/
ABC-W'-X'-Y'-postZ '

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

解决方案

非常感谢Bombe和一位离线朋友指出这对一些人有用。有了这种灵感,我现在能够回答我自己的问题。



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



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



引用提交信息(Andrew Wong):


  git-rebase--interactive.sh:保留合并在使用no-ff创建的合并时失败

'git rebase'使用'git merge'来保存合并(-p)。这保留了
正确的原始合并提交,除非原始合并
提交由'git merge --no-ff'创建。在这种情况下,'git rebase'
将无法保留合并,因为在'git rebase'期间,'git
merge'将简单地快进并跳过提交。例如:

B
/ \
A --- M
/
--- o --- O --- P- --Q

如果我们试图将M重定向到P,我们会失去合并提交,并发生这种情况:

A --- B
/
--- o --- O --- P --- Q

为了纠正这个问题,我们简单地对所有合并提交
进行不快进处理。因为当我们决定在
'git rebase'内部做一个'git merge'时,这意味着最初有一个合并,所以'git merge'
应该总是创建一个合并提交,而不管合并
分行的样子。这样,当从上面的
例子中将数据库转换为P时,我们得到:

B
/ \
A --- M
/
--- o --- O --- P --- Q


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

btw我用 git bisect 来解决这个问题。真棒工具。


Using git v1.7.1 I'm trying to do a rebase with both the --preserve-merges and --onto features at the same time. The end results seems to be without the merge commits, and so appears linear. I'd rather preserve the merge commits, for the same reason that people would often use --preserve-merges (easier to see the group of commits that was logically a separate feature and developed in its own branch).

My master branch (the destination for the rebase) is boring:

A-B-C

The feature branch I want to take from has a sub-feature branch that has been merged into it. Like:

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

Where Z is a merge commit that is the head of the feature branch to take from, and X and Y were on a sub-feature branch.

I'm using: git rebase --preserve-merges --onto C V Z

I'd like to end up with:

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

But instead I'm getting:

A-B-C-W-X-Y

Since Z was a conflict-free merge, the final state of the code is correct, but the history isn't as expressive as I would like.

Is there a way to get what I want?

edit to address @Bombe: I've written a bash script to construct my example. On my system (RHEL 6.2 with git 1.7.1) this demonstrates my problem.

#! /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

Before the rebase I get:

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

After the rebase I get:

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

Note the lack of Z' between Y' and postZ'.

解决方案

Many thanks to Bombe and an offline friend for pointing out that is does work for some people. With that inspiration, I am now able to answer my own question.

Short answer: git versions before 1.7.5.2 will exhibit this bad behavior.

Long answer: in git's own source repo, commit c192f9c865dbdae48c0400d717581d34cd315fb8 on Apr 28th 2011 was explicitly a fix for this problem.

To quote the commit message (by 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

Solution: get a new version of git, building from source if needed.

Btw, I used git bisect to figure this out. Awesome tool.

这篇关于git rebase“ - preserve-merges --onto”不保留合并的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆