git post commit钩子-服务器端

时间:2018-10-21 13:09:00

标签: git

我需要运行一个提交后的git服务器端钩子,该钩子应该检查是否存在合并,如果存在合并则进行一些自动化。

我尝试使用const object = { getPastEvents: () => Promise.resolve([1,2,3]) } function* fetchPastEvents() { console.log("entry") const values = yield object.getPastEvents() console.log(values) } const iterator = fetchPastEvents() const promise = iterator.next().value; promise.then(val => iterator.next(val)),它很好用,但只在客户端使用。

我还尝试实现合并后挂钩,但这没用。

当我在服务器端运行git reflog -1时,没有任何输出。

有什么想法可以实现这一目标吗?

1 个答案:

答案 0 :(得分:2)

ElpieKay's comment是答案的关键,但是值得更多细节。由于服务器实际上并未运行git commit,因此必须使用接收后挂钩监视参考更新。不幸的是,接收后钩子并不简单。这是一个通常有用的简单框架,以POSIX shell表示:

#! /bin/sh
# sample post-receive hook

# return true if the argument ($1) is the null hash (all-0s)
is_nullhash() {
    expr "$1" : '0*$' >/dev/null
}

while read oldhash newhash ref; do
    # If the old hash is all 0s, the reference was just created.
    # If the new hash is all 0s, the reference was just deleted.
    # Otherwise, the reference was updated, from $oldhash to $newhash.
    if is_nullhash $oldhash; then
        op=create
    elif is_nullhash $newhash; then
        op=delete
    else
        op=update
    fi

    # If the reference begins with refs/heads/, the rest of it is
    # a branch name.  If it starts with refs/tags, the rest is a tag.
    # Otherwise it's some other type of reference (not decoded here).
    case $ref in
    refs/heads/*) reftype=branch; shortref=${ref#refs/heads/};;
    refs/tags/*) reftype=tag; shortref=${ref#refs/tags/};;
    *) reftype=other; shortref=$ref;;  # NB: not shortened!
    esac

     ... insert code here ...
done

“在此处插入代码”部分中的代码必须:

  • 确定这是否是您关心的操作
  • 如果是,请根据操作类型决定要做什么

例如,如果您只想观看对master的推送:

if [ $reftype = branch -a $shortref = master ]; then
    if [ $op = update ]; then
        handle_master_update $oldhash $newhash
    else
        ... do something different if the op is create or delete ...
    fi
fi

其中handle_master_update是您处理master更新的函数。如果您不想处理master分支的创建和删除,则可以将其进一步简化为:

case $ref,$op in
refs/heads/master,update) handle_master_update $oldhash $newhash;;
esac

在这种情况下,您可以删除对引用类型进行解码的样板部分。

现在,我们进入更新处理的核心:

# Do something with update to master branch.
# The old hash is $1 and the new hash is $2,
# so commits in $1..$2 now appear on `master` but
# were not part of `master` before (they may have
# been on some other branch, and may still be).
# Meanwhile, commits in $2..$1 used to be on `master`
# but have just been removed via force-push.  If this
# list is empty, the push did not have to be forced,
# and maybe was not.
handle_master_update() {
    local rev parents
    git rev-list $2..$1 | while read rev; do ...; done  # deal with removed commits

    git rev-list --parents $1..$2 | while read rev parents; do
        ...
    done
}

第一部分(处理删除的提交)当然是可选的。第二部分是您要检测合并的部分,因此我们使用git rev-list(而不是git log,这里的rev-list是更有用的主力)来枚举所有添加的以及他们的父哈希ID read将所有父哈希放入变量parents中,因此我们可以轻松地在...部分中对其进行计数。例如:

        set -- $parents
        case $# in
        0) ...;; # $rev is a root commit
        1) ...;; # $rev is an ordinary commit
        *) ...;; # $rev is a merge, its parents are $1, $2, ... through $#
        esac

零号是非常不寻常的-要使其作为更新发生,我们必须向分支添加一个根提交,例如,从:

A--B--C   <-- master

收件人:

A--B--C--D--H   <-- master
           /
F---------G

在给定git rev-list的情况下,C..H(它们的哈希ID)将列出HDGF以某种顺序。 H的哈希将首先出现,但之后的所有内容都取决于您提供给git rev-list的任何排序选项。如果这对代码的工作方式很重要,请使用--topo-order来确保您得到拓扑排序(例如,您可能希望--reverse --topo-sort以便始终在 forward 上工作, D, F, G, HF, G, D, H中的一个作为输入)。

请注意,如果您确实使用兼容POSIX的sh来实现钩子,则git rev-list ... | while read ...会带来麻烦:while循环在子shell中运行,这意味着此处设置的任何变量退出循环时丢失。您可以通过以下几种方法来解决:参见While-loop subshell dilemma in Bash