Schreiben eines Git-Post-Receive-Hooks für einen bestimmten Zweig

107

Hier ist mein aktueller Hook in einem nackten Repo, das sich auf dem Server des Unternehmens befindet: git push origin master Dieser Hook wird an Assembla weitergeleitet. Was ich brauche, ist, nur einen Zweig (im Idealfall Master) zu pushen, wenn jemand Änderungen an diesem Zweig auf unserem Server überträgt, und Pushs an andere Zweige zu ignorieren. Ist es möglich, den Zweig aus einem Bare-Repo auszuwählen und nur diesen Zweig nach Assembla zu verschieben?

Jorge Guberte
quelle
Was meinst du? git push origin masterschiebt nur den masterZweig zur originFernbedienung, von der ich annehme, dass sie als Assembla definiert ist. Wollen Sie damit sagen , dass Sie brauchen auslösen den Haken nur , wenn jemand drückt zu master, im Gegensatz zu feature1, oder so etwas?
Stefan Kendall
@Stefan Genau das. Ich konnte das Wort nicht finden, hehe.
Jorge Guberte

Antworten:

386

Ein Post-Receive-Hook erhält seine Argumente von stdin in der Form <oldrev> <newrev> <refname>. Da diese Argumente von stdin stammen und nicht von einem Befehlszeilenargument, müssen Sie readstattdessen verwenden $1 $2 $3.

Der Post-Receive-Hook kann mehrere Zweige gleichzeitig empfangen (z. B. wenn jemand a ausführt git push --all), daher müssen wir den auch readin eine whileSchleife einschließen.

Ein funktionierendes Snippet sieht ungefähr so ​​aus:

#!/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
quelle
2
Das "==" funktioniert bei mir nicht. Mit Single "=" funktioniert das bei mir gut.
Ray
1
Es tut mir leid, einen alten Thread aufzurufen, aber bei der if-Anweisung wird eine Fehlermeldung angezeigt. tödlich: Das entfernte Ende legte unerwartet auf. Fehler: Fehler im Seitenband-Demultiplexer. Der $ -Zweig wird außerhalb der if-Anweisung wiedergegeben.
Gin93r
5
@ Ray, hast du #!/bin/shstatt #!/bin/bash?
Shuttle87
2
Ein Risiko, an das ich denken kann, wären Tags, da sich ihre Namen mit Zweignamen überschneiden können. Wenn Sie refs/heads/masterstattdessen suchen refs/tags/master, sollten Sie in Ordnung sein. Es kann andere Randfälle wie diesen geben, an die ich nicht denken kann. Es könnte eine gute StackOverflow-Frage für sich sein.
Pauljz
1
@pauljz Ich benutze, if branch=$(git rev-parse --symbolic --abbrev-ref $refname 2>/dev/null); thendamit git sich nicht beschwert, wenn ich einen Zweig entferne.
Jérôme
8

Der letzte Parameter, den ein Post-Receive-Hook auf stdin erhält, ist der, der ref geändert wurde. Daher können wir damit überprüfen, ob dieser Wert "refs / Heads / Master" war. Ein bisschen Rubin ähnlich dem, was ich in einem Post-Receive-Hook verwende:

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

Beachten Sie, dass für jede Referenz, die gedrückt wurde, eine Zeile angezeigt wird. Wenn Sie also mehr als nur den Master gedrückt haben, funktioniert dies weiterhin.

ebneter
quelle
Danke für das Ruby-Beispiel. Ich werde etwas Ähnliches tun.
Leif
6

Stefans Antwort hat bei mir nicht funktioniert, aber das hat funktioniert:

#!/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
quelle
Arbeitete für mich für Zweige mit einem einfachen Namen (Master, Test usw.), Aber wenn ich einen Filialnamen wie: prod12 / proj250 / ropesPatch12 habe. es funktioniert nicht gut. Haben Sie eine Lösung, die mit diesen Sonderzeichen funktioniert?
Shachar Hamuzim Rajuan
3

Keine der oben genannten Lösungen hat bei mir funktioniert. Nach vielem Debuggen stellt sich heraus, dass die Verwendung des Befehls 'read' nicht funktioniert. Stattdessen funktioniert das Parsen von Befehlszeilenargumenten auf die übliche Weise einwandfrei.

Hier ist der genaue Hook nach dem Update, den ich gerade erfolgreich unter CentOS 6.3 getestet habe.

#!/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: Noch seltsamer ist, dass der Pre-Receive-Hook seine Eingabe über stdin erhält und daher mit 'read' liest (wow, hätte nie gedacht, dass ich das sagen würde). Der Post-Update-Hook funktioniert bei mir immer noch mit 1 US-Dollar.

Razvan
quelle
2
Für das, was es wert ist, haben die oben genannten Lösungen möglicherweise nicht funktioniert, da sie speziell für post-receiveHaken und nicht für post-updateHaken bestimmt sind. Sie nehmen ihre Beiträge auf unterschiedliche Weise auf.
Pauljz
post-receivenimmt stdin wie hier angegeben: git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
h4xnoodle
1

Die Antwort von @pauljz funktioniert gut für bestimmte Git-Hooks wie pre-push, hat aber pre-commitkeinen Zugriff auf diese Variablenoldrev newrev refname

Also habe ich diese alternative Version erstellt, die für Pre-Commit oder wirklich und Hook funktioniert. Dies ist ein pre-commitHook, der ein huskySkript ausführt, wenn wir NICHT in der masterVerzweigung sind.

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

Ich hoffe das hilft jemandem. Sie können ganz einfach Änderungen an Ihren Anforderungen vornehmen, alles zwischen den Anweisungen ifund fi.

TetraDev
quelle
0

Ich hatte ein PHP-Skript für mich geschrieben, um diese Funktionalität auszuführen.

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

Hosten Sie diese Datei auf Ihrem Server, repo-Root und definieren Sie die URL in Github-Webhooks. Ändern Sie 'allcommits' in Zeile 8 mit Ihrem Filialnamen und fügen Sie Ihren Code / Ihre Funktion in Zeile 18 hinzu.

z.B

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

Einfacher Ansatz, git hookschriftlich

read refname
echo $refname

Einfach - mehr Infos zu diesem großartigen Link- Hooking-System

Haris Krajina
quelle