可以的Git pre-收到挂钩evaulate传入的承诺? [英] Can git pre-receive hooks evaulate the incoming commit?

查看:285
本文介绍了可以的Git pre-收到挂钩evaulate传入的承诺?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图写一个服务器端的pre-收到git的钩,因为他们正在推到评估的提交。

I'm trying to write a server side pre-receive git hook to evaluate commits as they are being pushed.

根据<一href=\"http://stackoverflow.com/questions/22491942/how-can-you-block-git-commits-from-invalid-users\">answers这里,这应该很容易通过搜索混帐日志,并过滤掉什么,我想可能出现的格式:。

According to the answers here, this should easily be possible by searching git log and filtering out what I want with 'format:'.

我创建了以下pre-commit脚本。

I've created the following pre-commit script.

#!/bin/bash

set -x #for debugging, TODO: remove
echo "parameters are" $@
echo "1 is " $1

#List of banned users
bannedusers=( root )

author_name=$(git show --pretty=oneline --pretty=format:%an | head -n1)
author_email=$(git show --pretty=oneline --pretty=format:%ae | head -n1)

committer_name=$(git show --pretty=oneline --pretty=format:%cn | head -n1)
committer_email=$(git show --pretty=oneline --pretty=format:%ce | head -n1)

commit_users=( "${author_name}" "${committer_name}" )


  for acommituser in "${commit_users[@]}"
  do
    :
    echo $acommituser #for debugging, TODO: remove
    for abanneduser in "${bannedusers[@]}"
    do
      :
        echo $abanneduser #for debugging, TODO: remove
        if [[ $abanneduser == $acommituser ]]; then
         echo "################################################################"
         echo "Commits from $abanneduser are not allowed"
         echo "git config user.name bob builder --replace-all"
         echo "git config user.email bob@aol.com"
         echo "git commit --amend --reset-author"
         echo "################################################################"
         exit 1
        fi
    done
  done

我发现,当我运行 git的节目 git的日志在服务器上,结果为电流的头,而我想查询的传入的承诺。

I find that when I run git show or git log on the server, the results are for the current HEAD, whereas I want to query the incoming commit.

我怎么能修改此脚本来运行 git的日志 git的节目关于还未收到承诺?

How could I modify this script to run git log or git show on the 'not-yet-recieved' commit?

推荐答案

您需要使用SHA-1的ID在标准输入被提供:

You need to use the SHA-1 IDs being supplied on standard input:

while read oldsha newsha refname; do
    ... testing code goes here ...
done

测试code,则需要看的至少某些的和可能的所有三个的项目,根据不同的测试被执行。

The "testing code" then needs to look at at least some and maybe all three items, depending on the tests to be performed.

$ oldsha 的值将是40 0 ■如果引用名 $ refname 正在提议被创建。也就是说, $ refname (通常类似于裁判/头/主裁判/标签/v1.2 ,而在裁判/ 的名称会显示:裁判/笔记/提交,例如)现在不在接收存储库中存在,但会存在,如果你允许更改将指向 $ newsha

The value in $oldsha will be 40 0s if the reference name $refname is being proposed to be created. That is, $refname (typically something like refs/heads/master or refs/tags/v1.2, but any name in refs/ can appear: refs/notes/commits, for instance) does not exist now in the receiving repository, but will exist and will point to $newsha if you allow the change.

$ newsha 的值将是40 0 ■如果引用名 $ refname 正在提议将被删除。也就是说, $ refname 确实存在,现在指向对象 $ oldsha ;如果你允许的变化,即参考名称将被删除。

The value in $newsha will be 40 0s if the reference name $refname is being proposed to be deleted. That is, $refname does exist now and points to object $oldsha; if you allow the change, that reference-name will be deleted.

如果所提议的引用名 $ refname 是要更新的,也就是说,它当前指向的git对象两者的值将是非零 $ oldsha ,如果你允许更改,它将指向新的对象 $ newsha 代替。

The values of both will be nonzero if the reference name $refname is being proposed to be updated, i.e., it currently points to git object $oldsha, and if you allow the change, it will point to new object $newsha instead.

如果你只是运行 git的日志 git的节目,Git使用的SHA-1发现通过运行 git的REV-HEAD解析。在一个典型的接收存储库, HEAD 是一个符号引用指向裁判/头/主(文件 HEAD 字面上包含字符串 REF:裁判/头/主),所以你会看到最上面的承诺分支(如你观察到的)。

If you just run git log or git show, git uses the SHA-1 it finds by running git rev-parse HEAD. In a typical receiving repository, HEAD is a symbolic reference pointing to refs/heads/master (the file HEAD literally contains the string ref: refs/heads/master), so you will see the top-most commit on branch master (as you observed).

您需要在未来任何新的对象,具体看你怎么知道哪些新的对象来了?这取决于所发生的事情所提供的 $ refname ,以及可能的其他的refnames为好。

