我被腌渍了.我无法从其他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'
Run Code Online (Sandbox Code Playgroud)
分支X已合并.我可以看到从X提交当我这样做git log的master.为什么会这样?我想使用-d而不是-D因为这可能导致灾难性地删除真正未合并的分支.
这里有几个不同的棘手的位.
关键问题git branch -d(删除而不强制1)不是"是否合并分支?",因为这个问题实际上是无法回答的.问题是"是分支合并到 <填写这里的东西>?"
在Junio C Hamano的提交99c419c91554e9f60940228006b7d39d42704da7中,这个测试在Git 1.7版本中更改了(这意味着每个人都应该拥有它,但请检查您的Git版本):
branch -d:在它合并的分支上建立"已合并"的安全性
当一个分支被标记为与另一个ref合并时(例如,本地'next'合并并推回原点的'next','branch.next.merge'设置为'refs/heads/next'),它几乎没有基于"branch -d"安全性的意义,其目的不是丢失当前分支上未合并到其他分支的提交.检查它是否与它合并的另一个分支合并是更明智的.
因此,有两个或有时三个,如果你看一下你(或Git)必须回答的上述提交问题,看看是否-d允许:
分支名称指向一个特定的提交(让我们将此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.");
}
Run Code Online (Sandbox Code Playgroud)
(我削减了部分用于显示目的的代码在这里):基本上,如果HEAD解析为其他一些犯下比我们使用的承诺:T≤测试,并且我们会得到一个不同的结果:T≤HEAD比我们得到了:T≤你,我们添加额外的警告信息.(注意,测试的第一部分是多余的:如果我们比较HEAD因为1.7之前的兼容性和缺少上游,那么如果我们再次与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
Run Code Online (Sandbox Code Playgroud)
该--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
Run Code Online (Sandbox Code Playgroud)
会告诉你是否master是它的祖先origin/master(为此目的,"指向相同的提交"计为"是一个祖先",即,这是非常相同的≤测试).
每当此过渡期最终结束时,"使用HEAD"测试可能完全消失,或者可能继续用于没有上游设置的分支.但无论如何,问题始终是"待删除的分支是否合并到 ____?(填空)",你必须看看填空的内容.
上游中与您要删除的分支上的提交相对应的提交必须(或者至少在其历史记录中)通过提交哈希ID进行相同的提交,因为"已合并到"测试中成功.如果feature/X被合并到origin/develop通过所谓的"南瓜合并"(这不是合并,但它是由合并完成2),该提交ID不匹配,并且"合并到"测试总是失败.
1顺便说一句,作为Git的2.3,现在就可以添加--force到git branch -d,而不是必须使用git branch -D的,当然虽然-D仍然有效.
2这里的区别在于"合并" - 作为名词的合并,意味着"作为合并提交的提交"(使用合并作为形容词),以及"合并" - 合并作为动词,意味着动作结合一些变化.该git merge命令可以:
"壁球合并"只有在您要求时才会发生,而"快速非合并"只有在可以且您不禁止的情况下才会发生.
当提交的内容与您尝试删除的分支的差异足够大时,就会发生这种情况。这可能是由于壁球提交或分支附加到先前的基础上,然后又被远程上的其他人合并。
如果您确信更改实际上已经合并(如您所说),那么a branch -D是安全的。
最后,
灾难性地删除分支
是不真实的。删除分支不是不可撤消的问题。所有操作都存储在git reflog和分支指向的提交中,该提交至少保留30天。如果确实是偏执狂,则可以改名为分支。但是实际上,删除分支会更容易。
换句话说,分支只是一个指针。删除指针不会删除内容。因此,您可以根据需要轻松地复活分支。