编写git post-receive钩子以处理特定分支


107

这是我当前存放在公司服务器中的裸存储库中的git push origin master 钩子: 该钩子将推到Assembla。我需要的是,当有人将更改推送到我们服务器上的该分支时,仅推送一个分支(理想情况下为master),而忽略推送到其他分支。是否可以从裸仓库中选择分支,然后仅将该分支推送到Assembla?


你什么意思?git push origin master只会将master分支推送到origin远程,我假设它被定义为Assembla。您是说只在有人按下而不是诸如此类的东西时才需要触发钩子吗?masterfeature1
Stefan Kendall'9

@Stefan就是这样。我找不到这个词,呵呵。
Jorge Guberte 2011年

Answers:


386

接收后挂钩从stdin获取其参数,形式为<oldrev> <newrev> <refname>。由于这些参数来自标准输入,而不是命令行参数,因此需要使用read代替$1 $2 $3

后收到钩可以同时接收多个分支(例如,如果有人做了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语句出现错误。致命:远端意外挂断。错误:边带解复用器中的错误。它将在if语句外回显$ branch。
gin93r 2014年

5
@Ray,您有#!/bin/sh代替#!/bin/bash吗?
穿梭车

2
我能想到的一种风险是标记,因为它们的名称可能与分支名称重叠。如果您寻找refs/heads/master而不是refs/tags/master您应该没事。也许还有其他我无法想到的极端情况。就其本身而言,这可能是一个很好的StackOverflow问题。
pauljz '16

1
我使用@pauljz,if branch=$(git rev-parse --symbolic --abbrev-ref $refname 2>/dev/null); then以便在删除分支时git不会抱怨。
杰罗姆

8

接收后挂钩在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示例。我将做与此类似的事情。
雷夫2014年

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。效果不好。您有可以使用这些特殊字符的解决方案吗?
Shachar Hamuzim Rajuan 2015年

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

更新:更奇怪的是,预接收钩子通过stdin获取其输入,因此以“ read”读取(哇,没想到我会这么说)。更新后挂钩对我仍然可以使用$ 1。


2
就其价值而言,上述解决方案可能没有用,因为它们专门用于post-receive挂钩而不是post-update挂钩。他们以不同的方式接受他们的意见。
pauljz 2014年

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

希望对您有所帮助。您可以轻松地根据自己的需要进行修改,并且可以在iffi语句之间进行任何修改。


0

我为自己编写了一个PHP脚本来实现此功能。

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

将此文件托管在您的服务器上,最好是回购根目录,并在github webhooks中定义url。在第8行的'allcommits'更改为您的分支名称,并在第18行添加代码/功能。

例如

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.