You need to look specifically at any new objects coming in. How do you know which new objects are coming in? That depends on what's happening to the supplied $refname, and possibly other refnames as well.

如果该refname被删除,没有什么新的进来,无论任何基础的git的对象的将被删除(垃圾回收)取决于refname是否是最后引用这些对象。例如,假设整个标准输入序列由两个指令:

If the refname is to be deleted, nothing new is coming in. Whether any underlying git objects will be deleted (garbage collected) depends on whether that refname is the "last" reference to those objects. For instance, suppose the entire standard input sequence consists of two directives:


  • 删除裁判/头/富

  • 删除裁判/标签/ V1.1

  • delete refs/heads/foo
  • delete refs/tags/v1.1

进一步假设裁判/头/富(分支)指向提交 ˚F在这个承诺,图图,标记 1.1版指向注释标记

Suppose further that refs/heads/foo (branch foo) points to commit F in this commit-graph diagram, and tag v1.1 points to annotated tag G:

A - B - C - D   <-- refs/heads/master
      \
        E - F   <-- refs/heads/foo
             \
              G <-- refs/tags/v1.1

删除分支是在没有提交会消失安全,因为注释标记将保留他们,通过 1.1版标记。

Deleting branch foo is "safe" in that no commits will go away because annotated tag G will retain them, via the v1.1 tag.

删除标记 1.1版是安全(ISH)在没有提交会消失,因为分支将保留它们,通过裁判/头/富引用。 (附加说明标签对象本身会自行消失。这取决于你是否允许此)

