【问题标题】:Git "push --delete" blocked remotely by update hookGit“push --delete”被更新钩子远程阻止
【发布时间】:2018-05-19 08:15:09
【问题描述】:

我需要一种更方便地删除 Git 存储库分支的方法,因为“更新挂钩”正在阻止它们:

命令

git push -v -f --no-verify --delete origin test_branch

输出

remote: fatal: Not a valid commit name 0000000000000000000000000000000000000000
remote: error: hook declined to update refs/heads/test_branch

我目前正在暂时禁用更新挂钩,执行删除,然后恢复挂钩,因此我正在寻找更好的建议,甚至可能更改 Perl Git 挂钩。

我对 Perl 或 Git 钩子一无所知,所以我有这些问题

  1. 我无法向 push 操作发送消息。实现这样的目标的最佳方法是什么?

  2. 有没有办法从钩子中获取push --delete 事件?

    有点像

    if ${push --delete} then skip hook checks
    
  3. 有没有办法为push 操作创建自定义参数以跳过钩子?类似的东西

    if command line contains --imgod then skip hook checks
    

我完全在黑暗中摸索。

这是 Git 文档中的 update 钩子定义

更新挂钩 这个钩子由远程存储库上的 git-receive-pack 调用,当在本地完成 git push 时会发生这种情况 存储库。就在更新远程存储库上的 ref 之前, 更新挂钩被调用。它的退出状态决定了成功或 ref 更新失败。

钩子对每个要更新的 ref 执行一次,需要三个 参数:

  • 正在更新的 ref 的名称,

  • 存储在 ref 中的旧对象名称,

  • 以及要存储在 ref 中的新对象名称

更新钩子的零退出允许更新引用。退出 具有非零状态的 git-receive-pack 无法更新它 参考。

这个钩子可以用来防止强制更新某些 refs 确保对象名称是一个提交对象,它是 由旧对象名称命名的提交对象的后代。那是, 强制执行“仅快进”政策。

它也可以用来记录 old..new 状态。然而,它不 知道整个分支集,所以它最终会发送一封电子邮件 但是,当幼稚地使用时,每个参考。接收后挂钩比较多 适合那个。

在限制用户只能访问 git 的环境中 网络上的命令,这个钩子可以用来实现访问 控制而不依赖于文件系统所有权和组成员身份。 请参阅 git-shell[1] 了解如何使用登录 shell 来限制 用户只能访问 git 命令。

标准输出和标准错误输出都转发给git send-pack 在另一端,因此您可以简单地回显消息 用户。

默认的更新钩子,当启用时——使用 hooks.allowunannotated config 选项未设置或设置为 false——​防止未注释的标签 推。

回答:

我找到了一种将分支删除事件捕获到更新钩子中并在所有其他情况下跳过钩子逻辑的方法:

zero="0000000000000000000000000000000000000000"
if [ "$refname" == "refs/heads/*"] && [ "$newrev" == "$zero" ]; 
then
      exit 0
else
      perform_your_checks()
fi

更多信息可以在 update.sample GIT 模板中找到。

【问题讨论】:

  • 你能展示一下钩子吗?参见例如here 一些想法。
  • 很抱歉,钩子太大,无法显示,但问题是它必须保持原样。我可以改进它,引入一个关于动作何时是“删除分支”的条件,问题是我需要了解如何识别该动作。
  • 所以您的问题更像是如何“根据我的需要”调整挂钩?我担心人们只有在你提供钩子和你希望改变行为的条件以及它应该如何改变时才能提供帮助。
  • 我的问题是我怎样才能得到那个事件,我正在推动一个分支删除:)
  • @ivoruJavaBoy:提供问题答案的首选方式是在答案字段中发帖,即使您正在回答自己的问题。 SO 鼓励这样做。这样,如果后一个更好的答案出现,它可以投票高于您的原始答案,人们可​​以留下仅与您的答案相关的 cmets,而不必将它们发布在问题上。

标签: git perl hook githooks


【解决方案1】:

