2010-11-09 15 views
24

Un po 'indietro I asked our developers to use rebase instead of merge before pushing. Eliminare le unioni banali rende molto più facile seguire il grafico del commit (es: gitk, git log).blocco push di banale unione a git server

A volte la gente ancora accidentalmente fa una fusione banale, quindi spinge. Qualcuno ha a portata di mano o ha suggerimenti per scrivere un hook lato server che blocca le fusioni banali?

Per "unione banale", intendo un'unione senza conflitti. Here's an example e here's a better explanation of a trivial merge in git.

Aggiornamento mer Nov 10 01:26:41 UTC 2010: ottimi commenti, tutto! Grazie.

  • Si consideri il seguente: tutto quello che sto veramente chiedendo alle persone di fare è questo:
    • se git pull --ff-only fallisce, effettuare git pull --rebase invece di git pull
  • git.git ha solo uno o due committer, giusto? In teoria, dovrebbe essere facile seguire il grafico del commit, ma mi sembra abbastanza complicato.

aggiornamento Gio 11 Nov 23:49:35 UTC 2010:

Aggiornamento mer 15 dicembre 18:34:52 UTC 2010:

  • adymitruk è vicino! Un solo caso è ancora irrisolto: le unioni non banali devono ancora funzionare.
  • Un numero completo test suite è disponibile, verificarlo.
  • Ho chiesto aiuto su un (il?) git mailing list.
+0

Come si definisce "unione banale?" Come pensi di essere in grado di distinguere tra fusioni banali e fusioni non banali? – cdhowie

+0

L'ho aggiunto, iniziando con * Per "unione banale" ... * –

+2

Esistono molti argomenti contro la rebasing anziché l'unione. Personalmente odio essere costretto a ribattere. Basta dire;) –

risposta

8

Mi sono imbattuto in questo pezzo di codice, mentre cercavo di trovare una soluzione. Non fa esattamente quello che vuoi, ma dovrebbe essere ez per aggiungere nomi di rami extra sull'istruzione if.

Lavori per me, finora. forza il comando pull --rebase per lo stesso ramo e consente il regolare merging con altri rami.

Tutti i crediti vanno all'autore originale.

#!/bin/bash 
# 
# This git update hook will refuse unnecessary merge commits caused by pulling 
# from being pushed to a shared repository. These commits make following the 
# history of a project difficult and are always avoidable with rebasing. 
# 
# by Scott Kyle (appden) 
# modified by Olivier Refalo (orefalo) 

refname="$1" 
oldrev="$2" 
newrev="$3" 

# if this is not run as a hook, you may have messed up 
if [ -z "$GIT_DIR" -o -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then 
    echo "Usage: GIT_DIR=<path> $0 <ref> <oldrev> <newrev>" >&2 
    exit 1 
fi 

# if the new revision is all 0's then it's a commit to delete a ref 
zero="0000000000000000000000000000000000000000" 
# also check if the new revision is not a commit or is not a fast forward 
# detect branch deletion, branch creation... and more 
if [ "${refname#refs/heads/}" = "master" ] || [ "$newrev" = "$zero" ] || [ "$oldrev" = "$zero" ] || [ $(git cat-file -t $newrev) != "co 
mmit" ] || [ $(git merge-base $oldrev $newrev) != "$oldrev" ]; then 
    exit 0 
fi 

# loop through merges in the push only following first parents 
for merge in $(git rev-list --first-parent --merges $oldrev..$newrev --); do 
    # lazily create the revision list of this branch prior to the push 
    [ -z "$revlist" ] && revlist=$(git rev-list $oldrev) 
    # check if the second parent of the merge is already in this branch 
    if grep -q $(git rev-parse $merge^2) <<< "$revlist"; then 
     cat >&2 <<-EOF 
      *** PUSH REJECTED *** 
      *** TRIVIAL merge detected on local branch ${refname#refs/heads/} 
      *** To fix: git rebase origin/${refname#refs/heads/} 
      *** 
      *** Next time use: git pull --rebase 
      *** 
      *** Permanent fix: git config [--global] branch.autosetuprebase always 
      *** Then for existing branches: git config branch.<name>.rebase true 
     EOF 
     exit 1 
    fi 
done 

echo -Info- Clean history successfully preserved! 
exit 0 
+1

Questo blocca anche le unioni non banali. Vedi https://gist.github.com/737842. Ho aggiunto questo codice a quell'elenco, basta digitare "make" per eseguire i test. –

+0

Quando viene distribuito sul server (hook di aggiornamento) obbliga gli utenti a "pull --rebase". Una fusione regolare da un altro ramo funziona bene, ma vedo che lo stesso ramo fallirà in un banale merge –

+0

Ah. Spiacente, dovresti leggere la tua descrizione più a fondo. Quando ho postato questa domanda un anno fa, penso che stavo cercando qualcosa che * avrebbe * permesso un'unione non banale da origine/master a padrone, quindi la gente potrebbe ancora fare fusioni. Mi sono imbattuto in diverse integrazioni nel mio vecchio lavoro (lavorando su Mifos) dove la rifondazione era difficile ma la fusione era facile. Ora che mi sento più a mio agio con rebase, probabilmente utilizzerò lo script di aggiornamento che hai presentato. Chiudiamo il libro su questo. Hai vinto! –

5

Questo aggiornamento gancio controllerà se si stanno spingendo a specifici rami (che permette le unioni banali in WIP, argomento e di altri rami).

Questo non si disturba con il resto dei genitori in caso di unione di polpo poiché fa riferimento solo al secondo genitore in ogni unione di commit che viene spinto. Sentiti libero di aggiornare la sceneggiatura.

AGGIORNAMENTO: i rami riservati devono esistere sul telecomando.

#!/bin/bash 
refname="$1" 
oldrev="$2" 
newrev="$3" 
branches="refs/heads/hotfixes refs/heads/dev refs/heads/qa refs/heads/master" 
cont="no" 
for branch in $branches ; do 
    if [[ $refname == $branch ]] ; then 
    cont="yes" 
    fi 
done 
if [[ $cont == "no" ]] ; then 
    exit 0 
fi 
echo "inspecting branch $refname for trivial merges" >&2 
hashes="$(git log --format=%H --merges $oldrev..$newrev)" 
for hash in $hashes ; do 
    echo "checking merge commit $hash" >&2 
    cont="no" 
    for branch in $branches ; do 
    if [[ $refname == $branch ]] ; then 
     continue 
    fi 
    # if [[ "$(git log --format=%H $hash^2 ^$branch | wc -l)" == "0" ]] ; then 
    if [[ "$(git log --format=%H $hash^2 ^$branch | wc -l)" == " 0" ]] ; then 
     cont="yes" 
    fi 
    done 
    if [[ $cont == "no" ]] ; then 
    echo "No trivial merges allowed. Please rebase and push again." >&2 
    exit 1 
    fi 
done 
exit 0 
+0

Grazie! Darò questo a un colpo e segnerò come risposta accettata se riesco a farlo funzionare. –

+0

@adymitruk - Si dovrebbe usare '&&' invece di 'AND'. Trarrebbe inoltre beneficio da alcune interruzioni di riga all'interno di '[[' e ']]'. – bstpierre

+0

Concordato .. questo era più codice pseudo. Si prega di suggerire un sostituto per la condizione if e modificheremo la risposta. –