git filter-branch和signed commits的意外行为

时间:2015-07-22 02:17:26

标签: git git-filter-branch

请考虑以下示例。

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 个答案:

答案 0 :(得分:5)

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

然而,至于第二个问题,似乎这是设计的状态。使用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

但是,似乎首选签名而不是追溯签署所有提交(请参阅例如here)。

这个答案很大程度上取决于雅各布凯勒对git mailing list.

的帮助

答案 1 :(得分:2)

回答你的第一个问题。文档说:

  

但是,此开关仅适用于具有一个且仅一个父

的提交      

https://git-scm.com/docs/git-filter-branch

这基本上是两个陈述。

  1. 提交必须有一个父级。
  2. 提交不得包含多个父级。
  3. 第一次检查时,添加a.txt的提交失败。

    代码(尽管文档记录不完整,但写得很好)证实了这一点。

    首先,父字符串作为参数传递给为每次提交运行的命令: https://github.com/git/git/blob/master/git-filter-branch.sh#L410

    因为根提交没有父项,所以这是空的。那么当代码稍后检查我们有三个参数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签名。它肯定没有记录,所以我猜这是一个错误,考虑到阅读代码的难度,这并不奇怪。