Comportamiento inesperado con git filter-branch y commits firmados

Considera el siguiente ejemplo.

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----- 

Tengo dos preguntas. Primero, ¿por qué esto no elimina la primera confirmación del logging? Y, en segundo lugar, ¿por qué la firma de PGP ahora está en la parte superior del post de confirmación y hay alguna forma de evitar este comportamiento cuando se usa git filter-branch ?

(En caso de que importe, estoy usando git v. 2.4.6.)

No tengo una respuesta sobre por qué el primer compromiso no se ha eliminado de la historia en este ejemplo de juguete.

Sin embargo, en cuanto a la segunda pregunta, parece que esto es estado por layout. La firma de PGP se rompe deliberadamente al usar git filter-branch para evitar que alguien modifique el contenido de una confirmación firmada y hacer que parezca que la persona que firmó la confirmación ha firmado el contenido modificado de la confirmación.

Presumiblemente, la firma rota también se coloca en la parte superior del post de compromiso para llamar la atención sobre este hecho.

En mi caso, dado que todas las firmas comienzan con algo como iQIcBA , pude eliminar las firmas rotas haciendo lo siguiente.

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

Si desea renunciar a las confirmaciones, puede hacer algo como lo siguiente.

 git filter-branch --commit-filter 'git commit-tree -S "$@"' HEAD 

Sin embargo, parece que se prefiere firmar una label en lugar de firmar de forma retroactiva todas las confirmaciones (ver, por ejemplo , aquí ).


Esta respuesta se basa en gran parte en la ayuda de Jacob Keller en la list de correo git .

En respuesta a tu primera pregunta. La documentation dice:

Sin embargo, este cambio solo se aplica a las confirmaciones que tienen uno y solo uno de los padres

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

Esto es esencialmente dos declaraciones.

  1. El compromiso debe tener un padre.
  2. El compromiso no debe tener más de un padre.

La confirmación que agrega a.txt falla el primer control.

El código (tan mal documentado y escrito como está) lo confirma.

Primero, la cadena primaria se pasa como arguments al command que se ejecuta para cada confirmación: https://github.com/git/git/blob/master/git-filter-branch.sh#L410

Como no hay padres para la confirmación de inicio, está vacía. Entonces, cuando el código comtesting más tarde que tenemos tres arguments, test $# = 3 y encuentra que este no es el caso: https://github.com/git/git/blob/master/git-filter-branch.sh#L47

Por lo tanto, se mueve a la twig else donde se agrega la confirmación.

En los casos en que hay una confirmación principal, el código pasa a la segunda testing de comprobación "$1" = $(git rev-parse "$3^{tree}") que hace una comparación del sha del tree para la confirmación previa y el sha del tree para este commit, si son iguales, se salta haciendo commit.

Como nota al margen, realmente me gustaría que este código fuera mucho más legible. Es muy triste que un proyecto tan importante permita envíos como este. Por otra parte, tal vez es solo mi prejuicio contra SHELL.

No tengo idea de por qué se agrega la firma de PGP. Ciertamente no está documentado, así que supongo que es un error, lo que no es sorprendente dada la dificultad de leer el código.