我们经常发布文档更新,此页面的翻译可能仍在进行中。有关最新信息,请访问英文文档。如果此页面上的翻译有问题,请告诉我们

此版本的 GitHub Enterprise 已停止服务 2020-11-12. 即使针对重大安全问题,也不会发布补丁。 要获得更好的性能、改进的安全性和新功能,请升级到 GitHub Enterprise 的最新版本。 如需升级方面的帮助,请联系 GitHub Enterprise 支持

创建预接收挂钩脚本

使用预接收挂钩脚本创建基于内容来接受或拒绝推送的要求。

本文内容

您可以在 github/platform-samples 仓库中查看 GitHub Enterprise Server 的预接收挂钩示例。

编写预接收挂钩脚本

预接收挂钩脚本在 GitHub Enterprise Server 设备上的预接收挂钩环境中执行。 创建预接收挂钩脚本时,请考虑可用的输入、输出、exit-status 和环境变量。

输入 (stdin)

在推送发生之后以及在远程仓库上更新任何 ref 之前,git-receive-pack 进程会调用预接收挂钩脚本,其中要更新的每个 ref 使用一行标准输入:

<old-value> SP <new-value> SP <ref-name> LF

此字符串表示以下参数:

参数描述
<old-value>存储在 ref 中的旧对象名称。
当您创建新的 ref 时,这等于 40 个零。
<new-value>要存储在 ref 中的新对象名称。
当您删除 ref 时,这等于 40 个零。
<ref-name>ref 的全名。

关于 git-receive-pack 的更多信息,请参阅 Git 文档中的“git-receive-pack”。 关于 ref 的更多信息,请参阅 Pro Git 中的“Git 引用”。

输出 (stdout)

脚本输出 (stdout) 将传递回客户端,因此用户可以在命令行或用户界面中看到任意 echo 语句。

Exit-status

预接收脚本的 exit-status 决定是否接受推送。

Exit-status 值操作
0将接受推送。
非零将拒绝推送。

环境变量

除了提供给 stdin 的值以外,还有一些其他变量可用于在 GitHub Enterprise Server 上运行的预接收挂钩脚本。

