How do I prompt the user from within a commit-msg hook?
如果用户的提交消息未遵循某些准则,我想警告用户,然后为他们提供编辑其提交消息,忽略警告或取消提交的选项。 问题是我似乎无法访问stdin。
以下是我的commit-msg文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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 |
当我将范围信息保留为空白时,以下是输出:
1 2 3 4 5 | Scope information should not be omitted Do you want to: 1) edit the commit message 3) cancel the commit 2) ignore this warning #? |
该消息是正确的,但实际上并没有停止输入。 我也尝试过使用更简单的"读取"命令,它也有同样的问题。 似乎问题在于,这时git可以控制stdin并提供自己的输入。 我该如何解决?
更新:似乎这可能是这个问题的重复,很不幸,这似乎表明我不走运。
调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #!/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 |
可靠通知用户的唯一方法是将错误写入stdout,将提交消息的副本放置在
如果您对环境有一定的控制权,则可以有一个替代的编辑器,它是一个包装脚本,用于检查建议的消息,并可以使用额外的注释消息重新启动编辑器。
基本上,您运行编辑器,根据规则检查保存的文件。如果失败,则在文件前添加警告消息(以
您甚至可以允许他们在消息中放入
如何在Node.js或TypeScript中做到这一点
编辑:我做了一个npm包
我看到人们在Eliot Sykes答案中评论如何针对其他语言进行操作,但是JavaScript解决方案有点长,所以我将单独回答。
我不确定是否需要
我改编了这个GitHub问题的答案
我没有看到有关如何使用
您必须使用
无论如何,我想将其与Husky.js一起使用,到目前为止,它似乎仍然有效。我有空的时候应该把它变成一个npm包。
Node.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #!/usr/bin/env node const fs = require('fs'); const tty = require('tty'); if (!process.stdin.isTTY) { const { O_RDONLY, O_NOCTTY } = fs.constants; let fd; try { fd = fs.openSync('/dev/tty', O_RDONLY + O_NOCTTY); } catch (error) { console.error('Please push your code in a terminal.'); process.exit(1); } const stdin = new tty.ReadStream(fd); Object.defineProperty(process, 'stdin', { configurable: true, enumerable: true, get: () => stdin, }); } ...Do your stuff... process.stdin.destroy(); process.exit(0); |
打字稿:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #!/usr/bin/env ts-node import fs from 'fs'; import tty from 'tty'; if (!process.stdin.isTTY) { const { O_RDONLY, O_NOCTTY } = fs.constants; let fd; try { fd = fs.openSync('/dev/tty', O_RDONLY + O_NOCTTY); } catch (error) { console.error('Please push your code in a terminal.'); process.exit(1); } // @ts-ignore: `ReadStream` in @types/node incorrectly expects an object. // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/37174 const stdin = new tty.ReadStream(fd); Object.defineProperty(process, 'stdin', { configurable: true, enumerable: true, get: () => stdin, }); } ...Do your stuff... process.stdin.destroy(); process.exit(0); |
从命令行运行git commit时,这工作正常。在Windows上(尚未在Linux上尝试过),如果您使用gitk或git-gui,则将无法进行提示,因为在" exec dev / tty"行上出现错误。
解决方法是在您的钩子中调用git-bash.exe:
.git / hooks / post-commit包含:
1 2 | #!/bin/sh exec /c/Program\ Files/Git/git-bash.exe /path/to/my_repo/.git/hooks/post-checkout.sh |
.git / hooks / post-commit.sh文件包含:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # -------------------------------------------------------- # 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" OK "; break;; [Nn]* ) printf" Abandon "; exit;; * ) printf" Answer with Yes or No. ";; esac done } f_askContinue"Do you want to continue ?" echo"This command is executed after the prompt !" |
为了使
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # 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 |
1 2 3 4 5 6 7 | read -p"Question? [y|n]" -n 1 -r < /dev/tty echo if echo $REPLY | grep -E '^[Yy]$' > /dev/null; then #do if Yes else #do if No fi |