2010-08-18 12 views
26

Tengo un problema con el gancho de "actualización". En el caso de una nueva sucursal, obtiene un 0000000000000000000000000000000000000000 como 'oldrev'. Y no sé cómo manejar ese caso.Git recibir/actualizar ganchos y nuevas ramas

Tenemos el requisito de que cada mensaje de confirmación haga referencia a un problema válido de Jira. Así que he instalado un gancho de "actualización" en nuestro repositorio central. Ese gancho obtiene un "oldrev" y un "newrev". Luego paso a los "git rev-list" de esta manera:

git rev-list $oldrev..$newrev

Esto me da la lista de todas las revoluciones, que luego se pueden repetir, y hacer lo que necesito hacer.

El problema es que cuando el usuario empuja una nueva rama, el gancho obtiene 0000000000000000000000000000000000000000 como oldrev. Y "git rev-list" simplemente se queja con:

fatal: Invalid revision range 0000000000000000000000000000000000000000..21bac83b2

Entonces, ¿cómo puedo obtener la lista de todas las revoluciones que están en esa nueva rama? He buscado en la red por bastante tiempo y no encontré nada. Los ganchos de ejemplo que encuentran ya sea

  • no manejar el problema, y ​​el error con el mensaje de error anterior
  • incorrectamente tratar de solucionar el problema estableciendo la OLDREV a "", que devuelve los resultados incorrectos de rev -lista
  • simplemente darse por vencido cuando se encuentran con que OLDREV

Ninguno de estos suena particularmente emocionante.

Entonces, ¿alguien tiene alguna idea de cómo obtener la respuesta correcta en ese caso? Estaba pensando en preguntar a git por "darme todas las revoluciones que son alcanzables desde newrev, pero no desde ninguna de las otras ramas (= todas las ramas excepto la nueva)". Pero incluso eso daría la respuesta incorrecta si se hubiera producido una fusión de la nueva rama con alguna de las antiguas.

Respuesta

14

El término "respuesta correcta" es un poco ambiguo en este caso. De hecho, creo que "todas las revoluciones alcanzables desde newrev pero en ningún otro lugar" es completamente correcto. Esto es cierto incluso si hubo una fusión; en ese caso, debería ver las confirmaciones exclusivas de la nueva referencia y la fusión, pero no las confirmaciones fusionadas.

Por lo tanto, yo diría, comprobar si el "OLDREV" es todo ceros, y si lo es, actuar en consecuencia:

if [ "$oldrev" -eq 0 ]; then 
    # list everything reachable from newrev but not any heads 
    git rev-list $(git for-each-ref --format='%(refname)' refs/heads/* | sed 's/^/\^/') "$newrev" 
else 
    git rev-list "$oldrev..$newrev" 
fi 
+2

No estoy seguro de si es algo extraño en mi entorno o una actualización de git, pero la negación está eliminando referencias en la rama actual. Tengo que hacer algo como esto: 'git rev-list $ (git for-each-ref --format = '% (refname)'" refs/heads/* "| grep -v '$ ref' | sed 's/^/\^/') "$ newrev" ' – mmalone

+1

Para usar en los ganchos' update' (y 'pre-receive'), como se especifica en la pregunta, estas respuestas son todas más complicadas y costosas. La respuesta de José a continuación es la más simple y eficiente; esa debería ser la respuesta elegida IMO. – MadScientist

+0

@mmalone tienes razón. Tuve que agregar "| grep -v '$ rev'". De lo contrario, siempre tengo el resultado vacío – dritan

7

yo sólo pensé que fuera yo mismo.

git log newref --no otherheads

es la clave para obtener todos los registros de una rama que no están en ninguna otra rama. Debajo está mi script python para verificar la longitud de línea máxima correcta de los mensajes de confirmación.

import sys 
import commands 

ref = sys.argv[1] 
old = sys.argv[2] 
new = sys.argv[3] 

x = 0 

# only a tag is pushed to server, nothing to check 
if ref.find('refs/tags/') >= 0: 
    if len(ref.strip('refs/tags/')) > 25: 
    print 'tag name is longer than 25 characters' 
    exit(1) 
    else: 
    exit(0) 
# either a new branch is pushed or an empty repo is being pushed 
if old == '0000000000000000000000000000000000000000': 
    heads = commands.getoutput("git for-each-ref --format='%(refname)' 'refs/heads/*'") 
    heads = heads.replace(ref+'\n','').replace('\n',' ') 
    hashes = commands.getoutput('git log '+new+' --pretty=%H --not '+heads).split('\n') 
else: 
    hashes = commands.getoutput('git log '+old+'..'+new+' --pretty=%H').split('\n') 

for hash in hashes: 
    subject = commands.getoutput('git show '+hash+' --format=%s --summary').split('\n') 
    body = commands.getoutput('git show '+hash+' --format=%b --summary').split('\n') 

    if len(subject[0]) > 75: 
    print 
    print 'commit: '+hash 
    print 'bad commit message(s): header line is too long or second line is not blank (max 75 chars)' 
    print 'bad line: "%s"' % subject[0] 
    print 'length of header line: %d' % len(subject[0]) 
    print 'try again with correct message format' 
    print 
    x = 1 

    for line in body: 
    if len(line) > 75: 
     print 
     print 'commit: '+hash 
     print 'bad commit message(s): description lines are too long (max 75 chars)' 
     print 'bad line: "%s"' % line 
     print 'length of line: %d' % len(line) 
     print 'try again with correct message format' 
     print 
     x = 1 

if x == 0: 
    exit(0) 
else: 
    exit(1) 
+0

Usar 'refs/heads/*' en 'for-each-ref' no es una buena idea. No coincidirá con ninguna rama con barras en el nombre (por ejemplo, 'foo/bar'). Deberías usar 'refs/heads /' (no '*'). Pero, vea la respuesta de José a continuación para una alternativa más simple. – MadScientist

3

He resuelto esto para mi actualización de gancho utilizando la siguiente:

if [ "$oldrev" -eq 0 ]; then 
git log "$(git show-branch --merge-base)".."$newrev"; else 
foo; 
fi 
+0

Esto no funcionará en absoluto si está dentro de un gancho, especialmente si tiene más de 25 sucursales en su repositorio. – MadScientist

9

Cuando $oldrev es todo ceros, un git rev-list comando diferente hace todo lo que necesita:

git rev-list $newrev --not --branches=* 

te dará una lista de revisiones accesibles desde $newrev pero no desde ninguna rama.

Tenga en cuenta que esto definitivamente hace no hacer lo mismo que cuando git rev-list $oldrev..$newrev OLDREV es no todos los ceros, así que es conveniente para comprobar cuyo caso en que está y escoger el comando adecuado para funcionar.

+1

Aunque en realidad esto funciona _en pre-receive y update hooks_ porque cuando esos hooks se ejecutan, ¡la nueva rama aún no está allí! ¡Bonito! – MadScientist

+0

¿No te hará esto también refs de antes de oldrev, en el caso de que no sean todos ceros? – Cascabel

+1

@Jefromi ¿qué quieres decir? El comando anterior le dará una lista de todas las confirmaciones que no están referenciadas desde ninguna rama. En los desencadenadores de actualización y pre-recepción, se trata de los nuevos commits que se agregan como parte del push: la bifurcación de la rama no existe (si es nueva) o no se ha movido (si existe). Esto no funciona en un enlace posterior a la recepción, pero de eso no se trataba la pregunta. No entiendo por qué esto es downvoted: es la respuesta más simple, más limpia A LA PREGUNTA PREGUNTADA. – MadScientist