2016-04-22 22 views
1

Ich wollte pre-commit Haken tun, wenn Python-Code folgen PEP8 überprüfen würde, so habe ich diese wie in https://www.stavros.io/posts/more-pep8-git-hooks/git pre-commit hook: triggert nur auf tatsächlichen zu committed code?

habe ich .git/hooks/pre-commit Datei. Und fügte hinzu diesen Inhalt:

#!/bin/sh 
flake8 . 

Dann: chmod +x .git/hooks/pre-commit

Aber wenn ich git commit eingeben, überprüft er tatsächlich die gesamte Branche und wenn es irgendetwas in Zweig findet, die nicht PEP8 folgen werden, wird es beenden (das Repository ist ein bisschen alt und einige Code nicht folgen pep8 von Anfang an, so dass ich weiß, es könnte refaktoriert werden, aber ich brauche nicht pre-hook, um mir das über bereits festgeschriebenen Code zu erzählen).

Wie kann ich nur den Code für das aktuelle Commit überprüfen, das committed werden soll?

+0

Ist diese Frage nicht ganz beantworten, aber dies in http://pre-commit.com behandelt wird. Dieses Projekt verwendet eine Kombination von 'git diff --gestaged --name-only' und' git-checkout' + 'git apply' (im Wesentlichen ein Stash). –

Antwort

1

Wie kann ich nur den Code für die aktuelle Festschreibung überprüfen, die festgeschrieben werden soll?

Verwenden git checkout-index die Dateien zur Kasse Sie in ein temporäres Verzeichnis begehen, und dann flake8 an diesem temporären Verzeichnis ausgeführt.

zunächst ein temporäres Verzeichnis zu erstellen:

git checkout-index --prefix=$tmpdir/ -af 

Hier finden Sie eine Liste von begehen und flake8 gegen laufen in dieser geänderten Dateien:

tmpdir=$(mktemp -d commitXXXXXX) 
trap "rm -rf $tmpdir" EXIT 

dann die Dateien Kasse in das Verzeichnis begangen werden sie:

git diff --cached --name-only --diff-filter=ACM | grep '\.py$' | 
(cd $tmpdir; xargs --no-run-if-empty flake8) 
+0

Hm, ich sollte das Script, das ich gerade geschrieben habe, wahrscheinlich modifizieren, um 'git checkout-index' anstelle von'gitcheckout' zu verwenden (benötigt dann nicht das' --work-tree' -Argument). – torek

+0

Mache ich etwas falsch? Ich habe diesen Code anstelle des einen, den ich geschrieben habe, hinzugefügt, aber es überprüft immer noch mehr als mein aktuelles Commit. Schritte, die ich getan habe. Ersetzte den Pre-Commit-Hook mit dem Code, den du geschrieben hast, änderte eine Datei ein wenig gegen pep8, fügte dann die Datei hinzu und schrieb dann 'git commit'. Dann wurde eine ganze Reihe von Warnungen über andere Module inkorrekt. – Andrius

+0

Das liegt daran, dass ich früher in Eile war und einen Schritt übersprungen habe. Alles behoben. – larsks

1

lassen sie uns zunächst answe r die Frage, die du tatsächlich gestellt hast, weil du das sowieso wissen musst:

Wie kann ich nur den Code für das aktuelle Commit überprüfen, das committed werden soll?

Der Inhalt des commit-that-will-gemacht wird, was auch immer im Index ist.

Dies ist jede Datei, nicht nur Dateien Sie vor kurzem git add Ed. Zum Beispiel, wenn Ihre Arbeitsbaum mit acht quellenkontrollierten *.py Python-Dateien hat, und Sie geändert und git add -ed zwei von ihnen, gibt es acht*.py Dateien, die dieses Mal begangen werden. Jedes Commit hat jede Datei, und nicht eine Reihe von Änderungen von einigen früheren Datei (en).

Um diese acht Dateien (und nicht den aktuellen Inhalt des Arbeitsbaums) zu überprüfen, müssen Sie den Inhalt des Index irgendwo extrahieren.

Natürlich, das ist nicht das, was Sie eigentlich wollen:

überprüft er tatsächlich die gesamte Branche und wenn es irgendetwas in Zweig findet, die nicht PEP8 folgen wird, wird es beenden (das Repository ist ein bisschen alt und einige Code nicht folgen PEP8 von Anfang an, damit ich weiß, es Refactoring werden könnte, aber ich brauche nicht vorge Haken, mir zu sagen, dass über bereits engagierten Code)

Auch hier ist es nicht wirklich überprüfen die Verzweigung; es überprüft die Arbeitsstruktur. Dies hilft zwar nicht sofort, dorthin zu gelangen, wo es nötig ist, aber es ist wichtig.

Was wir hier brauchen, ist, vielleicht aus dem Index die Dateien zu extrahieren, die sich vom aktuellen Commit unterscheiden.

Der Weg, dies zu tun, ist ein neues Commit zu machen. Im Idealfall könnten wir dieses Commit irgendwo anders als auf dem aktuellen Zweig machen, denn wenn wir es auf dem Zweig machen, müssen wir es später wieder machen.

Es gibt einen Befehl, der das tut - das macht Commits vom Index, aber nicht auf einem Zweig - und dieser Befehl ist git stash. Leider, there is a bug in git stash wenn Sie es auf diese Weise verwenden. Anstatt die Umgehungslösungen zu verwenden, die ich in dieser Antwort beschreibe, können wir etwas anderes tun: Wir können unseren eigenen Baum in einem temporären Verzeichnis erstellen, nachdem wir den aktuellen Index mit dem HEAD Commit verglichen haben.

Das Skript dafür (tatsächlich getestet, sogar!) Ist unten.


Hierher könnte man einwenden, dass git log -p oder git show zeigt Ihnen die Änderungen. Sie sind richtig, dass es Änderungen zeigt, aber es geschieht, indem Sie git diff gegen eine vorherige commit ausführen, die auch jede Datei enthält. Durch den Vergleich der vorherigen Version von "everything" mit der nächsten Version von "everything" entdeckt git, was sich geändert hat.


#! /bin/sh 

# run-checks: run some checking command(s) on a proposed commit. 
# 
# Optionally, run it only on files that differ from those in 
# the current commit (added or modified, treating rename as 
# modify), and/or do not run it at all if there are 
# no such files (e.g., if the commit consists only of file 
# removals). 

usage() 
{ 
    echo "usage: $0 [-d] checkcmd [args ...]" 1>&2 
    exit 1 
} 

# probably should use git rev-parse feature now, oh well 
diffmode=false 
skipempty=true 
while true; do 
    case "$1" in 
    -d|--diff) diffmode=true; shift;; 
    -z|--run-even-if-empty) skipempty=false; shift;; 
    -dz) diffmode=true; skipempty=false; shift;; 
    *) break;; 
    esac 
done 

case "$#" in 
0) usage;; 
esac 

# from here on, exit on error 
set -e 

# get temporary directory and arrange to clean it up 
tdir=$(mktemp -d -t run-checks) 
trap "rm -rf $tdir" 0 1 2 3 15 

# Get list of changed files (whether or not we are using 
# only the changed files). This includes deleted files. 
# For efficiency, we treat renames as delete/add pairs here. 
# Require that new commit not match current commit. 
if test $(git diff --cached --name-only --no-renames HEAD | wc -l) -eq 0; then 
    echo "no changes to test before committing" 
    exit 1 
fi 

# Populate work tree in temp dir. If we only want changed 
# files, limit the checkout to files added or modified. Note 
# that this list might be empty. 
if $diffmode; then 
    git diff --cached --name-only --no-renames --diff-filter=AM -z HEAD | 
     xargs -0 git --work-tree=$tdir checkout -f -- 
else 
    git --work-tree=$tdir checkout -f -- . 
fi 

# Now run checker in temp work tree. Our exit status is 
# its exit status. Do not use exec since we must still clean 
# up the temp dir, and optionally skip checker if work tree is empty. 
cd $tdir 
if test $(ls -A | wc -l) -eq 0; then 
    is_empty=true 
else 
    is_empty=false 
fi 
if $skipempty && $is_empty; then exit 0; fi 

if $is_empty; then 
    [email protected] 
else 
    [email protected] * 
fi