删除合并分支会出现“错误:分支X未完全合并......”

时间:2016-11-09 20:14:29

标签: git github merge

我被腌渍了。我无法从其他SO问题或阅读git文档中找到答案。我非常感谢你的帮助。

在Github上合并我的分支后,我从UI(远程)删除了我的分支。 我定期修剪当地的分支机构:

git checkout master
git pull origin master
git fetch -p
git branch -d X
Error: error: The branch X is not fully merged. If you are sure you want to delete it, run 'git branch -D X'

分支X已合并。当我在git logmaster时,我可以看到来自X的提交。为什么会这样?我想使用-d而不是-D,因为这可能会导致严重删除真正未合并的分支。

2 个答案:

答案 0 :(得分:8)

这里有几个不同的技巧。

git branch -d的关键问题(删除而不强制 1 )不是"是否合并分支?",因为该问题实际上是无法回答的。问题是"是分支合并<在这里填写一些东西>?"

这个测试在Git版本1.7中更改了(这意味着每个人都应该拥有它,但请检查您的Git版本),在commit 99c419c91554e9f60940228006b7d39d42704da7中由Junio C Hamano进行了更改:

  

branch -d:基础"已经合并"它与

合并的分支机构的安全性      

当分支被标记为与另一个引用合并时(例如本地'接下来的那个引用)       合并并推送到原点' next' branch.next.merge'       设置为' refs / heads / next'),基于"分支-d"是没有意义的。       安全,其目的不是失去未与其他人合并的承诺       分支机构,在当前分支机构。检查它是否更明智       与它合并的另一个分支合并。

因此,有两个或有时三个,如果你看一下你(或Git)必须回答的上述提交问题,看看是否允许-d

  1. 我们建议删除的分支的上游名称是什么? (如果没有,请参阅下文。)
  2. 分支名称指向一个特定提交(让我们为提示调用此 T )。上游分支名称还指向一个特定的提交(调用此提交 U )。

    T U 的祖先吗?

  3. 如果问题2的答案为是(即T≤U),则允许删除。

    如果 没有上游怎么办?好吧,那是"在1.7"进来:原始测试不是T≤U而是T≤HEAD。那个测试仍在那里。现在,如果没有上游,则使用HEAD测试而不是上游测试。同时,对于过渡期"当每个人都适应新奇的Git 1.7行为时,当 上游时,你也可能会收到警告或额外的解释。即使在今天,这个警告仍然存在,在Git 2.10中(差不多7年后现在:这是一个非常漫长的过渡时期!):

    if ((head_rev != reference_rev) &&
        in_merge_bases(rev, head_rev) != merged) {
            if (merged)
                warning("deleting branch ... not yet merged to HEAD.");
            else
                warning("not deleting branch ... even though it is merged to HEAD.");
    }
    

    (我在这里修剪了一些用于显示目的的代码):基本上,如果HEAD解析为除了我们在T≤测试中使用的提交之外的其他提交, T≤HE T≤U T≤U T 我们添加了T≤U额外的警告信息。 (请注意,测试的第一部分是多余的:如果由于1.7之前的兼容性和上游缺失而与HEAD进行比较,那么如果我们进行比较,我们将得到相同的结果HEAD再次。我们真正需要的是in_merge_bases测试。)

    你怎么知道上游是什么?好吧,实际上有一个简单的命令行方式可以找到:

    $ git rev-parse --abbrev-ref master@{u}
    origin/master
    $ git rev-parse --symbolic-full-name master@{u}
    refs/remotes/origin/master
    

    --abbrev-ref变体为您提供Git的典型缩写版本,而--symbolic-full-name为您提供完整的参考名称。如果在没有上游集的分支上运行,则两者都会失败。当然,您也可以使用git branch -vv查看缩写的上游(对于所有分支)。

    你如何测试整个T≤U的东西? git merge-base --is-ancestor命令对shell脚本执行此操作,因此:

    $ git merge-base --is-ancestor master origin/master && echo yes || echo no
    

    将告诉您master是否是origin/master的祖先(为此目的,"指向相同的提交"计为"是#an祖先&#34} ;即,这是非常相同的≤测试。)

    每当这个过渡期最终结束时,"使用HEAD"测试可能完全消失,或者可能继续用于没有上游设置的分支。但无论如何,问题始终是"待删除的分支是否已将合并到 ____? (填空)"你必须看看填补空白的内容。

    上游中与您要删除的分支上的提交相对应的提交必须(或至少在其历史记录中)相同的提交,通过提交哈希ID,为此"合并到"测试成功。如果feature/X通过所谓的" squash merge"合并到origin/develop (这不是合并,虽然它是通过合并 2 完成的),但提交ID不匹配,并且"合并到"测试永远都会失败。

    1 顺便提一下,从Git 2.3开始,您现在可以将--force添加到git branch -d,而不是被要求使用git branch -D,当然{ {1}}仍有效。

    2 这里的区别在于"合并" -merge作为名词,这意味着"提交是一个合并提交" (使用合并作为形容词)和"合并" -merge作为动词,意味着组合一些变化集的动作。 -D命令可以:

    • 做一个快进,既没有合并动词,也没有合并作为名词,所以根本就没有合并;或
    • 进行真正的合并,合并(动词)一些变化以产生合并(名词);或
    • 做一个" squash merge",它合并(动词)但产生一个非合并(由于一些莫名其妙的原因,你必须手动提交)。

    A"壁球合并"只有当你提出要求时才会发生,而快速前进的非合并"只有当

答案 1 :(得分:5)

当提交的内容与您尝试删除的分支相差足够时,就会发生这种情况。这可能是因为壁球提交或附加到先前基地的分支,然后当它们被遥控器上的其他人合并时。

如果您确信这些更改实际上是合并的(如您所说),则branch -D是安全的。

最后,

  

灾难性地删除分支

不真实。删除分支不是可撤销的问题。所有操作都存储在git reflog和分支指向的提交中至少保留30天。如果真的偏执,你可以重命名分支。但实际上,删除分支更容易。

换句话说,分支只是一个指针。删除指针不会删除内容。因此,如果需要,您可以轻松地恢复分支。