644 Stimmen

Wie verwendet man git bisect?

Ich habe in einigen Artikeln gelesen, dass git bisect ist großartig. Aber ich bin kein Muttersprachler und kann nicht verstehen, warum das so toll ist.

Könnte jemand bitte mit einem Codebeispiel demonstrieren:

  1. Wie wird es verwendet?
  2. Ist es genau wie svn blame ?

2 Stimmen

@01: Wie das Git-Buch sagt: eine Brute-Force-Suche durch die Projekthistorie durchführen .

26 Stimmen

Nicht so ///brute :-), es verwendet binäre Suche.

2 Stimmen

"git blame" ist ähnlich wie "svn blame". "git bisect" ist etwas völlig anderes

869voto

Sylvain Defresne Punkte 39987

Die Idee dahinter git bisect ist es, eine binäre Suche in der Historie durchzuführen, um eine bestimmte Regression zu finden. Stellen Sie sich vor, Sie haben die folgende Entwicklungshistorie:

... --- 0 --- 1 --- 2 --- 3 --- 4* --- 5 --- current

Sie wissen, dass Ihr Programm im Moment nicht richtig funktioniert current Revision, und dass es bei der Revision funktioniert hat 0 . Die Regression wurde also wahrscheinlich in einer der folgenden Übertragungen eingeführt 1 , 2 , 3 , 4 , 5 , current .

Sie könnten versuchen, jeden Commit zu überprüfen, ihn zu bauen und zu prüfen, ob die Regression vorhanden ist oder nicht. Bei einer großen Anzahl von Commits kann dies sehr lange dauern. Dies ist eine lineare Suche. Mit einer binären Suche können wir mehr erreichen. Das ist das, was die git bisect Befehl tut. Bei jedem Schritt wird versucht, die Anzahl der potenziell schlechten Revisionen um die Hälfte zu reduzieren.

Sie verwenden den Befehl wie folgt:

$ git stash save
$ git bisect start
$ git bisect bad
$ git bisect good 0
Bisecting: 2 revisions left to test after this (roughly 2 steps)
[< ... sha ... >] 3

Nach diesem Befehl, git checkt eine Übertragung aus. In unserem Fall wird es der Commit 3 . Sie müssen Ihr Programm erstellen und prüfen, ob die Regression vorhanden ist oder nicht. Sie müssen auch mitteilen git den Status dieser Revision mit entweder git bisect bad wenn die Regression vorhanden ist, oder git bisect good wenn dies nicht der Fall ist.

Nehmen wir an, dass die Regression in Commit eingeführt wurde 4 . Dann ist die Regression in dieser Revision nicht vorhanden, und wir sagen ihr, dass sie git .

$ make
$ make test
... ... ...
$ git bisect good
Bisecting: 0 revisions left to test after this (roughly 1 step)
[< ... sha ... >] 5

Es wird dann eine weitere Übergabe auschecken. Entweder 4 o 5 (da es nur zwei Übertragungen gibt). Nehmen wir an, es wählte 5 . Nach einem Build testen wir das Programm und stellen fest, dass die Regression vorhanden ist. Dann sagen wir dem Programm, dass es git :

$ make
$ make test
... ... ...
$ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[< ... sha ... >] 4

Wir testen die letzte Revision, 4 . Und da er derjenige ist, der die Regression eingeführt hat, sagen wir ihm, dass er git :

$ make
$ make test
... ... ...
$ git bisect bad
< ... sha ... > is the first bad commit
< ... commit message ... >

In dieser einfachen Situation mussten wir nur 3 Versionen testen ( 3 , 4 , 5 ) anstelle von 4 ( 1 , 2 , 3 , 4 ). Dies ist ein kleiner Gewinn, aber das liegt daran, dass unsere Geschichte so klein ist. Wenn der Suchbereich aus N Commits besteht, sollten wir erwarten, 1 + log2 N Commits zu testen mit git bisect anstelle von etwa N / 2 Übertragungen bei einer linearen Suche.

