Написание обработчика git post-receive для работы с конкретной веткой

107

Вот мой текущий крючок в голом репо, который находится на сервере компании: git push origin master Эти хуки подталкивают к Assembla. Мне нужно нажимать только одну ветку (в идеале - главную), когда кто-то отправляет изменения в эту ветку на нашем сервере, и игнорировать отправку в другие ветки. Можно ли выбрать ветку из чистого репо и отправить только эту ветку в Assembla?

Хорхе Губерте
источник
Что вы имеете в виду? git push origin masterбудет только отправлять masterветку на originудаленный компьютер, который, как я полагаю, определен как Assembla. Вы говорите, что вам нужно активировать крючок только тогда, когда кто-то толкает master, а не feature1что-то в этом роде?
Стефан Кендалл
@Stefan Именно так. Я не мог подобрать слова, хе-хе.
Хорхе Губерте 08

Ответы:

386

Ловушка post-receive получает свои аргументы из stdin в форме <oldrev> <newrev> <refname>. Поскольку эти аргументы поступают из стандартного ввода, а не из аргумента командной строки, вам нужно использовать readвместо $1 $2 $3.

Хук post-receive может получать сразу несколько веток (например, если кто-то делает git push --all), поэтому нам также нужно обернуть его readв whileцикл.

Рабочий фрагмент выглядит примерно так:

#!/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
источник
2
"==" у меня не работает. С одиночным "=" у меня работает хорошо.
Рэй
1
Извините за старую беседу, но я получаю сообщение об ошибке в операторе if. фатальный: удаленный конец неожиданно повесил трубку. error: ошибка в демультиплексоре боковой полосы. Он будет отображать ветку $ вне оператора if.
gin93r 07
5
@ Рэй, а у тебя #!/bin/shвместо #!/bin/bash?
Shuttle87,
2
Я могу придумать один риск, связанный с тегами, поскольку их имена могут совпадать с именами веток. Если вы будете искать refs/heads/masterвместо refs/tags/masterвас, все будет в порядке. Хотя могут быть и другие крайние случаи, о которых я не могу думать. Это может быть хороший вопрос по StackOverflow сам по себе.
pauljz
1
@pauljz Я использую, if branch=$(git rev-parse --symbolic --abbrev-ref $refname 2>/dev/null); thenчтобы git не жаловался, когда я удаляю ветку.
Жером
8

Последний параметр, который ловушка post-receive получает на stdin, - это то, что ref было изменено, поэтому мы можем использовать это, чтобы проверить, было ли это значение «refs / Heads / master». Немного рубина, похожего на то, что я использую в хуке после получения:

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

Обратите внимание, что он получает строку для каждой отправленной ссылки, поэтому, если вы нажали больше, чем просто master, она все равно будет работать.

эбнетер
источник
Спасибо за пример с Ruby. Я собираюсь сделать что-то подобное.
Лейф
6

Ответ Стефана не сработал для меня, но это сработало :

#!/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"
Дин Скорее
источник
Работал у меня для веток с простым именем (мастер, тест и т. Д.), Но когда у меня есть имя ветки, такое: prod12 / proj250 / ropesPatch12. это не работает хорошо. У вас есть решение, которое может работать с этими специальными символами?
Шахар Хамузим Раджуан
3

Ни одно из вышеперечисленных решений не помогло мне. После долгой отладки выясняется, что использование команды 'read' не работает - вместо этого обычный способ анализа аргументов командной строки работает нормально.

Вот точный хук после обновления, который я только что успешно протестировал на 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

ОБНОВЛЕНИЕ: на еще более странной ноте, хук pre-receive принимает ввод через stdin, поэтому читается с 'read' (вау, никогда не думал, что я скажу это). Хук после обновления по-прежнему работает для меня с 1 долларом.

разван
источник
2
Как бы то ни было, приведенные выше решения могли не сработать, потому что они предназначены специально для post-receiveкрючков, а не для post-updateкрючков. Они принимают свой вклад по-разному.
pauljz
post-receiveпринимает stdin, как указано здесь: git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
h4xnoodle
1

Ответ от @pauljz отлично работает для некоторых хуков git pre-push, но pre-commitне имеет доступа к этим переменнымoldrev newrev refname

Итак, я создал эту альтернативную версию, которая работает для предварительной фиксации, или на самом деле и для перехвата. Это pre-commitловушка, которая запускает huskyскрипт, если мы НЕ на masterветке.

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

Надеюсь, это кому-то поможет. Вы можете легко изменить для ваших потребностей, ничего между ifи fiотчетности.

TetraDev
источник
0

Я написал для себя PHP-скрипт, чтобы реализовать эту функцию.

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

Разместите этот файл на своем сервере, предпочтительно в корне репозитория, и определите URL-адрес в github webhooks. Замените allcommit в строке 8 именем своей ветки и добавьте свой код / ​​функцию в строку 18.

например

function githubdump($payload_object) {
    // Write your code here.
    exec('git push origin master');
}
фотузлаб
источник
0

Простой подход в git hookписьменной форме

read refname
echo $refname

Просто - больше информации об этой замечательной системе перехвата ссылок

Харис Краина
источник