git:为什么我不能在壁球合并后删除我的分支?

时间:2017-01-30 22:24:06

标签: git merge git-merge

我有一个带master(相当于$ git branch * mainline feature1 feature2 feature3 )和一些本地功能分支的git仓库。例如:

mainline

当我执行以下操作时,我能够将功能分支中的所有编辑内容合并到$ git checkout mainline $ git pull $ git checkout feature1 $ git rebase mainline $ git checkout mainline $ git merge --squash feature1 $ git commit $ git push 的一个提交中:

feature1

我的问题是,此时,当我尝试删除$ git branch -d feature1 error: The branch 'feature1' is not fully merged. If you are sure you want to delete it, run 'git branch -D feature1'. 分支时,它告诉我它没有完全合并:

git merge --squash feature1

导致此错误的原因是什么?我认为feature1mainline合并到{{1}}。

2 个答案:

答案 0 :(得分:34)

这是因为Git不知道squash merge是“等同于”各种特定于分支的提交。您必须使用git branch -D而不是git branch -d强制删除分支。

(其余部分只是为什么就是这种情况。)

绘制提交图

让我们绘制(部分)提交图(这一步适用于Git中的许多内容......)。事实上,让我们再退一步,以便我们在你的git rebase之前开始,有这样的事情:

...--o--o--o     <-- mainline
      \
       A--B--C   <-- feature1

分支名称,如mainlinefeature1,仅指向一个特定提交。该提交指向(向左)到先前的提交,依此类推,这是形成实际分支的这些向后指针。

提交的最上一行,在这里所谓的o都有点无聊,所以我们没有给他们字母。提交的最后一行A-B-C仅在分支feature1 C是最新的提交;它返回B,返回A,返回到无聊的o提交之一。 (顺便说一下:最左边的o提交以及...部分中的所有早期提交都位于两个分支上。)

当您运行git rebase时,三个A-B-C提交被复制提交附加到mainline的提示,给我们:

...--o--o--o            <-- mainline
      \     \
       \     A'-B'-C'   <-- feature1
        \
         A--B--C       [old feature1, now abandoned]

新的A'-B'-C'提交与原始提交大致相同,但它们在图表中移动。 (请注意,现在所有三个无聊的o提交都在两个分支上。)放弃原来的三个意味着Git通常不会拥有来将副本与原始文件进行比较。 (如果原件可以通过其他名称访问 - 例如附加到旧feature1的分支,例如-Git 可以计算出来,至少在大多数情况下是这样。具体细节Git如何解释这一点在这里并不是特别重要。)

无论如何,现在你继续运行git checkout mainline; git merge --squash feature1。这使得一个新的提交是feature1上的三个或多个提交的“压缩副本”。我将停止绘制旧的废弃的,并为壁球调用新的壁球提交S

...--o--o--o--S         <-- mainline
            \
             A'-B'-C'   <-- feature1

“删除安全”完全由提交历史记录

决定

当您要求Git删除feature1时,会执行安全检查:“feature1是否合并到mainline?”这个“合并到”测试完全基于图形连接。名称mainline指向提交S;提交S指向第一个无聊的o提交,这会导致更多无聊的o提交。提案C'feature1的提示 <{1}} <我>不允许向右移动,只能向左移动。

将此与“正常”合并进行对比S

M

使用相同的测试 - “...--o--o--o---------M <-- mainline \ / A'-B'-C' <-- feature1 的提示可以从feature1提示?” - 答案现在是,因为提交{{ 1}}有一个左下角链接提交mainline。 (在Git内部说法中,提交M是合并提交C'第二个父。)

由于壁球合并实际上并非合并,因此C'M之间没有任何联系。

同样,Git甚至尝试看看S是否与“C'SA'相同。但是,如果确实如此,它会说“不一样”,因为B'只与所有三次提交的 sum 相同。让C'匹配压缩提交的唯一方法是只有一个这样的提交(在这种情况下,首先不需要压缩)。

答案 1 :(得分:7)

实际上,您可以确定并删除壁球合并的分支,尽管它并不简单。

git for-each-ref refs/heads/ "--format=%(refname:short)" | while read branch; do mergeBase=$(git merge-base master $branch) && [[ $(git cherry master $(git commit-tree $(git rev-parse $branch\^{tree}) -p $mergeBase -m _)) == "-"* ]] && git branch -D $branch; done

要确定分支是否被合并,git-delete-squashed将创建一个git commit-tree的临时悬挂的提交。然后,它使用git cherry来检查压缩的提交是否已应用于master。如果是这样,它将删除分支。

所有学分归Teddy Katz,https://github.com/not-an-aardvark/git-delete-squashed