我如何提示用户从一个commit-msg钩子?

我想警告用户,如果他们的提交消息不遵循一定的指导方针,然后给他们select编辑他们的提交信息,忽略警告,或取消提交。 问题是,我似乎无法访问标准input。

以下是我的commit-msg文件:

function verify_info { if [ -z "$(grep '$2:.*[a-zA-Z]' $1)" ] then echo >&2 $2 information should not be omitted local_editor=`git config --get core.editor` if [ -z "${local_editor}" ] then local_editor=${EDITOR} fi echo "Do you want to" select CHOICE in "edit the commit message" "ignore this warning" "cancel the commit"; do case ${CHOICE} in i*) echo "Warning ignored" ;; e*) ${local_editor} $1 verify_info "$1" $2 ;; *) echo "CHOICE = ${CHOICE}" exit 1 ;; esac done fi } verify_info "$1" "Scope" if [ $# -ne 0 ]; then exit $# fi verify_info "$1" "Affects" if [ $# -ne 0 ]; then exit $# fi exit 0 

下面是我把Scope信息留空的输出:

 Scope information should not be omitted Do you want to: 1) edit the commit message 3) cancel the commit 2) ignore this warning #? 

该消息是正确的,但实际上并没有停止input。 我也尝试使用更简单的“读取”命令,它也有同样的问题。 看来问题是,在这一点上,git控制着stdin,并提供自己的input。 我该如何解决?

更新:似乎这可能是这个问题的重复,不幸的是似乎表明我不幸运。

调用exec < /dev/tty为键盘分配标准input。 在post-commit git hook中为我工作:

 #!/bin/sh echo "[post-commit hook] Commit done!" # Allows us to read user input below, assigns stdin to keyboard exec < /dev/tty while true; do read -p "[post-commit hook] Check for outdated gems? (Y/n) " yn if [ "$yn" = "" ]; then yn='Y' fi case $yn in [Yy] ) bundle outdated --pre; break;; [Nn] ) exit;; * ) echo "Please answer y or n for yes or no.";; esac done 

commit-msg挂钩不会在交互式环境中运行(如您所注意到的)。

唯一能够可靠地通知用户的方法是向stdout写入一个错误,将一个提交消息的副本放置在'BAD_MSG'文件中,并指示用户编辑文件,'git commit –file = BAD_MSG'


如果你对环境有一些控制,你可以有一个替代编辑器,它是一个包装脚本,用来检查build议的消息,并且可以用额外的注释消息重新启动编辑器。

基本上,你运行编辑器,检查保存的文件违反你的规则。 如果失败,则在文件前加上警告消息(带前导#),然后重新启动编辑器。

你甚至可以允许他们在消息中放置一个'#FORCE = true'的行来抑制检查并继续。

为了使inputselect停止,你也可以尝试从/dev/fd/3redirectselectstdin (参见: 在while循环中的bash中的读input )。

 # sample code using a while loop to simulate git consuming stdin { echo 'fd 0' | while read -r stdin; do echo "stdin: $stdin" echo "Do you want to" select CHOICE in "edit the commit message" "ignore this warning" "cancel the commit"; do case ${CHOICE} in i*) echo "Warning ignored" ;; e*) echo ${local_editor} $1 echo verify_info "$1" $2 ;; *) echo "CHOICE = ${CHOICE}" exit 1 ;; esac done 0<&3 3<&- done } 3<&- 3<&0 

当从命令行运行git commit时,这工作正常。 如果你使用gitk或者git-gui,在windows上(没有在linux上试过),你将无法提示,因为你在“exec </ dev / tty”行中出现错误。

解决的办法是在你的hook中调用git-bash.exe:

.git / hooks / post-commit包含:

 #!/bin/sh exec /c/Program\ Files/Git/git-bash.exe /path/to/my_repo/.git/hooks/post-checkout.sh 

.git / hooks / post-commit.sh文件包含:

 # -------------------------------------------------------- # usage: f_askContinue "my question ?" function f_askContinue { local myQuestion=$1 while true; do read -p "${myQuestion} " -n 1 -r answer case $answer in [Yy]* ) printf "\nOK\n"; break;; [Nn]* ) printf "\nAbandon\n"; exit;; * ) printf "\nAnswer with Yes or No.\n";; esac done } f_askContinue "Do you want to continue ?" echo "This command is executed after the prompt !"