Написание обработчика 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

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отчетности.


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');
}

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.