78

コミットメッセージが特定のガイドラインに準拠していない場合はユーザーに警告し、コミットメッセージを編集するか、警告を無視するか、コミットをキャンセルするかを選択できるようにします。問題は、私がstdinにアクセスできないように見えることです。

以下は私の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 information should not be omitted
Do you want to:
1) edit the commit message  3) cancel the commit
2) ignore this warning
#?

メッセージは正しいですが、実際には入力のために停止しません。より単純な「読み取り」コマンドを使用してみましたが、同じ問題があります。問題は、この時点でgitがstdinを制御し、独自の入力を提供していることだと思われます。これを修正するにはどうすればよいですか?

更新:これはこの質問の複製である可能性がありますが、残念ながら私は運が悪いことを示唆しているようです。

4

6 に答える 6

167

呼び出しexec < /dev/ttyは、キーボードに標準入力を割り当てます。コミット後のgitフックで動作します:

#!/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
于 2012-04-04T16:49:05.757 に答える
7

commit-msgフックはインタラクティブな環境では実行されません(お気づきのとおり)。

ユーザーに確実に通知する唯一の方法は、stdoutにエラーを書き込み、コミットメッセージのコピーをファイルに配置し、BAD_MSGファイルを編集するようにユーザーに指示することです。git commit --file=BAD_MSG


環境をある程度制御できる場合は、提案されたメッセージをチェックするラッパースクリプトである代替エディターを使用して、追加のコメント付きメッセージでエディターを再起動できます。

基本的に、エディターを実行し、保存されたファイルをルールと照らし合わせてチェックします。失敗した場合は、警告メッセージ(先頭に#)をファイルの前に追加して、エディターを再起動します。

#FORCE=trueチェックを抑制して続行するメッセージに行を入れることを許可することもできます。

于 2010-08-20T18:23:28.140 に答える
3
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
于 2019-02-25T13:05:30.763 に答える
2

これは、コマンドラインからgitcommitを実行するときに正常に機能します。Windows(Linuxでは試していません)では、gitkまたはgit-guiを使用すると、「exec </ dev / tty」行でエラーが発生するため、プロンプトを表示できません。

解決策は、フックで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 !"
于 2017-04-26T11:58:20.583 に答える
2

Node.jsまたはTypeScriptでそれを行う方法

編集:私はnpmパッケージを作成しました


Eliot Sykesの回答で、他の言語でそれを行う方法についてコメントしている人がいますが、JavaScriptソリューションは少し長いので、別の回答をします。

必要かどうかO_NOCTTYはわかりませんが、何の影響も受けていないようです。制御端末とは何なのかよくわかりません。GNUドキュメントの説明O_NOCTTYこれが意味することは、 onを使用すると、プロセスにを送信できなくなることだと思いCTRL+Cます(制御端末がまだない場合)。その場合は、生成されたプロセスを制御しないように、オンのままにしておきます。メインノードのプロセスには、すでに制御端末が必要だと思います。

このGitHubの問題からの回答を採用しました

コンストラクターの使用方法に関するドキュメントが表示されないため、 Node.jsのソースコードtty.ReadStreamを少し試行錯誤して調べました。

Node.jsの内部もそれを使用し、セッターを定義しないため、使用する必要がありますObject.defineProperty。別の方法は実行することですが、その方法で重複した出力が得られます。process.stdin.fd = fd

とにかく、私はこれをHusky.jsで使用したかったのですが、これまでのところ機能しているようです。時間があれば、おそらくこれをnpmパッケージに変換する必要があります。

Node.js

#!/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);

TypeScript:

#!/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);
于 2019-07-27T02:18:18.870 に答える
1

入力をselect停止するにはstdinselectfromをリダイレクトすることもできます( whileループ内のbashで入力を読み取るを/dev/fd/3参照)。

# 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
于 2013-05-03T11:27:29.713 に答える