2014-11-17 15 views
31

Ich möchte durch eine Reihe von Commits gehen und einen Shell-Befehl auf jedem ausführen. Wenn der Befehl fehlschlägt, möchte ich, dass der Weg aufhört, sonst mach weiter. Ich habe mir filter-branch angesehen, aber ich möchte die Commits nicht neu schreiben, sondern einfach nachsehen. for-each-ref scheint Ihnen nicht zu ermöglichen, einen Bereich anzugeben, auf den reagiert werden soll.Git Run Shell-Befehl für jeden Commit

Mein spezifisches Problem ist, dass ich eine Reihe von Commits erstellt habe und ich möchte sicherstellen, dass jedes Commit erstellbar ist. Ich möchte wie etwas tun:

git foreach origin/master..master 'git submodule update && make clean && make' 

Ich könnte natürlich ein Shell-Skript schreiben, dies zu tun, aber es scheint, wie die Art der Sache, dass git könnte eine schöne Art und Weise zu tun.

+0

Haben Sie in Betracht gezogen, Python zu verwenden? Vielleicht könnte GitPython eine Lösung sein. Überprüfen Sie diesen Beitrag: http://StackOverflow.com/Questions/1456269/Python-Git-Module-Experiences – kmundnic

+0

Wissen Sie, dass Herkunft/Master ist gut und Master ist schlecht (oder die Umkehrung), oder versuchen Sie nur zu testen alles zwischen ihnen, ohne zu wissen, dass es irgendwo einen Fehler gibt? –

+0

@CharlesDuffy, letzteres. Ich habe von einem Arbeitspunkt angefangen und eine Reihe von Änderungen vorgenommen, die funktionierten. Dann machte ich mehrere feinkörnige Commits aus dem Stapel von nicht festgelegten Arbeitsänderungen und möchte sicherstellen, dass alle dazwischen liegenden Commits erstellbar sind. – FazJaxton

Antwort

38

Sie interaktives Fütterungsmaterial mit einer Option exec verwenden können.

git rebase -i --exec <build command> <first sha you want to test>~ 

--exec Append "exec" nach jeder Zeile a in der letzten Geschichte begehen zu schaffen. wird als eine oder mehrere Shell Befehle interpretiert.

Beim Neuanordnen und Bearbeiten von Commits werden normalerweise nicht getestete Zwischenschritte erstellt. Sie können überprüfen, ob Ihre Verlaufsbearbeitung nichts durch Ausführen eines Tests unterbrochen hat, oder mindestens Punkte im Verlauf neu kompilieren, indem Sie den Befehl "Exec" (Verknüpfung "x") verwenden.

Die interaktive Rebase wird beendet, wenn ein Befehl fehlschlägt (d. H. Beendet mit nicht-0-Status), um Ihnen die Möglichkeit zu geben, das Problem zu beheben.

+0

Die Version von Git Ich bin mit 1,7 fest.10 hat nicht die Kommandozeilenoption --exec, stattdessen habe ich nach jedem Befehl "x make" manuell eingefügt und es hat sich bewährt. Vielen Dank. –

+0

Sie können zusätzlich die Option -p- & -prepresemo-merges benötigen, wenn der Bereich der Rebase Merges enthält. – Unapiedra

+0

Für was ist das ~ am Ende gut? –

16

Wahrscheinlich möchten Sie rev-list.

#!/usr/bin/env bash 
# test_commits.sh 

while read -r rev; do 
    git checkout "$rev" 
    if ! git submodule update && make clean && make; then 
     >&2 echo "Commit $rev failed" 
     exit 1 
    fi 
done < <(git rev-list "$1") 

Dann können Sie es mit

./test_commits.sh origin/master..master 
+4

Benötigt mehr Anführungszeichen, um String-Splitting und Glob-Expansion zu vermeiden. '" $ 1 "', '" $ rev "' usw. Das Sammeln aller Ausgaben von 'git rev-list' vor dem String-Splitting und Iterieren bedeutet auch eine höhere Verzögerung als" while read -r rev; machen ...; done <<(git rev-list "$ 1") ', die den Inhalt streamen, während sie gelesen werden, anstatt den gesamten Stream zu sammeln und im Voraus zu analysieren. (Dieser Ansatz ist aus offensichtlichen Gründen auch mit sehr großen Revisionslisten speicherfreundlicher). –

+2

(Das heißt, während es Shell-Best-Practice-Möglichkeiten gibt, ist dies die beste Antwort hier und hat meine +1). –

+0

@CharlesDuffy - Ich wusste nie über diese Art des Inhalts in einer Liste, wie sie gelesen werden - danke! –

1

Hier ist ein cooler Einstrich mit xargs.

git rev-list @{upstream}..HEAD | xargs -n1 -I{} sh -c 'git checkout {} && git submodule update && make clean && make' 
+0

Je nachdem, wie weit Sie zurückgehen möchten, wäre es gut, vorher eine Sicherungskopie von '.git/logs/HEAD' zu erstellen, wenn Sie keinen" trashed up reflog "haben möchten. – CDanU