Deleting tag v1.1 is "safe"(ish) in that no commits will go away because branch foo will retain them, via the refs/heads/foo reference. (The annotated tag object itself will go away. It's up to you whether to allow this)

但是,删除的两个的是的的安全:提交电子˚F将无法访问,将被收集。 (这取决于你是否允许此反正。)

However, deleting both is not safe: commits E and F will become unreachable and will be collected. (It's up to you whether to allow this anyway.)

在另一方面,它可能是与这两个指令以来,标准输入包含第三指令:

On the other hand, it's possible that along with those two directives, stdin contains a third directive:


  • 创建裁判/头/ foo2的指向提交 ^ h ,以犯下 ^ h 指向提交作为其父[修改:在现在重新读这篇文章,我注意到了明显的假设,即是一个commit对象,而不是一个标签对象。如果我们假设是一个commit对象的下方剩下的就是正确的,但上面成为至少有一点是错误的。但是,一般的想法,认为DAG由具有外部保护的引用,仍然是正确的,这应该主要是有意义的。]

  • create refs/heads/foo2 pointing to commit H, with commit H pointing to commit G as its parent [ on re-reading this now, I notice the glaring assumption that G is a commit object rather than a tag object. If we assume G is a commit object the rest of the below is correct, but the above becomes at least a little wrong. However, the general idea—that the DAG is protected by having external references—is still right, and this should mostly make sense.]

在这种情况下删除毕竟是安全的,因为新的分支 foo2的将保留提交 ^ h 将保留提交

in which case deletion of foo is safe after all, as the new branch foo2 will retain commit H which will retain commit G.

做一个全面的分析是棘手的;它往往是更好的只是做一个分段分析功能,使安全操作(无论你决定这些都是),并强制用户推送更新分段在一个安全的方式(创建分支 foo2的第一,然后才删除分支作为一个单独的推动,例如)。

Doing a complete analysis is tricky; it's often better to just do a piecewise analysis that allows "safe" operations (whatever you decide these are), and force users to push updates piecewise in a "safe" manner (create branch foo2 first, and only then delete branch foo as a separate push, for instance).

如果你只想看的新的的承诺,那么,对每个参考更新时间:

If you only want to look at new commits, then, for each reference update:


  • 如果这是一个删除,允许它(或使用其他规则)。

  • 如果这是一个创建或修改,找对象提交它使那些不前可达可达,并检查这些提交。

在最正常的pre-收到挂钩你会使用下面介绍的方法,但我们有这个特殊的任务的替代品。

In most "normal" pre-receive hooks you'd use the methods outlined below, but we have an alternative for this particular task.

有对修改处理中最常见的,通常最有趣的,情况下,短切的方法。假设有人提议更新裁判/头/富 1234567 ... 9876543 .. 。这有可能是在范围内的某些对象已经存在,例如,也许 1234567 是提交的ID C 9876543 是ID提交电子

There's a short-cut method for modifications that handles the most common, and usually most interesting, cases. Suppose someone proposes updating refs/heads/foo from 1234567... to 9876543.... It's possible that some objects in the range already existed, e.g., perhaps 1234567 is the ID of commit C and 9876543 is the ID of commit E:

A - B - C           <-- refs/heads/foo
          \
            D - E   <-- refs/heads/bar

在这种情况下,这将考察对象D和E也是如此,如果提交 D 电子有刚刚上传的,但有的没有的引用没有,也就是说,建议更新是加入 D 电子和图表目前看起来是这样的:

in which case this will examine objects D and E. This is also true if commits D and E have just been uploaded but have no references yet, i.e., the proposed update is to add D and E and the graph currently looks like this:

A - B - C           <-- refs/heads/foo
          \
            D - E   [no reference yet]

在这两种情况下,一个简单的:

In either case, a simple:

git rev-list $oldsha..$newsha

生成的对象ID,你应该看看。

produces the object IDs you should look at.

有关新的引用,没有任何捷径。举例来说,假设我们有上述相同的五个提交,以相同裁判/头/富,但没有裁判/头/条,而实际的建议是创建裁判/头/条指向电子。在这种情况下,我们应该再看看提交 D 电子,但有了解<$没有明显的方式C $ C> D

For new references, there's no short-cut. For instance, suppose we have the same five commits shown above, with the same refs/heads/foo but no refs/heads/bar, and the actual proposal is "create refs/heads/bar pointing to E". In this case, we should again look at commits D and E, but there's no obvious way to know about D.

的非显而易见的方式,但这种方式只在某些情况下,是要找到将要到达的给定所提出的创建对象,目前尚未到达在所有

The non-obvious way, which only works in some cases, is to find objects that will be reachable given the proposed creation, that are not currently reachable at all:

git rev-list $newsha --not --all

在这种特殊情况下,这将再次产生的ID为 D 电子

In this particular case, this will again produce the IDs for D and E.

现在让我们考虑您的特殊情况下,如果你想看看正在提议将要添加的所有提交。这里有一个方法来处理这​​一个。

Now let's consider your particular case, where you want to look at all commits that are being proposed-to-be-added. Here's a way to handle this one.

有关的所有建议的更新:

For all proposed updates:


  • 如果这个人是一个删除,我们有一些删除。

  • 如果这个人是创建或更新,我们有一些新的提交;积累新的SHA。

如果我们有一些删除的的我们已经积累了一定的SHA,拒绝尝试:​​它太硬。使用户分离出来的操作。

If we have some deletes and we have accumulated some SHAs, reject the attempt: it's too hard. Make the user separate out the operations.

否则,如果我们没有积累的SHA,我们必须就必须删除(或者什么都没有,不应该发生,但无害的);允许这种(退出0)。

Otherwise, if we have no accumulated SHAs, we must just have deletes (or maybe nothing at all—should not happen, but harmless); allow this (exit 0).

否则,我们必须有一些新的SHA-1的值。

Otherwise we must have some new SHA-1 values.

使用提出了新的SHA作为起点,找到所有的Git对象,这将是访问,不包括目前以任何名义访问的所有对象。这些都是新的对象。

Using the proposed new SHAs as starting points, find all git objects that would be reachable, excluding all objects that are currently reachable under any name. These are all the new objects.

有关每一个这是一个承诺,审视它,看它是否是被禁止的。如果是这样,则拒绝整个操作(即使一些部分可能成功);和以前一样,太难搞清楚,所以使用户从坏的人分离出好的操作。

For each one that is a commit, examine it to see if it's forbidden. If so, reject the entire operation (even if some parts could succeed); as before, it's too hard to figure out, so make the user separate out the "good" operations from the "bad" ones.

如果我们走这么远,一切都OK了;使得整个更新。

If we get this far, everything is OK; permit the entire update.

在code形式:

#! /bin/sh
# (untested)
NULL_SHA1="0000000000000000000000000000000000000000" # 40 0's
new_list=
any_deleted=false
while read oldsha newsha refname; do
    case $oldsha,$newsha in
    *,$NULL_SHA1) # it's a delete
        any_deleted=true;;
    $NULL_SHA1,*) # it's a create
        new_list="$new_list $newsha";;
    *,*) # it's an update
        new_list="$new_list $newsha";;
    esac
done
$any_deleted && [ -n "$new_list" ] && {
    echo 'error: you are deleting some refs and creating/updating others'
    echo 'please split your push into separate operations'
    exit 1
}
[ -z "$new_list" ] && exit 0

# look at all new objects, and verify them
# let's write the verifier function, including a check_banned function...
check_banned() {
    if [ "$1" = root ]; then
        echo "################################################################"
        echo "Commits from $1 are not allowed"
        echo ... rest of message ...
        exit 1
     fi
}
check_commit() {
    check_banned "$(git log -1 --pretty=format:%an $1)"
    check_banned "$(git log -1 --pretty=format:%cn $1)"
}


git rev-list $new_list --not --all |
while read sha1; do
    objtype=$(git cat-file -t $sha1)
    case $objtype in
    commit) check_commit $sha1;;
    esac
done

这篇关于可以的Git pre-收到挂钩evaulate传入的承诺?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