2010-08-18 12 views
26

Ho un problema con il gancio di 'aggiornamento'. Nel caso di una nuova filiale, ottiene un 0000000000000000000000000000000000000000 come 'oldrev'. E non so come gestire quel caso.Git ricevere/aggiornare ganci e nuovi rami

Abbiamo il requisito che ogni messaggio di commit faccia riferimento a un problema Jira valido. Quindi ho installato un hook di "aggiornamento" sul nostro repository centrale. Quel gancio ottiene un "oldrev" e un "newrev". Ho poi trasferirà a "git rev-list" come questo:

git rev-list $oldrev..$newrev

Questo mi dà l'elenco di tutti i regimi, che posso poi scorrere, e fare tutto ciò che devo fare.

Il problema è che, quando l'utente preme un nuovo ramo, il gancio ottiene 0000000000000000000000000000000000000000 come oldrev. E "git rev-list" semplicemente si lamenta con:

fatal: Invalid revision range 0000000000000000000000000000000000000000..21bac83b2

così come faccio a ottenere l'elenco di tutti i giri che si trovano su quel nuovo ramo? Ho cercato la rete per un bel po 'di tempo e non ho trovato nulla. L'esempio ganci ho trovato sia

  • non gestire il problema, e non con il messaggio di errore di cui sopra
  • in modo non corretto cercare di risolvere il problema impostando l'oldrev su "", che restituisce i risultati errati dal rev -list
  • semplicemente rinunciare quando incontrano che oldrev

Nessuno di questi suono particolarmente emozionante.

Quindi qualcuno ha qualche idea su come ottenere la risposta giusta in questo caso? Stavo pensando di interrogare git per "dammi tutti i giri che sono raggiungibili da newrev, ma non da nessuno degli altri rami (= tutti i rami eccetto quello nuovo)". Ma anche questo darebbe la risposta sbagliata se ci fosse stata una fusione tra il nuovo ramo e uno qualsiasi di quelli vecchi.

risposta

14

Il termine "risposta corretta" è un po 'ambiguo in questo caso. In realtà penso che "tutti i giri raggiungibili da newrev ma da nessun'altra parte" sia completamente corretto. Questo è vero anche se ci fosse un'unione: in questo caso, dovresti vedere i commit unici per il nuovo ref e il commit di unione, ma non i commit che sono stati uniti.

Quindi, direi, controllare se il "oldrev" è tutti zeri, e se lo è, agire di conseguenza:

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

Non sono sicuro che si tratti di qualcosa di strano con il mio ambiente o di un aggiornamento di git, ma la negazione sta rimuovendo i riferimenti sul ramo corrente. Devo fare qualcosa del genere: 'git rev-list $ (git for-each-ref --format = '% (refname)'" refs/heads/* "| grep -v '$ ref' | sed 's/^/\^/') "$ newrev" ' – mmalone

+1

Per l'uso negli hook' update' (e 'pre-receive'), come specificato nella domanda, queste risposte sono tutte più complicate e costose. La risposta di Joseph sotto è la più semplice e più efficiente; quella dovrebbe essere la risposta scelta IMO. – MadScientist

+0

@mmalone hai ragione. Ho dovuto aggiungere "| grep -v '$ rev'". Altrimenti ho sempre ottenuto risultati empy – dritan

7

ho capito io.

git log newref --non otherheads

è la chiave per ottenere tutti i registri di un ramo che non sono su qualsiasi altro ramo. Di seguito è riportato il mio script python per verificare la lunghezza massima della linea corretta dei messaggi di commit.

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

Usare 'refs/heads/*' in 'for-each-ref' non è una buona idea. Non corrisponderà a nessun ramo con barre nel nome (ad esempio, 'foo/bar'). Dovresti semplicemente usare 'refs/heads /' (no '*'). Ma, vedi la risposta di Joseph in basso per un'alternativa più semplice. – MadScientist

3

ho risolto questo per il mio gancio di aggiornamento utilizzando il seguente:

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

Questo non funzionerà affatto se ci si trova all'interno di un hook, specialmente se si hanno più di 25 rami nel proprio repository. – MadScientist

9

Quando $oldrev è tutti gli zeri, un diverso comando git rev-list fa tutto quello che serve:

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

vi darà un elenco di revisioni raggiungibile da $newrev ma non da alcuna succursale.

Si noti che questo sicuramente non fare la stessa cosa di quando git rev-list $oldrev..$newrev oldrev è non tutti gli zeri, quindi ti consigliamo di verificare qual caso siete in e scegliere il comando appropriato per l'esecuzione.

+1

Anche se in realtà funziona _in pre-ricevere e aggiornare i hook_ perché quando vengono eseguiti questi hook il nuovo ramo non è ancora lì! Bello! – MadScientist

+0

Anche questo non ti farà ottenere dei ref da prima di oldrev, nel caso in cui non siano tutti zeri? – Cascabel

+1

@Jefromi cosa intendi? Il comando sopra ti darà una lista di tutti i commit che non sono affatto referenziati da nessun ramo. Nei trigger di aggiornamento e pre-ricezione, si tratta dei nuovi commit che vengono aggiunti come parte del push: il refname del ramo non esiste (se è nuovo) o non è stato spostato (se esistente). Questo non funziona in un hook di post-ricezione, ma non è di questo che si trattava. Non capisco perché questo è downvoted: è la risposta più semplice, più pulita alla domanda CHIEDE. – MadScientist