删除合并的分支给出“错误:分支 X 未完全合并......”
Posted
技术标签:
【中文标题】删除合并的分支给出“错误:分支 X 未完全合并......”【英文标题】:Deleting merged branch gives "error: The branch X is not fully merged...' 【发布时间】:2017-03-23 18:01:31 【问题描述】:我被泡菜夹住了。我无法从其他 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 已合并。当我在 master
上执行 git log
时,我可以看到来自 X 的提交。为什么会这样?我想使用-d
而不是-D
,因为这可能会导致灾难性地删除真正未合并的分支。
【问题讨论】:
可以使用-f
强制本地删除
【参考方案1】:
这里有几个不同的棘手部分。
git branch -d
(不强制删除1)的关键问题不是“分支合并了吗?”,因为这个问题实际上是无法回答的。问题是“分支是否合并到 ?”
此测试在 Git 版本 1.7 中进行了更改(这意味着每个人今天都应该拥有它,但请检查您的 Git 版本),commit 99c419c91554e9f60940228006b7d39d42704da7 by Junio C Hamano:
branch -d:将“已经合并”的安全性建立在它合并的分支上
当一个分支被标记为与另一个 ref 合并时(例如本地 'next' 使用 'branch.next.merge' 合并并推回原点的 'next' 设置为'refs/heads/next'),以“branch -d”为基础没有什么意义 安全性,其目的是不丢失未合并到其他的提交 分支,在当前分支上。检查它是否更明智 与它合并的另一个分支合并。
因此,如果您查看上述提交,您(或 Git)必须回答两个(或有时三个)问题,以确定是否允许 -d
:
-
我们建议删除的分支的上游名称是什么? (如果没有,请参见下文。)
分支名称指向一个特定的提交(我们称其为 T 表示 Tip)。上游分支名称也指向一个特定的提交(将此提交称为 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 ≤ 测试中使用的提交之外的其他提交,and 对于 T ≤ HEAD,我们会得到一个 不同 的结果,而不是 T ≤ U,我们添加了额外的警告消息。 (请注意,测试的第一部分是多余的:如果我们因为 1.7 之前的兼容性和缺少上游而与 HEAD 进行比较,那么如果我们再次与 HEAD 比较,我们将得到 same 结果. 我们真正需要的是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
的祖先(为此,“指向同一个提交”算作“是一个祖先”,即,这是相同的≤测试)。
当这个过渡期最终结束时,“使用 HEAD”测试可能会完全消失,或者可能会继续用于没有上游设置的分支。但是,无论如何,问题始终是“要删除的分支是否合并到 ____?(填空)”,您必须查看填空的内容。
与您提议删除的分支上的提交相对应的上游提交必须是(或至少在其历史中具有)相同的提交,通过提交哈希ID,以便“合并到”测试成功。如果 feature/X
通过所谓的“squash merge”(不是合并,虽然它是通过 merging2 完成的)合并到 origin/develop
,那么提交 ID 将不匹配,并且“被合并到”测试总是会失败。
1顺便说一句,从 Git 2.3 开始,您现在可以将 --force
添加到 git branch -d
,而不是被要求使用 git branch -D
,当然 -D
仍然有效。
2这里的区别在于“a merge”——作为名词的merge,意思是“作为合并提交的提交”(使用merge作为形容词)和“to merge” "——merge 作为动词,意思是组合一些变化的动作。 git merge
命令可以:
只有在您提出要求时才会发生“挤压合并”,而只有当它可以并且您不禁止时才会发生“快进非合并” > 它。
【讨论】:
这些都是有用的信息,但我希望它提供有关如何解决(或至少改善)问题中描述的问题的指南。 @AlexJohnson:问题是没有解决办法。 很公平。令我惊讶的是,对于合并到上游后本地和远程删除功能分支的极其常见的情况,没有更好的工作流程。 @AlexJohnson:如果你使用真正的合并(包括真正合并模式下的 GitHub 的“合并”按钮),git branch -d
本地将起作用(在git fetch
-ing 并更新您的其他本地分支之后) .如果你使用 GitHub 的“rebase and merge”或“squash and merge”,你会被强制删除。不是很漂亮。
我在那个提交被合并之前被压扁了,所以这是有道理的。我想我必须选择合并(壁球)或删除(非强制删除)时是否漂亮。谢谢你的解释。【参考方案2】:
当提交的内容与您尝试删除的分支足够不同时,就会发生这种情况。这可能是因为 squash 提交或附加到先前基础的分支,然后当它们被远程上的其他人合并时。
如果您确信更改实际上已合并(如您所说),那么branch -D
是安全的。
最后,
灾难性地删除分支
不真实。删除分支不是可撤销的问题。所有操作都存储在git reflog
中,分支指向的提交至少要保留 30 天。如果你真的很偏执,你可以重命名分支。但实际上删除分支更容易。
换句话说,分支只是一个指针。删除指针不会删除内容。因此,如果需要,您可以轻松地复活分支。
【讨论】:
小心删除,因为删除分支名称也会删除该分支的引用日志。HEAD
reflog 可能仍然有分支的 reflog 将保护的提交的条目,但那是 可能(如可能),不一定 确实。但总的来说,对象本身确实会持续一段时间:即使它们没有受到保护,也会发生这种情况。您必须解除对它们的保护并触发(或手动运行)git gc
或 git prune
才能让它们消失。以上是关于删除合并的分支给出“错误:分支 X 未完全合并......”的主要内容,如果未能解决你的问题,请参考以下文章