Menulis hook pasca-terima git untuk menangani cabang tertentu

107

Inilah hook saya saat ini dalam repo kosong yang tinggal di server perusahaan: git push origin master Hook ini mendorong ke Assembla. Yang saya perlukan adalah mendorong hanya satu cabang (master, idealnya) ketika seseorang mendorong perubahan ke cabang itu di server kami, dan mengabaikan dorongan ke cabang lain. Apakah mungkin untuk memilih cabang dari repo telanjang dan hanya mendorong cabang itu ke Assembla?

Jorge Guberte
sumber
Maksud kamu apa? git push origin masterhanya akan mendorong mastercabang ke originremote, yang saya asumsikan didefinisikan sebagai Assembla. Apakah Anda mengatakan bahwa Anda perlu memicu kail hanya ketika seseorang mendorong master, sebagai lawan feature1, atau sesuatu seperti itu?
Stefan Kendall
@ Stefan Persis seperti itu. Saya tidak bisa menemukan kata itu, hehe.
Jorge Guberte

Jawaban:

386

Hook pasca-terima mendapatkan argumennya dari stdin, dalam bentuk <oldrev> <newrev> <refname>. Karena argumen ini berasal dari stdin, bukan dari argumen baris perintah, Anda perlu menggunakan readbukan $1 $2 $3.

Hook pasca-terima dapat menerima banyak cabang sekaligus (misalnya jika seseorang melakukan a git push --all), jadi kita juga perlu membungkusnya readdalam satu whilelingkaran.

Cuplikan yang berfungsi terlihat seperti ini:

#!/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
sumber
2
"==" tidak bekerja untuk saya. Dengan single "=" bekerja dengan baik untuk saya.
Ray
1
Maaf memunculkan utas lama, tetapi saya mendapatkan kesalahan di pernyataan if. fatal: ujung remote tiba-tiba terputus. error: error di sideband demultiplexer. Ini akan menggemakan $ branch di luar pernyataan if.
gin93r
5
@Ray, apakah Anda memiliki #!/bin/shbukan #!/bin/bash?
antar
2
Satu risiko yang dapat saya pikirkan adalah tag, karena nama mereka dapat tumpang tindih dengan nama cabang. Jika Anda mencari refs/heads/masterbukannya refs/tags/masterAnda harus baik-baik saja. Mungkin ada kasus tepi lain seperti ini yang tidak bisa saya pikirkan. Ini bisa menjadi pertanyaan StackOverflow yang bagus dengan sendirinya.
pauljz
1
@pauljz saya gunakan if branch=$(git rev-parse --symbolic --abbrev-ref $refname 2>/dev/null); thenagar git tidak mengeluh ketika saya menghapus cabang.
Jérôme
8

Parameter terakhir yang didapat hook pasca-terima pada stdin adalah ref yang diubah, jadi kita bisa menggunakannya untuk memeriksa apakah nilai itu adalah "refs / heads / master". Sedikit ruby ​​yang mirip dengan yang saya gunakan di hook pasca-terima:

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

Perhatikan bahwa itu mendapat garis untuk setiap ref yang didorong, jadi jika Anda mendorong lebih dari sekadar master, itu akan tetap berfungsi.

ebneter
sumber
Terima kasih atas contoh Ruby. Saya akan melakukan sesuatu yang mirip dengan ini.
Leif
6

Jawaban Stefan tidak berhasil untuk saya, tetapi ini berhasil:

#!/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 Sebaliknya
sumber
Bekerja untuk saya untuk cabang dengan nama sederhana (master, test, dll.), Tetapi ketika saya memiliki nama cabang seperti: prod12 / proj250 / ropesPatch12. itu tidak bekerja dengan baik. Apakah Anda memiliki solusi yang dapat bekerja dengan karakter khusus tersebut?
Shachar Hamuzim Rajuan
3

Tidak satu pun dari solusi di atas yang berhasil untuk saya. Setelah banyak, banyak debugging, ternyata menggunakan perintah 'read' tidak berfungsi - sebagai gantinya, mengurai argumen baris perintah dengan cara biasa berfungsi dengan baik.

Berikut adalah pengait pasca-pembaruan yang baru saja berhasil saya uji sekarang di 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: pada catatan yang lebih aneh, hook pra-terima mengambil inputnya melalui stdin, oleh karena itu baca dengan 'read' (wow, tidak pernah terpikir saya akan mengatakan itu). Pengait pasca-pembaruan masih berfungsi dengan $ 1 untuk saya.

razvan
sumber
2
Untuk apa nilainya, solusi di atas mungkin tidak berhasil karena khusus untuk post-receivepengait, bukan post-updatepengait. Mereka menerima masukan mereka dengan cara yang berbeda.
pauljz
post-receivemengambil stdin seperti yang disebutkan di sini: git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
h4xnoodle
1

Jawaban dari @pauljz berfungsi dengan baik untuk kait git tertentu seperti pre-push, tetapi pre-committidak memiliki akses ke variabel tersebutoldrev newrev refname

Jadi saya membuat versi alternatif ini yang berfungsi untuk pre-commit, atau really and hook. Ini adalah pre-commithook yang akan menjalankan huskyskrip jika kita TIDAK berada di mastercabang.

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

Saya harap itu membantu seseorang. Anda dapat dengan mudah memodifikasi untuk kebutuhan Anda, apa pun di antara pernyataan ifdan fi.

TetraDev
sumber
0

Saya telah menulis skrip PHP untuk diri saya sendiri untuk melakukan fungsi ini.

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

Host file ini di server Anda, sebaiknya repo root dan tentukan url di webhook github. Ubah 'allcommits' di baris 8 dengan nama cabang Anda dan tambahkan kode / fungsi Anda di baris 18.

misalnya

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

Pendekatan sederhana, dalam git hookmenulis

read refname
echo $refname

Sederhana - info lebih lanjut tentang sistem pengait tautan yang hebat ini

Haris Krajina
sumber