如何防止 Git 客户端在接收后挂钩期间挂起

如何防止 Git 客户端在接收后挂钩期间挂起

我有一个 Git 存储库,其中包含配置文件和 python 脚本的集合。

在服务器存储库中,我有一个后接收钩子,它将:

  • 签出主分支,
  • 设置 python 虚拟环境,
  • 安装 pip 要求,
  • 并运行一些脚本

像这样:

#!/bin/bash
while read oldrev newrev ref; do
    branch=$(git rev-parse --symbolic --abbrev-ref $ref)
    if [[ $branch == "master" ]];
    then
        echo "Ref $ref received in branch $branch"
        echo "setup..."

        cd /srv/repo.git
        git --work-tree=/opt/work-dir checkout master -f

        cd /opt/work-dir
        echo "install virtual environment..." > "setup.log"
        python3 -m virtualenv venv >> "setup.log"
        echo "activate virtual environment..." >> "setup.log"
        source venv/bin/activate >> "setup.log"
        echo "install requirements..." >> "setup.log"
        pip install -r requirements.txt >> "setup.log"
        echo "done." >> "setup.log"

        echo "run scripts..."
        python source/some_script.py --param=value
    else
        echo "Ref $ref received, in branch $branch"
        echo "no action needed."
    fi
done

所有这些都运行正常,但 Git 客户端在钩子运行时会挂起,并且会一直保持这种状态,直到我手动取消。需要明确的是,服务器端钩子成功完成,但客户端中途停止记录。

我知道,我可以通过将 python 设置和执行移至单独的 bash 文件并使用nohupdisown以便它在终端关闭后继续执行来解决挂起问题。但是,这需要我单独记录脚本执行的结果,而不是将其显示在 git push 日志中。

  1. 什么原因导致 git 客户端挂起?
  2. 如何监视 git 客户端中脚本执行的状态而不导致客户端挂起?

直接致电

如果我通过手动调用 post-receive 钩子来模拟推送,则该钩子将成功完成。

hooks/post-receive <<MARK
09998130e13827a097797ff2fd3a973e91665960 fcb0b23a62f47bb73d6ccf2e6bfce324a04eeace master
MARK

子进程

我检查了挂钩的子进程,以查看是否存在退出不正常的现象。据我所知,所有子进程在父脚本继续运行之前都已完全退出。

ps auxf在每个命令之后调用了 post-receive 钩子来查看进程树是什么样子的,它总是返回:

root       711  0.0  0.3  95184  6812 ?        Ss   Feb16   0:00 sshd: username [priv]
username   720  0.0  0.2  95184  4660 ?        S    Feb16   0:04  \_ sshd: username @pts/1,pts/0,pts/2
username   725  0.0  0.1  19892  3712 pts/0    Ss   Feb16   0:00      \_ -bash
root       842  0.0  0.1  49484  3676 pts/0    S    02:49   0:00      |   \_ sudo -i
root       843  0.0  0.1  19940  3768 pts/0    S    02:49   0:00      |       \_ -bash
root      4616  0.0  0.1  50892  3428 pts/0    S    13:59   0:00      |           \_ su - git
git       4617  0.0  0.1  19920  3752 pts/0    S    13:59   0:00      |               \_ -su
git       5108  0.0  0.1  11256  3016 pts/0    S+   17:26   0:00      |                   \_ /bin/bash hooks/post-receive
git       5130  0.0  0.1  38456  3328 pts/0    R+   17:27   0:00      |                       \_ ps auxf

这个巢很大,因为我通过 ssh 登录,然后通过 sudo 变为 root,然后通过 su 变为 git 用户……但重要的部分在最后两行。

排除法

我已经确定了导致挂起的行:

python3 -m virtualenv venv >> "setup.log"

如果我从钩子中删除此行,并在推送更新之前手动设置虚拟环境,则推送将成功完成。

答案1

我相信要么python source/some_script.py --param=value留下pip install一个悬而未决的子进程。

从我的实验来看,我猜 git 有一些服务器端逻辑来等待脚本留下的所有子进程post-receive。它会永远等待挂起的子进程。

请验证您的预测,即接收后脚本始终会完全完成:post-receive在 shell 中手动运行,然后使用以下方法查找子脚本ps

相关内容