我有一个 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 文件并使用nohup
或disown
以便它在终端关闭后继续执行来解决挂起问题。但是,这需要我单独记录脚本执行的结果,而不是将其显示在 git push 日志中。
- 什么原因导致 git 客户端挂起?
- 如何监视 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