2010-08-05 11 views
48

Voglio avvisare l'utente se il suo messaggio di commit non segue un determinato insieme di linee guida e quindi dare loro la possibilità di modificare il messaggio di commit, ignorare l'avviso o annullare il commit. Il problema è che non sembra avere accesso a stdin.Come si chiede all'utente di accedere a un hook di commit-msg?

Qui di seguito è il mio file di commettere-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 

Ecco l'output quando lascio le informazioni Ambito vuoto:

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

Il messaggio è corretto, ma in realtà non si ferma per l'input. Ho anche provato a usare il più semplice comando "leggi", e ha lo stesso problema. Sembra che il problema sia che a questo punto git ha il controllo di stdin e sta fornendo il proprio input. Come posso risolvere questo?

Aggiornamento: Sembra che questo potrebbe essere un duplicato di this question che purtroppo sembra suggerire che sono sfortunato.

+0

Quando si ha accesso a un server X si può sfuggire ad uno strumento di dialogo grafica. Brutto ma funzionante – Rudi

+0

Al posto del messaggio di errore è possibile fornire semplicemente un messaggio di errore informativo, incluso l'eco del comando necessario per ignorare l'avviso. – bstpierre

+0

@btspierre, questo è l'approccio che ho preso. Su consiglio di John Feminella, ho permesso l'uso di una variabile di ambiente per ignorare l'avviso e fare semplicemente eco all'avviso ogni volta che si verifica una situazione non valida. –

risposta

108

La chiamata exec < /dev/tty assegna l'input standard alla tastiera. Funziona per me in un gancio git post-commit:

#!/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 
+13

STDIN può essere chiuso di nuovo con 'exec <& -' – Andy

+10

Se stai usando Ruby, questo si tradurrebbe in 'STDIN.reopen ('/ dev/tty')'. Roba fantastica, questa è la vera risposta. –

+2

Questo è fantastico, ma potrebbe rompersi quando si esegue il commit da un altro strumento, come un editor. Non sono sicuro di come aggirarlo, ma se qualcuno ha un'idea, sarei interessato a sentirlo. – Peeja

4

L'hook di commit-msg non viene eseguito in un ambiente interattivo (come notato).

L'unico modo per informare l'utente in modo affidabile è scrivere un errore nello stdout, inserire una copia del messaggio di commit in un file "BAD_MSG" e chiedere all'utente di modificare il file e "git commit --file = BAD_MSG'


Se avete qualche controllo sull'ambiente si potrebbe avere un editor alternativo, che è uno script wrapper che controlla il messaggio proposto, e in grado di riavviare l'editor con un messaggio in più commentato.

Fondamentalmente, si esegue l'editor, controllare il file salvato rispetto alle regole. e se fallisce, aggiungi il tuo messaggio di avvertimento (con il numero iniziale) al file e riavvia l'editor.

Si potrebbe anche consentire loro di inserire una riga "# FORCE = true" nel messaggio che eliminerebbe il controllo e continuerà.

+3

Prova a chiamare 'exec

+0

Anche se questa è una risposta ben ponderata, Eliot dovrebbe essere accettato poiché dimostra che * è * effettivamente possibile! –

+0

L'utente può saltare i ganci con '--no-verify', non è necessario ricorrere a' # FORCE = true' hackery. – fsaintjacques

1

Per rendere select arresto per l'ingresso, si può anche provare a reindirizzare la stdin di select da /dev/fd/3 (Vedi: Read input in bash inside a while loop).

# 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 
0

funziona correttamente quando si esegue git commit dalla riga di comando. Su windows (non ho provato su linux) se usi gitk o git-gui non sarai in grado di richiedere perché ricevi un errore sulla riga "exec </dev/tty".

Il sollution è chiamare git-bash.exe nel vostro gancio:

.git/ganci/post-commit contiene:

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

il .git/ganci/post-commit.file di sh contiene:

# -------------------------------------------------------- 
# 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 !"