使用git filter-branch和签名提交时出现意外行为

4
考虑以下示例。
mkdir pgp-git-test
cd pgp-git-test
git init
touch a.txt
git add a.txt
git commit -m "Add a.txt" -S
touch b.txt
git add b.txt
git commit -m "Add b.txt" -S
git filter-branch --index-filter 'git rm --cached --ignore-unmatch a.txt' --prune-empty HEAD
git log --oneline --decorate
b4efdf0 (HEAD -> master)  iQIcBAABCgAGBQJVrvqHAAoJEGuo23L9/VuyntUQAIBD0g03rTKRkOd9eM4bJgUV  jJezu7R4J0U+zVLrsrSl8oTrYrKPL5QAIqqaB9978qSx5WsmCJj8EfIZ2lwFj7kI  sWWcqjAWcRjWrte/v7ehUyTpJF6h5mWJPbC31BueZ3qlVvvfI03NbMUGocm1VOvE  KZakYkbhrA4ucA0K0YH9RKFo59cLS48SB7DQK4dBfdJSOnBC0Ga9pgBp8wnF2TQG  znRA3MnGRPJMRxZsend5P6gyeGl3wo0J/yk8HDFZXudTRS3SLB+um3NcTXRLIE9Z  Whud2oERKE9CuHU8Y64prbKKA27vWgaVQOC44ujaCqbYXuq+4Ozs34PBlf3CjJqW  19GdVBlqFfiyCPULwyxoPWkRk2kPQyEejt+sJIXG9QgefvoqFF5oLW/YA7AOrDSE  luLbC8uxmTARCWGZVGINL7NmPmEVFDZVj9EyYOjxE/+0wm4cGNBHrL6/JMkVOgpT  pWlgZWR3rX4IjzYtN6DMqKYNWVkVawZQUPh5n5jteuripWtnu5IG8vvvK2mtlkQ3  1OZIdQNAv0HYhBO0vHlV0o2TlVL5x9WfPFn+1XJepJUcoN3MdzXLxN27njdW5Bti  olEqyHrTRxYJNZgSwpQ7WITheIFDqpdcoUV2h4hNjGcXfc0DfaevtCA/oQir+3L4  JlFB35Le9Yby9htVhlu2  =RJi9  -----END PGP SIGNATURE-----
9f82e63  iQIcBAABCgAGBQJVrvp7AAoJEGuo23L9/Vuy/3QP/itaNGwRtlPB4uajGGHMUPxn  gnzd5k5gaWvWlE0Cn/v+CFqE9zVfNiqfsEwJ5YUycUNtEuF9rsiqeQWaWdHWquqr  kOEwRx/9mliK7iC2MZBn/biY5wBE2VcO2m281SnCKxslCjHJxlBo9rglq1t0wybT  CX7C7ScKAtYkos4c1vL0D5Bam2panVXs/KT/YDgWZT9kTg+lEd7NaIwxxNn7HNs7  sOvI2zLyca2FepahF99ZRGg1kKXarVh9nW4mZ1GfeAUuCNSwgwBv+NO3wFC1Blcp  uzKAo1F/cN0rAOr0bMdIZ0qJEVMBBpaqodqRqCOcmYTm5CoKFmcNJvixPl+hYsQx  mPFxM0yVsjlLAnIckNqos/T3i6T8zrb5X4g5ZwuQZzzNKy1xx809v9erb2HHK+d1  +MqdzwEcMyGqfyhz9s1BGrwpBk5CAg2MXbtPpoMTBIG7hmke1al89jvgBiuir06E  kEN6jl/2yAfsj7k5ryjFQNSPJ+HYEyvYBCx3u+xXdA5IBH6CU2S44RqugwztbVKz  /Viel4wIHJ8UCA85ZiprRWJE+nz1RXKlBZc/37W4vcSUSTELXEkhaybOM/eBKACR  sDHOKq5MG9VmZXcu0Zs0cyEvuqljSnZggbDasXHj68b86rB5VRGIO10ad1xKPnFZ  PTUmKKtz1NZkMmjIX4vR  =Mnxi  -----END PGP SIGNATURE-----

我有两个问题。首先,为什么这不会从日志中删除第一个提交?其次,为什么PGP签名现在在提交消息的顶部,并且在使用git filter-branch时有没有避免此行为的方法?

(如果有关系的话,我正在使用git v. 2.4.6。)

2个回答

6

我无法回答为什么这个玩具示例中第一个提交记录没有被从历史记录中删除的问题。

然而,对于第二个问题,似乎这是一种设计状态。当使用git filter-branch时,PGP签名故意被破坏,以防止某人修改已签署提交的内容,并使其看起来像签署提交的人已经签署了修改后的提交内容。

可以假定破损的签名也被放置在提交消息的顶部,以引起注意。

在我的情况下,由于所有签名都以iQIcBA开头,我可以通过执行以下操作来删除损坏的签名。

git filter-branch --msg-filter 'sed "/iQIcBA.*/,/.*END PGP SIGNATURE.*/d"' HEAD

如果你想撤销提交的代码,可以尝试以下操作。
git filter-branch --commit-filter 'git commit-tree -S "$@"' HEAD

然而,似乎签署标签而不是追溯地签署所有提交更受青睐(见,例如,这里)。

这个答案在很大程度上基于git邮件列表上Jacob Keller的帮助。


2
针对您的第一个问题,文档中写道:
尽管如此,这个开关仅适用于只有一个父提交的提交。
这实际上是两个陈述:
1. 提交必须有一个父节点。 2. 提交不能有多个父节点。
添加 a.txt 的提交未通过第一个检查。
代码(虽然文档和编写都很差)也证实了这一点。
首先,父字符串作为参数传递给每个提交运行的命令:
由于您的根提交没有父级,因此为空。因此,当代码稍后检查我们是否有三个参数test $# = 3时,会发现这不是情况: https://github.com/git/git/blob/master/git-filter-branch.sh#L47 因此,它转到else分支,其中添加提交。
在存在父提交的情况下,代码进入第二个检查测试"$1" = $(git rev-parse "$3^{tree}"),该测试比较了先前提交的树的SHA和此提交的树的SHA,如果它们相同,则跳过创建该提交。
顺便说一句,我真的希望这段代码更易读。如此重要的项目允许像这样的提交实在令人沮丧。不过,也许这只是我对SHELL的偏见。
我不知道为什么要添加PGP签名。它肯定没有记录,所以我猜这是一个错误,考虑到阅读代码的难度,这并不奇怪。

+1 谢谢,你的侦查工作做得很好!邮件列表上的人们建议PGP问题并非一个漏洞,而是出于设计考虑,以防止别人冒充你签署了你实际上没有签署的更改。 - Adam Liter
不用担心调查。关于邮件列表的回复。那不是我的理解方式。他说:“我不确定为什么它将第一行放在提交的顶部。”这让我觉得他们也认为这不对。根据代码,我怀疑签名通常存储在提交消息中,但在运行git log时隐藏,除非您添加--show-signatures,但是当运行filter-branch时,他们忘记将其剥离并将其添加到消息正文中。我猜编写filter-branch代码的人不使用签名。我会修补它,但这段代码让我头痛。 - Gerry

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接