Sobald Sie den Commit gefunden haben, der die Regression eingeführt hat, können Sie ihn untersuchen, um das Problem zu finden. Sobald dies geschehen ist, verwenden Sie git bisect reset um alles wieder in den ursprünglichen Zustand zu versetzen, bevor Sie git bisect comando.

14 Stimmen

Ich werde hier widersprechen, das ist eine gute Erklärung der Winkelhalbierenden, aber sie hilft mir nicht wirklich bei der Anwendung. Vor allem, da ich es geschafft habe, einen guten Commit zu finden und ich bin jetzt auf diesem Zweig. Von dieser Position aus ist diese Erklärung überhaupt keine Hilfe. Wie gebe ich den schlechten Zweig an, ohne ihn auszuchecken, zum Beispiel

7 Stimmen

Sie können verwenden git bisect bad <rev> [<rev>...] um bestimmte Überarbeitungen als schlecht zu kennzeichnen (oder gut mit git bisect good <rev> [<rev>...] ). rev kann ein beliebiger Revisionsbezeichner wie ein Zweigname, ein Tag, ein Commit-Hash (oder ein eindeutiges Präfix eines Commit-Hash), ... sein.

60 Stimmen

...und wenn Sie fertig sind, tippen Sie git bisect reset um alles wieder auf den letzten Stand zu bringen

248voto

git bisect run automatische Halbierung

Wenn Sie eine automatisierte ./test Skript, das den Exit-Status 0 hat, wenn der Test OK ist, können Sie den Fehler automatisch finden mit bisect run :

git checkout KNOWN_BAD_COMMIT
git bisect start

# Confirm that our test script is correct, and fails on the bad commit.
./test
# Should output != 0.
echo $?
# Tell Git that the current commit is bad.
git bisect bad

# Same for a known good commit in the past.
git checkout KNOWN_GOOD_COMMIT
./test
# Should output 0.
echo $?
# After this, git automatically checks out to the commit
# in the middle of KNOWN_BAD_COMMIT and KNOWN_GOOD_COMMIT.
git bisect good

# Bisect automatically all the way to the first bad or last good rev.
git bisect run ./test

# End the bisect operation and checkout to master again.
git bisect reset

Dies setzt natürlich voraus, dass das Testskript ./test wird von Git nachverfolgt, so dass es nicht bei einem früheren Commit während der Bisection verschwindet.

Ich habe festgestellt, dass man sehr oft damit auskommt, wenn man das In-Tree-Skript einfach aus dem Tree kopiert und eventuell mit PATH -ähnlichen Variablen, und führen Sie es stattdessen von dort aus.

Natürlich, wenn die Testinfrastruktur, auf der test von älteren Commits abhängt, dann gibt es keine Lösung, und Sie müssen die Dinge manuell erledigen und entscheiden, wie Sie die einzelnen Commits testen.

Ich habe jedoch festgestellt, dass diese Automatisierung oft funktioniert und eine enorme Zeitersparnis für langsamere Tests sein kann, die in Ihrem Aufgabenrückstand liegen, wo Sie sie einfach über Nacht laufen lassen können und möglicherweise Ihren Fehler am nächsten Morgen identifiziert haben, es ist einen Versuch wert.

Weitere Tipps

Bleiben Sie bei der ersten fehlgeschlagenen Übergabe nach dem Bisect, anstatt zurück zu master :

git bisect reset HEAD

start + anfänglich bad y good auf einen Schlag:

git bisect start KNOWN_BAD_COMMIT KNOWN_GOOD_COMMIT~

ist dasselbe wie:

git checkout KNOWN_BAD_COMMIT
git bisect start
git bisect bad
git bisect good KNOWN_GOOD_COMMIT

Sehen Sie, was bisher getestet wurde (durch manuelle good y bad o run ):

git bisect log

Beispielhafte Ausgabe:

git bisect log
git bisect start
# bad: [00b9fcdbe7e7d2579f212b51342f4d605e53253d] 9
git bisect bad 00b9fcdbe7e7d2579f212b51342f4d605e53253d
# good: [db7ec3d602db2d994fe981c0da55b7b85ca62566] 0
git bisect good db7ec3d602db2d994fe981c0da55b7b85ca62566
# good: [2461cd8ce8d3d1367ddb036c8f715c7b896397a5] 4
git bisect good 2461cd8ce8d3d1367ddb036c8f715c7b896397a5
# good: [8fbab5a3b44fd469a2da3830dac5c4c1358a87a0] 6
git bisect good 8fbab5a3b44fd469a2da3830dac5c4c1358a87a0
# bad: [dd2c05e71c246f9bcbd2fbe81deabf826c54be23] 8
git bisect bad dd2c05e71c246f9bcbd2fbe81deabf826c54be23
# bad: [c536b1b7242d5fcf92cd87e9a534bedb1c0c9c05] 7
git bisect bad c536b1b7242d5fcf92cd87e9a534bedb1c0c9c05
# first bad commit: [c536b1b7242d5fcf92cd87e9a534bedb1c0c9c0

Zeigen Sie gute und schlechte Schiedsrichter im Git-Log an, um eine bessere Vorstellung von der Zeit zu bekommen:

git log --decorate --pretty=fuller --simplify-by-decoration master

Dies zeigt nur Commits mit einem entsprechenden Ref an, was das Rauschen stark reduziert, aber auch automatisch generierte Refs des Typs enthält:

refs/bisect/good*
refs/bisect/bad*

die uns mitteilen, welche Übertragungen wir als gut oder schlecht markiert haben.

Erwägen Sie dieses Test-Repositorium wenn Sie mit dem Befehl herumspielen wollen.

Scheitern ist schnell, Erfolg ist langsam

Manchmal:

  • Fehler passieren schnell, z. B. wenn einer der ersten Tests abbricht
  • der Erfolg dauert eine Weile, z. B. wird der defekte Test bestanden, und alle anderen Tests, die uns nicht interessieren, folgen

Für diese Fälle, z. B. wenn der Fehler immer innerhalb von 5 Sekunden auftritt, und wenn wir zu faul sind, den Test spezifischer zu gestalten, können wir Folgendes verwenden timeout wie in:

#!/usr/bin/env bash
timeout 5 test-command
if [ $? -eq 1 ]; then
  exit 1
fi

Dies funktioniert, da timeout Ausgänge 124 während das Scheitern von test-command Ausgänge 1 .

Magische Ausgangszustände

git bisect run ist ein wenig wählerisch, was den Exit-Status angeht:

  • alles über 127 führt dazu, dass die Halbierung fehlschlägt mit etwas wie:

    git bisect run failed:
    exit code 134 from '../test -aa' is < 0 or >= 128

    Insbesondere ist ein C assert(0) führt zu einer SIGABRT und beendet sich mit Status 134, sehr ärgerlich.

  • 125 ist magisch und lässt den Lauf überspringen mit git bisect skip .

    Damit soll verhindert werden, dass Builds aus unerfindlichen Gründen nicht funktionieren.

Ver man git-bisect für die Einzelheiten.

Sie könnten also etwas wie verwenden:

#!/usr/bin/env bash
set -eu
./build
status=0
./actual-test-command || status=$?
if [ "$status" -eq 125 ] || [ "$status" -gt 127 ]; then
  status=1
fi
exit "$status"

Getestet auf git 2.16.1.

7 Stimmen

Woher weiß Git, dass Ihr neuer Test nicht verschwindet, wenn Sie zu einer früheren/schlechten Revision zurückkehren (in der Ihr neu geschriebener Test nicht enthalten war)?

8 Stimmen

@thebjorn Sie haben einen Punkt: Soweit ich weiß, muss der Test entweder in einer externen ausführbaren Datei im PATH oder in einer nicht verfolgten Datei im Repo sein. In vielen Fällen ist das möglich: Legen Sie den Test in einer separaten Datei ab, fügen Sie die notwendige Test-Boilerplate mit einem gut ausgearbeiteten test_script + modulare Testsuite, und führen Sie es aus der separaten Datei während der Halbierung. Wenn Sie den Test behoben haben, fügen Sie ihn in die Haupt-Testsuite ein.

1 Stimmen

