Git post-receive钩子如何脱离终端完成执行?
解决post-receive钩子中程序输出与git提交终止的问题
我来帮你搞定这个头疼的钩子问题!核心矛盾就是你既要看到程序fork前的输出,又要让fork后的子进程后台运行,同时还得让git提交正常终止对吧?下面给你两个靠谱的解决方案,按需选择就行:
方案1:在程序内部精准控制(最推荐)
这是最稳妥的方式,毕竟你能直接掌控程序的输出和进程行为:
修改你的程序代码:
- 在fork操作之前,把所有你想在git提交时看到的内容(比如启动提示、初始化状态)都输出完毕——这些内容会顺着钩子的stdout/stderr传到你的git客户端。
- fork出子进程后,让子进程做这几件事彻底脱离终端:
- 调用
setsid():创建一个新的会话,让子进程彻底摆脱原终端的控制,不再和钩子的输出流绑定。 - 切换工作目录到根目录(
chdir("/")):防止钩子所在的仓库目录被占用,导致后续操作出问题。 - 关闭或重定向标准流:要么直接关闭
STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,要么把它们重定向到日志文件(比如/var/log/myapp.log),这样子进程的输出就不会再传到git客户端了。
- 调用
- 父进程输出完需要的内容后立刻退出,这样post-receive钩子会跟着结束,git提交自然就正常终止了。
简化后的钩子脚本:
钩子里不用加任何复杂的重定向或后台参数,编译完直接运行程序就行:#!/bin/bash # 编译你的程序(根据实际情况替换成你的编译命令) make # 直接运行程序 ./myapp
方案2:在钩子脚本中处理(不用改程序)
如果不想动程序代码,也可以通过钩子的进程管理和重定向来实现:
- 钩子脚本示例:
这个脚本会先把程序fork前的输出传给git客户端,同时把子进程的输出转到日志文件,还能让子进程彻底脱离钩子的控制:
或者用#!/bin/bash # 编译程序 make # 运行程序,用tee同时把输出传到git客户端和日志文件 ./myapp 2>&1 | tee -a /var/log/myapp.log & # 给父进程一点时间输出内容(根据你的程序调整sleep时长) sleep 1 # 把后台进程从shell作业控制中移除,避免git等待 disown $!nohup更稳妥:#!/bin/bash make # nohup让程序脱离终端,同时用tee保留输出到git客户端和日志 nohup ./myapp > >(tee -a /var/log/myapp.log) 2>&1 & disown $!
关键逻辑说明
为啥之前的方法不行?因为git的post-receive钩子会一直等着,直到所有子进程的标准输出/错误流关闭。所以必须让fork后的子进程彻底和这些流解绑,要么在程序里关流/重定向,要么在钩子中用disown或nohup让它脱离控制,这样git才会结束提交流程。
内容的提问来源于stack exchange,提问作者John Smith
相关产品推荐
相关产品推荐