变量描述
$GITHUB_USER_LOGIN创建 ref 的用户 ID。
$GIT_DIR设备上远程仓库的路径。
$GITHUB_USER_IP执行推送的用户的 IP 地址。
$GITHUB_REPO_NAME正在更新的仓库的 owner/repo 格式的名称。
$GITHUB_PULL_REQUEST_AUTHOR_LOGIN在您的实例上打开的拉取请求的作者的用户 ID。
$GITHUB_REPO_PUBLIC一个布尔值,为 true 时表示公共仓库,为 false 时表示私有仓库。
$GITHUB_PUBLIC_KEY_FINGERPRINT用户的公钥指纹。
$GITHUB_PULL_REQUEST_HEAD格式中的字符串:user:branch,适用于 PR 的 HEAD。
示例:octocat:fix-bug
$GITHUB_PULL_REQUEST_BASE格式中的字符串:user:branch,适用于 PR 的 BASE。
示例: octocat:main
$GITHUB_VIA用于创建 ref 的方法。
可选值:
- auto-merge deployment api
- blob edit
- branch merge api
- branches page delete button
- git refs create api
- git refs delete api
- git refs update api
- merge api
- pull request branch delete button
- pull request branch undo button
- pull request merge api
- pull request merge button
- pull request revert button
- releases delete button
- stafftools branch restore
- slumlord (#{sha})
$GIT_PUSH_OPTION_COUNT客户端发送的推送选项数。 关于推送选项的更多信息,请参阅 Git 文档中的“git-push”。
$GIT_PUSH_OPTION_N其中 N 是一个从 0 开始的整数,此变量包含客户端发送的推送选项字符串。 发送的第一个选项存储在 GIT_PUSH_OPTION_0 中,发送的第二个选项存储在 GIT_PUSH_OPTION_1 中,依此类推。 关于推送选项的更多信息,请参阅 Git 文档中的“git-push”。

设置权限并将预接收挂钩推送到 GitHub Enterprise Server

GitHub Enterprise Server 设备上的仓库中包含预接收挂钩脚本。 站点管理员必须考虑仓库权限,确保只有适当的用户才能访问。

我们建议将挂钩合并到单个仓库。 如果统一的挂钩仓库是公共的,则可以使用 README.md 来解释策略强制实施。 此外,也可以通过拉取请求接受贡献。 但是,只能从默认分支添加预接收挂钩。 对于测试工作流程,应使用具有配置的仓库的分支。

  1. 对于 Mac 用户,确保脚本具有执行权限:

    $ sudo chmod +x SCRIPT_FILE.sh

    对于 Windows 用户,确保脚本具有执行权限:

    git update-index --chmod=+x SCRIPT_FILE.sh
  2. 提交并推送到 GitHub Enterprise Server 实例上指定的预接收挂钩仓库。

    $ git commit -m "YOUR COMMIT MESSAGE"
    $ git push
  3. 在 GitHub Enterprise Server 实例上创建预接收挂钩

在本地测试预接收脚本

在 GitHub Enterprise Server 设备上创建或更新预接收挂钩脚本之前,您可以在本地对其进行测试。 一种方法是创建本地 Docker 环境以充当可以执行预接收挂钩的远程仓库。

  1. 确保 Docker 在本地安装

  2. 创建一个名为 Dockerfile.dev 的文件,其中包含:

    FROM gliderlabs/alpine:3.3
    RUN \
      apk add --no-cache git openssh bash && \
      ssh-keygen -A && \
      sed -i "s/#AuthorizedKeysFile/AuthorizedKeysFile/g" /etc/ssh/sshd_config && \
      adduser git -D -G root -h /home/git -s /bin/bash && \
      passwd -d git && \
      su git -c "mkdir /home/git/.ssh && \
      ssh-keygen -t ed25519 -f /home/git/.ssh/id_ed25519 -P '' && \
      mv /home/git/.ssh/id_ed25519.pub /home/git/.ssh/authorized_keys && \
      mkdir /home/git/test.git && \
      git --bare init /home/git/test.git"
    
    VOLUME ["/home/git/.ssh", "/home/git/test.git/hooks"]
    WORKDIR /home/git
    
    CMD ["/usr/sbin/sshd", "-D"]
    
  3. 创建一个名为 always_reject.sh 的测试预接收脚本。 此示例脚本将拒绝所有推送,这对于锁定仓库非常有用:

    #!/usr/bin/env bash
    
    echo "error: rejecting all pushes"
    exit 1
    
  4. 确保 always_reject.sh 脚本具有执行权限:

    $ chmod +x always_reject.sh
  5. 从包含 Dockerfile.dev 的目录中,构建一个镜像:

    $ docker build -f Dockerfile.dev -t pre-receive.dev .
    > Sending build context to Docker daemon 3.584 kB
    > Step 1 : FROM gliderlabs/alpine:3.3
    >  ---> 8944964f99f4
    > Step 2 : RUN apk add --no-cache git openssh bash && ssh-keygen -A && sed -i "s/#AuthorizedKeysFile/AuthorizedKeysFile/g"  /etc/ssh/sshd_config && adduser git -D -G root -h /home/git -s /bin/bash && passwd -d git && su git -c "mkdir /home/git/.ssh && ssh-keygen -t ed25519 -f /home/git/.ssh/id_ed25519 -P ' && mv /home/git/.ssh/id_ed25519.pub /home/git/.ssh/authorized_keys && mkdir /home/git/test.git && git --bare init /home/git/test.git"
    >  ---> Running in e9d79ab3b92c
    > fetch http://alpine.gliderlabs.com/alpine/v3.3/main/x86_64/APKINDEX.tar.gz
    > fetch http://alpine.gliderlabs.com/alpine/v3.3/community/x86_64/APKINDEX.tar.gz
    ....truncated output....
    > OK: 34 MiB in 26 packages
    > ssh-keygen: generating new host keys: RSA DSA ECDSA ED25519
    > Password for git changed by root
    > Generating public/private ed25519 key pair.
    > Your identification has been saved in /home/git/.ssh/id_ed25519.
    > Your public key has been saved in /home/git/.ssh/id_ed25519.pub.
    ....truncated output....
    > Initialized empty Git repository in /home/git/test.git/
    > Successfully built dd8610c24f82
  6. 运行包含生成的 SSH 密钥的数据容器:

    $ docker run --name data pre-receive.dev /bin/true
  7. 将测试预接收挂钩 always_reject.sh 复制到数据容器中:

    $ docker cp always_reject.sh data:/home/git/test.git/hooks/pre-receive
  8. 启动一个运行 sshd 的应用程序容器并执行挂钩。 记下返回的容器 ID:

    $ docker run -d -p 52311:22 --volumes-from data pre-receive.dev
    > 7f888bc700b8d23405dbcaf039e6c71d486793cad7d8ae4dd184f4a47000bc58
  9. 将生成的 SSH 密钥从数据容器复制到本地计算机:

    $ docker cp data:/home/git/.ssh/id_ed25519 .
  10. 修改远程测试仓库并将其推送到 Docker 容器中的 test.git 仓库。 此示例使用了 git@github.com:octocat/Hello-World.git,但您可以使用想要的任何仓库。 此示例假定您的本地计算机 (127.0.0.1) 绑定了端口 52311,但如果 docker 在远程计算机上运行,则可以使用不同的 IP 地址。

    $ git clone git@github.com:octocat/Hello-World.git
     $ cd Hello-World
     $ git remote add test git@127.0.0.1:test.git
     $ GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p 52311 -i ../id_ed25519" git push -u test main
     > Warning: Permanently added '[192.168.99.100]:52311' (ECDSA) to the list of known hosts.
     > Counting objects: 7, done.
     > Delta compression using up to 4 threads.
     > Compressing objects: 100% (3/3), done.
     > Writing objects: 100% (7/7), 700 bytes | 0 bytes/s, done.
     > Total 7 (delta 0), reused 7 (delta 0)
     > remote: error: rejecting all pushes
     > To git@192.168.99.100:test.git
     >  ! [remote rejected] main -> main (pre-receive hook declined)
     > error: failed to push some refs to 'git@192.168.99.100:test.git'

    请注意,在执行预接收挂钩并回显脚本中的输出后,将拒绝推送。

延伸阅读