Escrevendo um gancho pós-recebimento git para lidar com um branch específico

107

Este é meu gancho atual em um repositório vazio que reside no servidor da empresa: git push origin master Este gancho empurra para Assembla. O que eu preciso é enviar apenas um branch (master, idealmente) quando alguém enviar alterações para aquele branch em nosso servidor e ignorar os push para outros branches. É possível selecionar o branch de um repositório simples e enviar apenas esse branch para o Assembla?

Jorge Guberte
fonte
O que você quer dizer? git push origin masterirá apenas enviar o masterbranch para o originremoto, que suponho que esteja definido como Assembla. Você está dizendo que precisa acionar o gancho apenas quando alguém empurra master, em vez de feature1ou algo assim?
Stefan Kendall,
@Stefan Exatamente isso. Não consegui encontrar a palavra, hehe.
Jorge Guberte

Respostas:

386

Um gancho pós-recebimento obtém seus argumentos de stdin, no formulário <oldrev> <newrev> <refname>. Visto que esses argumentos vêm de stdin, não de um argumento de linha de comando, você precisa usar em readvez de $1 $2 $3.

O gancho pós-recebimento pode receber vários ramos de uma vez (por exemplo, se alguém fizer um git push --all), portanto, também precisamos envolvê-lo readem um whileloop.

Um snippet de trabalho é semelhante a este:

#!/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
fonte
2
O "==" não funciona para mim. Com um único "=" funciona bem para mim.
Ray
1
Desculpe por trazer um tópico antigo, mas estou recebendo um erro na instrução if. fatal: o terminal remoto desligou inesperadamente. erro: erro no demultiplexador de banda lateral. Ele irá ecoar a ramificação $ fora da instrução if.
gin93r
5
@Ray, você tem em #!/bin/shvez de #!/bin/bash?
translado 87 de
2
Um risco em que posso pensar são as tags, já que seus nomes podem se sobrepor aos nomes dos ramos. Se você procurar ao refs/heads/masterinvés de refs/tags/mastervocê, tudo bem. Pode haver outros casos extremos como este, mas não consigo pensar. Pode ser uma boa pergunta sobre StackOverflow por si só.
pauljz
1
@pauljz eu uso if branch=$(git rev-parse --symbolic --abbrev-ref $refname 2>/dev/null); thenpara que o git não reclame quando removo um branch.
Jérôme
8

O último parâmetro que um gancho pós-recebimento obtém em stdin é o que foi alterado, portanto, podemos usá-lo para verificar se esse valor era "refs / heads / master". Um pouco de rubi semelhante ao que uso em um gancho pós-recebimento:

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

Observe que ele obtém uma linha para cada ref que foi empurrado, então se você empurrou mais do que apenas o mestre, ainda funcionará.

ebneter
fonte
Obrigado pelo exemplo Ruby. Vou fazer algo semelhante a isso.
Leif
6

A resposta de Stefan não funcionou para mim, mas este fez:

#!/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
fonte
Funcionou para mim para branches com um nome simples (master, test, etc.), Mas quando tenho nome de branch como: prod12 / proj250 / ropesPatch12. não funciona muito bem. Você tem uma solução que pode funcionar com esses caracteres especiais?
Shachar Hamuzim Rajuan
3

Nenhuma das soluções acima funcionou para mim. Depois de muita, muita depuração, descobriu-se que usar o comando 'ler' não funciona - em vez disso, a análise de argumentos de linha de comando da maneira usual funciona bem.

Aqui está o gancho pós-atualização exato que testei com sucesso agora no 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

ATUALIZAÇÃO: em uma nota ainda mais estranha, o gancho de pré-recepção recebe sua entrada via stdin, portanto, lê com 'ler' (uau, nunca pensei que diria isso). O gancho pós-atualização ainda funciona com $ 1 para mim.

Razvan
fonte
2
Pelo que vale a pena, as soluções acima podem não ter funcionado porque são especificamente para post-receiveganchos, não para post-updateganchos. Eles recebem suas opiniões de maneiras diferentes.
pauljz
post-receiveleva stdin conforme indicado aqui: git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
h4xnoodle
1

A resposta de @pauljz funciona bem para certos git hooks como pre-push, mas pre-commitnão tem acesso a essas variáveisoldrev newrev refname

Então eu criei esta versão alternativa que funciona para pré-commit, ou realmente e hook. Este é um pre-commitgancho que executará um huskyscript se NÃO estivermos no 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

Espero que ajude alguém. Você pode modificar facilmente de acordo com suas necessidades, qualquer coisa entre as instruções ife fi.

TetraDev
fonte
0

Eu mesmo escrevi um script PHP para fazer essa funcionalidade.

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

Hospede esse arquivo em seu servidor, de preferência repo root e defina a url nos webhooks do github. Altere 'allcommits' na linha 8 com o nome do seu ramo e adicione seu código / função na linha 18.

por exemplo

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

Abordagem simples, por git hookescrito

read refname
echo $refname

Simples - mais informações sobre este ótimo sistema de link hooking

Haris Krajina
fonte