一方面,它真的很微不足道。另一方面,这非常困难。
这是微不足道的:
- 有一个合并。合并要么是正确的,要么是错误的。查看合并,看看它是对还是错。如果错了,作者和提交者会告诉你是谁做的(在你信任作者和提交者1的范围内)。
这是非常困难的:
没有自动方法可以找到该问题的答案。
如果您有良好的自动化测试,您可以任意接近自动回答问题。好的自动化测试并不容易,如果你试图让它们变得非常好,就会变得非常困难。
如果您没有自动化测试,但确实有一些擅长正确合并的人,您也许可以进行抽查:只需让这些优秀的人自己重复合并,并将他们的结果与之前的结果进行比较。如果相同,则原始合并已正确完成。如果它不同,则不是。
合并冲突的存在与否并不能确定合并是否正确完成。Git 没有秘密知识:它只是根据一组固定的规则组合文本。也就是说,如果您希望选择手动测试,特别是那些确实看到冲突的合并,您可以自动化这部分。只需重复合并(确保git rerere
没有打开),看看是否有冲突。
重复合并
上面,短语“repeat the merge”出现了两次。您可能想知道如何重复合并。这大多是微不足道的。2 首先,找到每个合并的提交 ID:
git rev-list --merges <start-point> [additional options if desired]
这会生成一个候选 ID 列表。(您将希望将它们全部保存在某个地方,并注释您检查过的那些,以便您以后不必重新检查它们。在这里使用您喜欢的任何临时解决方案。)
然后,给定一个合并 ID,只需将其第一个父级作为分离的 HEAD 检出,并git merge
在其剩余的父级 ID 上运行(此位依赖于 POSIX shell 行为和语法):
id=c79a113... # or whatever, from your list
set -- $(git rev-parse ${id}^@)
git checkout $1 # check out first parent
shift # now that we have $1 out, discard $1
git merge $* # (attempt to) merge the remaining commits
该rev^@
符号来自gitrevisions,意思是“给定修订版的所有父母”。如果您的所有合并都是标准的双父合并,则可以使用更清晰的(但不太通用):
git checkout ${id}^1
git merge ${id}^2
(gitrevisions
语法和外壳set
和shift
技术允许章鱼合并)。
由于此合并是在分离的 HEAD 上进行的,因此生成的合并(如果它自动完成)可以通过检查任何其他提交或分支名称来轻松放弃。如果因冲突而git merge
失败,则您有一个冲突的合并,索引中的通常结果;您可以继续完成合并,或使用git merge --abort
终止它。(如果合并成功,则退出状态为非零,否则为非零git merge
。)0
1请记住,除了通过 push 或 fetch 进行的提交传输之外,每个 Git 操作都是由完全控制他或她自己的存储库的人在本地完成的。用户当然可以撒谎并声称自己是其他人。如果你完全控制了这一点,你可以而且必须在传输边界这样做:当你从其他人那里收到一个提交时——无论是git fetch
从你这边还是git push
从他们那边——你知道你在和谁说话(通过您实施的任何身份验证:这完全在 Git 之外,并且现在通常来自 ssh 或 https,通常包含在 Gitolite 等第三方扩展中,或者由 GitHub 等作为服务提供)。此时,您有机会在接受提交之前进行任何您喜欢的验证。
或者,您可以使用例如 PGP 签名来检查“事后”。如果有人对某些标签和/或某些提交进行了 PGP 签名,并且您可以验证这些签名,那么您可以选择相信这些标签和/或提交是他们的。然后,您可以将该信任(当然,基于 SHA-1 的安全性以及您对签名者的信任程度)扩展到这些提交和/或标签的祖先,因为构建了一个匹配的对象预定义的 SHA-1 及其文本至少非常难。(这称为第二个原像电阻;例如,请参阅此 crypto.stackexchange.com 问题。)
2我说“几乎是微不足道的”,因为用户提供的选项在git merge
此处不可用。您可以要求使用非标准合并选项的用户将它们记录在他们的提交中,或者在提交附加的注释中,但这很难强制执行。另见脚注 1:您只能在转移边界应用强制规则。