Escribir un gancho de post-recepción de git para tratar con una rama específica

107

Aquí está mi gancho actual en un repositorio vacío que vive en el servidor de la compañía: git push origin master Este gancho empuja a Assembla. Lo que necesito es empujar solo una rama (maestra, idealmente) cuando alguien empuja cambios a esa rama en nuestro servidor e ignorar los empujes a otras ramas. ¿Es posible seleccionar la rama de un repositorio simple y enviar solo esa rama a Assembla?

Jorge Guberte
fuente
¿Qué quieres decir? git push origin mastersolo empujará la masterrama hacia el origincontrol remoto, que supongo que se define como Assembla. ¿Estás diciendo que necesitas activar el gancho solo cuando alguien presiona master, en lugar de feature1, o algo así?
Stefan Kendall
@Stefan Exactamente eso. No pude encontrar la palabra, jeje.
Jorge Guberte

Respuestas:

386

Un gancho posterior a la recepción obtiene sus argumentos de stdin, en la forma <oldrev> <newrev> <refname>. Dado que estos argumentos provienen de stdin, no de un argumento de línea de comando, debe usar en readlugar de $1 $2 $3.

El gancho posterior a la recepción puede recibir varias ramas a la vez (por ejemplo, si alguien hace a git push --all), por lo que también debemos envolverlo readen un whilebucle.

Un fragmento de trabajo se parece a esto:

#!/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
fuente
2
El "==" no me funciona. Con solo "=" funciona bien para mí.
Ray
1
Lamento traer un hilo antiguo, pero recibo un error en la declaración if. fatal: el extremo remoto colgó inesperadamente. error: error en el demultiplexor de banda lateral. Hará eco de la rama $ fuera de la declaración if.
gin93r
5
@Ray, ¿tienes en #!/bin/shlugar de #!/bin/bash?
traslado 87
2
Un riesgo en el que puedo pensar serían las etiquetas, ya que sus nombres pueden superponerse con los nombres de las ramas. Si busca en refs/heads/masterlugar de refs/tags/masterusted debería estar bien. Sin embargo, puede haber otros casos extremos como este en los que no puedo pensar. Podría ser una buena pregunta de StackOverflow por derecho propio.
Pauljz
1
@pauljz lo uso if branch=$(git rev-parse --symbolic --abbrev-ref $refname 2>/dev/null); thenpara que git no se queje cuando elimino una rama.
Jérôme
8

El último parámetro que obtiene un gancho posterior a la recepción en stdin es qué se cambió ref, por lo que podemos usarlo para verificar si ese valor era "refs / heads / master". Un poco de rubí similar al que uso en un gancho posterior a la recepción:

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

Tenga en cuenta que obtiene una línea por cada ref que se presionó, por lo que si presionó más que solo master, seguirá funcionando.

ebneter
fuente
Gracias por el ejemplo de Ruby. Voy a hacer algo similar a esto.
Leif
6

La respuesta de Stefan no funcionó para mí, pero esto sí:

#!/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 Rather
fuente
Me funcionó para sucursales con un nombre simple (maestro, prueba, etc.), pero cuando tengo un nombre de sucursal como: prod12 / proj250 / ropesPatch12. no funciona muy bien. ¿Tiene una solución que pueda funcionar con esos caracteres especiales?
Shachar Hamuzim Rajuan
3

Ninguna de las soluciones anteriores funcionó para mí. Después de mucha, mucha depuración, resulta que usar el comando 'leer' no funciona; en cambio, analizar los argumentos de la línea de comando de la forma habitual funciona bien.

Aquí está el gancho posterior a la actualización exacto que acabo de probar con éxito ahora en 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

ACTUALIZACIÓN: en una nota aún más extraña, el gancho de pre-recepción toma su entrada a través de stdin, por lo tanto, lea con 'leer' (wow, nunca pensé que diría eso). El gancho posterior a la actualización todavía funciona con $ 1 para mí.

razvan
fuente
2
Por lo que vale, es posible que las soluciones anteriores no hayan funcionado porque son específicamente para post-receiveganchos, no para post-updateganchos. Reciben sus aportes de diferentes formas.
pauljz
post-receivetoma stdin como se indica aquí: git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
h4xnoodle
1

La respuesta de @pauljz funciona bien para ciertos ganchos de git como pre-push, pero pre-commitno tiene acceso a esas variablesoldrev newrev refname

Así que creé esta versión alternativa que funciona para la confirmación previa, o realmente y enganchar. Este es un pre-commitgancho que ejecutará un huskyscript si NO estamos en la masterrama.

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

Espero que ayude a alguien. Puede modificar fácilmente según sus necesidades, cualquier cosa entre las declaraciones ify fi.

TetraDev
fuente
0

Había escrito un script PHP para mí mismo para hacer esta funcionalidad.

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

Aloje este archivo en su servidor, preferiblemente la raíz del repositorio y defina la URL en los webhooks de github. Cambie 'allcommits' en la línea 8 con el nombre de su sucursal y agregue su código / función en la línea 18.

p.ej

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

Enfoque simple, por git hookescrito

read refname
echo $refname

Simple: más información sobre este excelente sistema de enlace de enlaces

Haris Krajina
fuente