Ecrire un hook post-receive git pour traiter une branche spécifique

107

Voici mon hook actuel dans un dépôt nu qui vit sur le serveur de l'entreprise: git push origin master Ce hook pousse à Assembla. Ce dont j'ai besoin, c'est de ne pousser qu'une seule branche (maître, idéalement) lorsque quelqu'un pousse des modifications à cette branche sur notre serveur et d'ignorer les poussées vers d'autres branches. Est-il possible de sélectionner la branche à partir d'un dépôt nu et de ne pousser que cette branche vers Assembla?

Jorge Guberte
la source
Que voulez-vous dire? git push origin masterne poussera que la masterbranche vers la origintélécommande, qui, je suppose, est définie comme étant Assembla. Êtes-vous en train de dire que vous devez déclencher le crochet uniquement lorsque quelqu'un pousse master, par opposition à feature1ou quelque chose du genre?
Stefan Kendall
@Stefan Exactement cela. Je n'ai pas trouvé le mot, hehe.
Jorge Guberte

Réponses:

386

Un hook post-réception obtient ses arguments de stdin, sous la forme <oldrev> <newrev> <refname>. Étant donné que ces arguments proviennent de stdin et non d'un argument de ligne de commande, vous devez utiliser à la readplace de $1 $2 $3.

Le hook post-receive peut recevoir plusieurs branches à la fois (par exemple si quelqu'un fait a git push --all), nous devons donc également l'envelopper readdans une whileboucle.

Un extrait de code fonctionnel ressemble à ceci:

#!/bin/bash
while read oldrev newrev refname
do
    branch=$(git rev-parse --symbolic --abbrev-ref $refname)
    if [ "master" = "$branch" ]; then
        # Do something
    fi
done
pauljz
la source
2
Le "==" ne fonctionne pas pour moi. Avec single "=" fonctionne bien pour moi.
Ray
1
Désolé de faire apparaître un ancien fil, mais j'obtiens une erreur au niveau de l'instruction if. fatal: la télécommande a raccroché de manière inattendue. erreur: erreur dans le démultiplexeur de bande latérale. Il fera écho à la branche $ en dehors de l'instruction if.
gin93r
5
@ Ray, avez-vous à la #!/bin/shplace de #!/bin/bash?
navette87
2
Un risque auquel je peux penser serait les balises, car leurs noms peuvent chevaucher les noms de succursales. Si vous cherchez à la refs/heads/masterplace de refs/tags/mastervous, ça devrait aller. Il peut y avoir d'autres cas extrêmes comme celui-ci auxquels je ne pense pas. Cela pourrait être une bonne question StackOverflow à part entière.
pauljz
1
@pauljz J'utilise if branch=$(git rev-parse --symbolic --abbrev-ref $refname 2>/dev/null); thenpour que git ne se plaint pas lorsque je supprime une branche.
Jérôme
8

Le dernier paramètre qu'un hook de post-réception obtient sur stdin est ce que ref a été changé, nous pouvons donc l'utiliser pour vérifier si cette valeur était "refs / heads / master". Un peu de rubis similaire à ce que j'utilise dans un hook post-réception:

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

Notez qu'il obtient une ligne pour chaque ref qui a été poussé, donc si vous avez poussé plus que juste master, cela fonctionnera toujours.

Ebneter
la source
Merci pour l'exemple Ruby. Je vais faire quelque chose de similaire.
Leif
6

La réponse de Stefan n'a pas fonctionné pour moi, mais cela a fonctionné:

#!/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"
Dean plutôt
la source
A travaillé pour moi pour des branches avec un nom simple (master, test, etc.), mais quand j'ai un nom de branche tel que: prod12 / proj250 / ropesPatch12. ça ne marche pas trop bien. Avez-vous une solution qui peut fonctionner avec ces caractères spéciaux?
Shachar Hamuzim Rajuan
3

Aucune des solutions ci-dessus n'a fonctionné pour moi. Après beaucoup, beaucoup de débogage, il s'avère que l'utilisation de la commande 'read' ne fonctionne pas - à la place, l'analyse des arguments de ligne de commande de la manière habituelle fonctionne bien.

Voici le hook post-update exact que je viens de tester avec succès maintenant sur 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

UPDATE: sur une note encore plus étrange, le hook de pré-réception prend son entrée via stdin, donc lu avec 'read' (wow, je n'aurais jamais pensé que je dirais ça). Le hook post-update fonctionne toujours avec 1 $ pour moi.

Rasvan
la source
2
Pour ce que cela vaut, les solutions ci-dessus peuvent ne pas avoir fonctionné car elles sont spécifiquement destinées aux post-receivehameçons, pas aux post-updatehameçons. Ils prennent leur contribution de différentes manières.
pauljz
post-receiveprend stdin comme indiqué ici: git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
h4xnoodle
1

La réponse de @pauljz fonctionne bien pour certains hooks git comme pre-push, mais pre-commitn'a pas accès à ces variablesoldrev newrev refname

J'ai donc créé cette version alternative qui fonctionne pour le pré-commit, ou vraiment et hook. C'est un pre-commithook qui exécutera un huskyscript si nous ne sommes PAS sur la masterbranche.

#!/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

J'espère que cela aide quelqu'un. Vous pouvez facilement modifier selon vos besoins tout ce qui se trouve entre les instructions ifet fi.

TetraDev
la source
0

J'avais écrit un script PHP pour moi-même pour faire cette fonctionnalité.

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

Hébergez ce fichier sur votre serveur, de préférence repo root et définissez l'url dans les webhooks github. Changez 'allcommits' à la ligne 8 avec le nom de votre succursale et ajoutez votre code / fonction à la ligne 18.

par exemple

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