对于仍在寻找解决方案的人,这里附有脚本。 将此脚本放在基于 git 的 SCM 的 hooks 目录中。 在 hooks 目录下,您需要创建一个名为 - pre-receive.d 的新目录。 在pre-receive.d/里面,放置脚本文件,这个脚本文件名没有限制。

#!/bin/bash

# Place this script in gitlab server directory -> <path_to_your_gitSCM_server_root>/hooks/pre-receive.d
# Create directory,if it does not exists -> mkdir -p <path_to_your_gitSCM_server_root>/hooks/pre-receive.d

# Get input data passed along pre-receive hook
read old_sha new_sha refname

zero="0000000000000000000000000000000000000000"
if [[ "$new_sha" == "$zero" ]]; 
then
    exit 0
else
    # Default separator is ' ', change to ','
    IFS=","

    # Use env variable GL_USERNAME to get the matching details from users csv file
    # This file can be easily generated from the database that you have configured for your gitSCM instance.
    # It contains records in following format - <username>,<user_email>,<user_name>
    IFS=', ' read -r -a validuserarray <<< `grep -i "$GL_USERNAME," /tmp/gituser.csv `
    valid_user_email=${validuserarray[1]}
    valid_user_name=${validuserarray[2]}

    # Get the last log user details from git log
    IFS=', ' read -r -a incoming_committer_array <<< `git log -1 "$new_sha" --pretty=%ce,%cn | tr '[:upper:]' '[:lower:]'`
    IFS=', ' read -r -a incoming_author_array <<< `git log -1 "$new_sha" --pretty=%ae,%an | tr '[:upper:]' '[:lower:]'`

    # If no match found, fail the push
    if [[ ${#validuserarray[@]} < 3 ]]; then
        echo "GL-HOOK-ERR: You are not authorised to perform this action."
        exit 1
    fi

    # Ensure no conflict markers are there
    if git diff "$old_sha" "$new_sha" | grep -qE '^\+(<<<<<<<|>>>>>>>)'; then
        echo "GL-HOOK-ERR: Code has conflict markers. Please resolve and retry."
        exit 1
    fi

    # Validate author email ends with domain.com
    if ! [[ "${incoming_author_array[0]}" =~ ^[A-Za-z0-9.]+[@]domain\.com$ ]]; then
            echo "GL-HOOK-ERR: Author email address ${incoming_author_array[0]} is invalid."
            exit 1
    fi

    # Validate committer email
    if [ "${valid_user_email}" != "${incoming_committer_array[0]}" ]; then
        echo "GL-HOOK-ERR: Committer email address ${incoming_committer_array[0]} is invalid."
        exit 1
    fi

    # Validate committer name
    if [ "${valid_user_name}" != "${incoming_committer_array[1]}" ]; then
        echo "GL-HOOK-ERR: Committer name ${incoming_committer_array[1]} is invalid."
        exit 1
    fi
    exit 0
fi

每当推送事件完成时,它都会为我们提供 3 个值 - branch、old_sha、new_sha。 对于所有其他操作,我们只需要打印这些详细信息并采取相应措施即可。

【讨论】:

    【解决方案2】:
    1. 我无法向推送操作发送消息。实现此类目标的最佳方法是什么?

    你不能。这到底是什么意思?

    1. 有没有办法从钩子中获取push --delete 事件?类似if ${push --delete} then skip hook checks

    是的,正如您从收到的错误消息中看到的那样,在删除的情况下,第三个参数(“新对象名称”)将为 0000000000000000000000000000000000000000,您可以检查它。

    有没有办法为推送操作创建自定义参数以跳过钩子?

    没有。客户端无法决定是否在服务器上运行挂钩。这是一个深思熟虑的决定,允许服务器通过挂钩执行策略。

    【讨论】:

    猜你喜欢
    • 2014-03-01
    • 1970-01-01
    • 2012-06-10
    • 2012-05-12
    • 2015-07-03
    • 1970-01-01
    • 2018-03-04
    • 1970-01-01
    • 2014-02-15
    相关资源
    最近更新 更多