Omitir el procesamiento de las revisiones de Git en el gancho posterior a la recepción que ya se han procesado previamente

Tengo un gancho git post-receive que extrae todas las revisiones que se agregaron durante un "git push" y procesa algo en cada una (como el envío de correos electrónicos de notificación). Esto funciona genial excepto cuando se fusiona; p.ej:

  1. Realizo algunos commits en branch1 y luego push branch1. El enganche post-recepción procesa los commits correctamente.
  2. Combino branch1 en branch2 y luego push branch2. El enganche post-recepción procesa todas las confirmaciones fusionadas por segunda vez.

¿Cómo puedo evitar esto? Debajo está el comienzo de mi gancho post-recepción donde extraigo las confirmaciones que deben procesarse (al final $ COMMITS contiene la list de confirmaciones para procesar).

#!/bin/sh REPO_PATH=`pwd` COMMITS='' SHELL=/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin # for each ref that was updated during the push while read OLD_REV NEW_REV REF_NAME; do OLD_REV="`git rev-parse $OLD_REV`" NEW_REV="`git rev-parse $NEW_REV`" if expr "$OLD_REV" : '0*$' >/dev/null; then # if the branch was created, add all revisions in the new branch; skip tags if ! expr "$REF_NAME" : 'refs/tags/' >/dev/null; then REF_REV="`git rev-parse $REF_NAME`" REF_NAME="`git name-rev --name-only $REF_REV`" COMMITS="$COMMITS `git rev-list $REF_NAME | git name-rev --stdin | grep -G \($REF_NAME.*\) | awk '{ print $1 }' | tr '\n' ' '`" fi elif expr "$NEW_REV" : '0*$' >/dev/null; then # don't think branch deletes ever hit a post-receive hook, so we should never get here printf '' else # add any commits in this push COMMITS="$COMMITS `git rev-parse --not --all | grep -v $(git rev-parse $REF_NAME) | git rev-list --reverse --stdin $(git merge-base $OLD_REV $NEW_REV)..$NEW_REV | tr '\n' ' '`" fi done 

Mire $(prefix)/share/git-core/contrib/hooks/post-receive-email , que hace exactamente lo que (creo) usted quiere. Básicamente, usa git for-each-ref para encontrar los nombres de todas las twigs, y luego excluye cada confirmación que sea accesible desde alguna twig que no sea la que se está actualizando:

 if [ "$change_type" = create ] then # Show all revisions exclusive to this (new) branch. revspec=$newrev else # Branch update; show revisions not part of $oldrev. revspec=$oldrev..$newrev fi other_branches=$(git for-each-ref --format='%(refname)' refs/heads/ | grep -F -v $refname) git rev-parse --not $other_branches | git rev-list --pretty --stdin $revspec 

(Lo he simplificado aquí, y espero que no haya dañado nada en mi trabajo de cortar y pegar. Las inputs aquí son: $change_type es create si $oldrev es ceros completos, de lo contrario es una update ; $oldrev es el viejo rev SHA1 desde la línea recientemente, lea de stdin; $newrev es la nueva rev SHA1; y $refname es el nombre completo, por ejemplo, refs/heads/topic ).

Lo que hacemos es mantener el hash de las confirmaciones procesadas previamente en un file de text. Cada vez que se ejecuta el gancho, busca en ese file para verificar si una confirmación determinada ya se ha procesado o no. Si aún no procesó esa confirmación, trátela y luego registre esa confirmación en el file.

Esto no es muy escalable, ya que los files de text solo crecerán a medida que se agreguen más commits al repository y también boostá el time para verificar un compromiso determinado.

Hicimos esto haciendo que el gancho post-recepción dejara de procesar cuando se encontró con un commit de fusión (un commit con dos o más padres). Esto requiere un poco de disciplina al impulsar las fusiones para garantizar que no se descarten otras confirmaciones "reales". La disciplina es empujar siempre antes de fusionar y luego empujar la combinación por separado.

Implementé esto completamente en un gancho post-recepción. Notifica trac de solo nuevas confirmaciones desde la última recuperación sin duplicación , independientemente de si las nuevas confirmaciones se enviaron a una sola twig o varias twigs al mismo time. Este método mantiene un file llamado TRAC_HEAD en su directory git para rastrear qué confirmaciones ya se han procesado.

Se recomienda ejecutar cat refs/heads/* > TRAC HEAD en su directory .git antes de habilitar el enganche.

 #!/bin/sh # # Reads and notifies trac of only new commits that have not yet been dealt with. # # The "post-receive" script is run after receive-pack has accepted a pack # and the repository has been updated. It is passed arguments in through # stdin in the form # <oldrev> <newrev> <refname> # For example: # aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master # TRAC_PATH="/path/to/trac/env" # Read the standard input while read oldrev newrev refname ; do echo "Processing branch: $refname" # Read the last revisions for each branch from TRAC_HEAD exclusions=$(cat TRAC_HEAD | uniq | sed -e 's/^/^/' -e 's/ / ^/g' | xargs echo) echo "Exclusion list: $exclusions" git rev-list --reverse $newrev $exclusions | while read rev ; do trac-admin $TRAC_PATH changeset added '(default)' $rev echo "Processed: $rev" done # Add to the exclusions file the latest revision from this branch echo $newrev >> TRAC_HEAD done # Update the TRAC_HEAD file cat refs/heads/* > TRAC_HEAD