@CiroSantilli Sorry, ich habe deinen Edit unten zurückgenommen, weil ich denke, dass er für Neulinge erklärender ist und nur einen weiteren Punkt zu deiner Antwort hinzufügt (nicht eine exakte Antwort wie deine - daher die Erwähnung, um einen Punkt hinzuzufügen)

181voto

Geoffrey Hale Punkte 9139

TL;DR

Start:

$ git bisect start
$ git bisect bad
$ git bisect good <goodcommit>

Oder

$ git bisect start
$ git bisect good
$ git bisect bad <badcommit>

Bisecting: X revisions left to test after this (roughly Y steps)

Wiederholen Sie das:

Besteht das Problem noch?

  • Ja: $ git bisect bad
  • Nein: $ git bisect good

Ergebnis:

<abcdef> is the first bad commit

Wenn Sie fertig sind:

git bisect reset

9 Stimmen

Vergewissern Sie sich, dass Sie sich im Wurzelverzeichnis Ihres Git-Repos befinden, sonst erhalten Sie eine seltsame Fehlermeldung "Sie müssen diesen Befehl von der obersten Ebene des Arbeitsbaums aus ausführen.

1 Stimmen

Also habe ich git bad auf meinem HEAD und git good auf der ersten Übergabe gemacht, als der Fehler nicht vorhanden war. Also, was als nächstes zu tun? wenn der Fehler nicht vorhanden ist git bisect gut auf die nächste Übertragung zu bewegen?

0 Stimmen

@Gobliins Wenn der Fehler nicht vorhanden ist, richtig, git bisect good um zur nächsten Übergabe überzugehen.

49voto

Nicks Punkte 15662

Nur um einen weiteren Punkt hinzuzufügen:

Wir können einen Dateinamen oder einen Pfad zu git bisect start für den Fall, dass wir wissen, dass der Fehler aus bestimmten Dateien stammt. Ein Beispiel, Angenommen, wir wissen, dass die Änderungen, die die Regression verursacht haben, im Verzeichnis com/workingDir liegen, können wir Folgendes ausführen git bisect start com/workingDir Das bedeutet, dass nur die Übertragungen geprüft werden, die den Inhalt dieses Verzeichnisses geändert haben, und das macht die Dinge noch schneller.

Wenn es schwierig ist zu sagen, ob eine bestimmte Übergabe gut oder schlecht ist, können Sie auch können Sie git bisect skip die es ignorieren wird. Wenn es genügend andere Commits gibt, wird git bisect stattdessen einen anderen Commit zur Eingrenzung der Suche verwenden.

0 Stimmen

Das gefällt mir sehr. Oft weiß ich bereits, in welcher Datei sich ein Fehler befindet, so dass ich nur noch danach suche, in welchem Commit der Fehler eingeführt wurde.

16voto

Nabeel Ahmed Punkte 16621

$ git bisect .. im Grunde ein Git-Werkzeug für die Fehlersuche . Git Bisect' debuggt, indem es durch die vorherige verpflichtet sich seit Ihrem letzten (bekannten) Arbeitseinsatz. Es verwendet die binäre Suche, um alle diese Commits zu durchsuchen, um zu demjenigen zu gelangen, der die Regression/den Fehler eingeführt hat.

$ git bisect start # Start der Halbierung

$ git bisect bad # Die aktuelle Übergabe (v1.5) hat den Regressions-/Einstellungspunkt 'bad'.

$ git bisect good v1.0 # Erwähnung des letzten funktionierenden Commits (ohne Regression)

Die Erwähnung von "schlechten" und "guten" Punkten wird helfen git bisect (binäre Suche) wählen Sie das mittlere Element (Commit v1.3). Wenn die Regression bei Commit v1.3 vorhanden ist, setzen Sie sie als neuen "schlechten" Punkt, d.h. ( Gut -> v1.0 und Schlecht -> v1.3 )

$ git bisect bad

oder ähnlich, wenn der Commit v1.3 fehlerfrei ist, setzen Sie ihn als neuen 'Good point' d.h. (*Good -> v1.3 und Bad -> v1.6).

$ git bisect good

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X