Scrivere un hook post-ricezione git per gestire un ramo specifico


107

Ecco il mio attuale hook in un semplice repo che risiede nel server dell'azienda: git push origin master questo hook spinge ad Assembla. Quello di cui ho bisogno è di spingere solo un ramo (master, idealmente) quando qualcuno invia le modifiche a quel ramo sul nostro server e ignorare i push ad altri rami. È possibile selezionare il ramo da un semplice repository e inviare solo quel ramo ad Assembla?


Cosa intendi? git push origin mastersposterà il masterramo solo al origintelecomando, che presumo sia definito come Assembla. Stai dicendo che devi attivare il gancio solo quando qualcuno spinge master, al contrario di feature1, o qualcosa del genere?
Stefan Kendall

@Stefan Esattamente quello. Non sono riuscito a trovare la parola, hehe.
Jorge Guberte

Risposte:


386

Un hook post-ricezione riceve i suoi argomenti da stdin, nella forma <oldrev> <newrev> <refname>. Poiché questi argomenti provengono da stdin, non da un argomento della riga di comando, è necessario utilizzare al readposto di $1 $2 $3.

L'hook post-ricezione può ricevere più rami contemporaneamente (ad esempio se qualcuno fa a git push --all), quindi dobbiamo anche avvolgere il readin un whileciclo.

Uno snippet funzionante ha un aspetto simile a questo:

#!/bin/bash
while read oldrev newrev refname
do
    branch=$(git rev-parse --symbolic --abbrev-ref $refname)
    if [ "master" = "$branch" ]; then
        # Do something
    fi
done

2
"==" non funziona per me. Con il singolo "=" funziona bene per me.
Ray

1
Mi dispiace aprire una vecchia discussione, ma ricevo un errore nell'istruzione if. fatale: il terminale remoto si è bloccato in modo imprevisto. errore: errore nel demultiplexer di banda laterale. Ripeterà il ramo $ al di fuori dell'istruzione if.
gin93r

5
@ Ray, hai #!/bin/shinvece di #!/bin/bash?
navetta87

2
Un rischio a cui posso pensare sarebbero i tag, poiché i loro nomi possono sovrapporsi ai nomi dei rami. Se cerchi refs/heads/masterinvece di refs/tags/masterte dovrebbe essere a posto. Potrebbero esserci altri casi limite come questo a cui non riesco a pensare. Potrebbe essere una buona domanda StackOverflow a sé stante.
pauljz

1
@pauljz che uso in if branch=$(git rev-parse --symbolic --abbrev-ref $refname 2>/dev/null); thenmodo che git non si lamenti quando rimuovo un ramo.
Jérôme

8

L'ultimo parametro che un hook post-ricezione ottiene su stdin è quello che ref è stato modificato, quindi possiamo usarlo per verificare se quel valore era "refs / heads / master". Un po 'di rubino simile a quello che uso in un hook post-ricezione:

STDIN.each do |line|
    (old_rev, new_rev, ref_name) = line.split
    if ref_name =~ /master/
         # do your push
    end
end

Nota che ottiene una linea per ogni ref che è stato spinto, quindi se hai spinto più del semplice master, funzionerà comunque.


Grazie per l'esempio di Ruby. Farò qualcosa di simile a questo.
Leif

6

La risposta di Stefan non ha funzionato per me, ma questo ha funzionato:

#!/bin/bash

echo "determining branch"

if ! [ -t 0 ]; then
  read -a ref
fi

IFS='/' read -ra REF <<< "${ref[2]}"
branch="${REF[2]}"

if [ "master" == "$branch" ]; then
  echo 'master was pushed'
fi

if [ "staging" == "$branch" ]; then
  echo 'staging was pushed'
fi

echo "done"

Ha funzionato per me per i rami con un nome semplice (master, test, ecc.), Ma quando ho il nome del ramo come: prod12 / proj250 / ropesPatch12. non funziona bene. Hai una soluzione che possa funzionare con quei caratteri speciali?
Shachar Hamuzim Rajuan

3

Nessuna delle soluzioni sopra ha funzionato per me. Dopo molto, molto debug, si scopre che l'uso del comando 'read' non funziona - invece, l'analisi degli argomenti della riga di comando nel solito modo funziona bene.

Ecco l'esatto hook post-aggiornamento che ho appena testato con successo su CentOS 6.3.

#!/bin/bash

echo "determining branch"

branch=`echo $1 | cut -d/ -f3`

if [ "master" == "$branch" ]; then
    echo "master branch selected"
fi

if [ "staging" == "$branch" ]; then
    echo "staging branch selected"
fi

exec git update-server-info

AGGIORNAMENTO: su una nota ancora più strana, l'hook di pre-ricezione prende il suo input tramite stdin, quindi leggi con 'read' (wow, non avrei mai pensato di dirlo). L'hook post-aggiornamento funziona ancora con $ 1 per me.


2
Per quel che vale, le soluzioni di cui sopra potrebbero non aver funzionato perché sono specifiche per post-receiveganci, non per post-updateganci. Prendono il loro contributo in modi diversi.
pauljz

post-receiveprende stdin come indicato qui: git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
h4xnoodle

1

La risposta di @pauljz funziona bene per alcuni hook git come pre-push, ma pre-commitnon ha accesso a quelle variabilioldrev newrev refname

Quindi ho creato questa versione alternativa che funziona per pre-commit, o davvero e hook. Questo è un pre-commithook che eseguirà uno huskyscript se NON siamo sul masterramo.

#!/bin/bash
# git 'commit' does not have access to these variables: oldrev newrev refname
# So get the branch name off the head

branchPath=$(git symbolic-ref -q HEAD) # Something like refs/heads/myBranchName
branch=${branchPath##*/}      # Get text behind the last / of the branch path

echo "Head: $branchPath";
echo "Current Branch: $branch";

if [ "master" != "$branch" ]; then

   # If we're NOT on the Master branch, then Do something
   # Original Pre-push script from husky 0.14.3

   command_exists () {
     command -v "$1" >/dev/null 2>&1
   }

   has_hook_script () {
     [ -f package.json ] && cat package.json | grep -q "\"$1\"[[:space:]]*:"
   }

   cd "frontend" # change to your project directory, if .git is a level higher

   # Check if precommit script is defined, skip if not
   has_hook_script precommit || exit 0

   # Node standard installation
   export PATH="$PATH:/c/Program Files/nodejs"

   # Check that npm exists
   command_exists npm || {
     echo >&2 "husky > can't find npm in PATH, skipping precommit script in package.json"
     exit 0
   }

   # Export Git hook params
   export GIT_PARAMS="$*"

   # Run npm script
   echo "husky > npm run -s precommit (node `node -v`)"
   echo

   npm run -s precommit || {
     echo
     echo "husky > pre-commit hook failed (add --no-verify to bypass)"
     exit 1
   }
fi

Spero che aiuti qualcuno. Puoi facilmente modificare per le tue esigenze, qualsiasi cosa tra le istruzioni ife fi.


0

Avevo scritto uno script PHP per me stesso per eseguire questa funzionalità.

https://github.com/fotuzlab/githubdump-php

Ospita questo file sul tuo server, preferibilmente root repository e definisci l'URL nei webhook github. Cambia 'allcommits' sulla riga 8 con il nome della tua filiale e aggiungi il tuo codice / funzione alla riga 18.

per esempio

function githubdump($payload_object) {
    // Write your code here.
    exec('git push origin master');
}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.