git - 删除 merge 的分支给出 "error: The branch X is not fully merged...'

标签 git github merge

我陷入了泡菜中。我无法从其他 SO 问题或阅读 git 文档中找到我的答案。我真的很感激你在这里的帮助。

在 Github 上 merge 我的分支后,我从 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 已 merge 。当我这样做时,我可以看到来自 X 的提交 git logmaster .为什么会发生这种情况?我想用-d而不是 -D因为这可能导致灾难性地删除真正未 merge 的分支。

最佳答案

这里有几个不同的棘手部分。
git branch -d的关键问题(delete without force1) 不是“分支 merge 了吗?”,因为这个问题实际上是无法回答的。问题是“分支是否 merge 到 ”?

这个测试在 Git 1.7 版中发生了变化(这意味着每个人今天都应该拥有它,但请检查你的 Git 版本),在 commit 99c419c91554e9f60940228006b7d39d42704da7通过 Junio C Hamano:

branch -d: base the "already-merged" safety on the branch it merges with

When a branch is marked to merge with another ref (e.g. local 'next' that merges from and pushes back to origin's 'next', with 'branch.next.merge' set to 'refs/heads/next'), it makes little sense to base the "branch -d" safety, whose purpose is not to lose commits that are not merged to other branches, on the current branch. It is much more sensible to check if it is merged with the other branch it merges with.



因此,有两个——有时是三个,如果你看看上面的提交——你(或 Git)必须回答的问题,以查看 -d允许:
  • 我们建议删除的分支的上游名称是什么? (如果没有,请参见下文。)
  • 分支名称指向一个特定的提交(我们将此 T 称为提示)。上游分支名称也指向一个特定的提交(称之为提交 U)。

    T 是 U 的祖先吗?

  • 如果问题 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 ≤ HEAD 的结果与 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
    

    会告诉你是否masterorigin/master的祖先(为此,“指向同一个提交”算作“是一个祖先”,即,这是完全相同的 ≤ 测试)。

    每当此过渡期最终结束时,“使用 HEAD”测试可能会完全消失,或者可能会继续用于没有上游集的分支。但是无论如何,问题总是“要删除的分支是否 merge 到____?(填空)”,您必须看看是什么填空了。

    与您提议删除的分支上的提交相对应的上游提交必须(或至少在其历史记录中具有)相同的提交,通过提交哈希 ID,对于“已 merge 到”测试成功。如 feature/X并入 origin/develop通过所谓的“ Squash merge ”(这不是 merge ,尽管它是通过 merging2 完成的),该提交 ID 将不匹配,并且“merge 到”测试将始终失败。

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

    2这里的区别是“a merge”——merge作为名词,意思是“a commit that is a merge commit”(使用merge作为形容词)和“to merge”——merge作为动词,意思是结合一些变化。 git merge命令可以:
  • 做一个快进,既不将 merge 作为动词也不将 merge 作为名词,因此根本没有 merge ;或
  • 进行真正的 merge , merge (动词)一些更改以产生 merge (名词);或
  • 做一个“ Squash merge ”,它 merge (动词)但产生一个非 merge (由于某些莫名其妙的原因,你必须手动提交)。

  • “ Squash merge ”仅在您要求时发生,而“快进非 merge ”仅在可以且您不禁止时发生。

    关于git - 删除 merge 的分支给出 "error: The branch X is not fully merged...',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40515232/

    相关文章:

    ruby-on-rails - 生成 SSH key (Win/msysgit) - Ruby on Rails 教程

    windows - 如何在 MS Windows 下使用 Git 忽略 obj 文件夹

    c# - 来自 Github 的自动化构建

    html - 如何在 git 功能分支工作流中处理 xml/html?

    git merge 不会出现在提交历史记录中

    r - 合并具有多个值的列

    git - 无法让 TeamCity 使用默认私钥向 GitHub 进行身份验证

    python - 推送到 Git 存储库时如何设置自动部署到 AppEngine

    docker - 使用Github Action部署Docker镜像

    github - 有没有办法通过比较分支来查看GitHub上的合并冲突?