Anleitung

git bisect: den Commit finden, der den Code kaputt gemacht hat

Aktualisiert: · Skillaria.Top

git bisect findet den Commit, mit dem ein Fehler eingeschleppt wurde, per binärer Suche in der Historie. Starten Sie mit git bisect start, markieren Sie den fehlerhaften Commit mit git bisect bad und einen sicher funktionierenden mit git bisect good <hash>, prüfen Sie dann die vorgeschlagenen Commits, bis Git den Schuldigen nennt; zum Schluss git bisect reset.

git bisect sucht den Commit, der einen Fehler eingeführt hat, per binärer Suche. Sie geben einen Commit an, in dem der Bug vorhanden ist, und einen, in dem es ihn noch nicht gab – Git springt in die Mitte des Bereichs und fragt: „Ist es hier gut oder schlecht?“ Jede Antwort halbiert die Zahl der Kandidaten, deshalb ist der Schuldige unter 1000 Commits nach etwa 10 Prüfungen gefunden.

Das ist besonders wertvoll, wenn der Fehler nicht offensichtlich ist: Ein Test schlägt fehl, die Performance ist eingebrochen, das Layout verrutscht, und die Diffs verraten nichts. Statt Hunderte von Änderungen zu lesen, beantworten Sie mehrmals dieselbe einfache Frage.

Wie die binäre Suche in der Historie funktioniert

Angenommen, zwischen der funktionierenden Version v2.3 und dem aktuellen main liegen 200 Commits. Git nimmt den Commit in der Mitte und lässt ihn prüfen. Ist dort schon etwas kaputt, entstand der Fehler in der ersten Hälfte, sonst in der zweiten. Die Zahl der Kandidaten halbiert sich mit jedem Schritt: 200, 100, 50, 25, 13, 7, 4, 2, 1. Acht Prüfungen statt zweihundert.

Daraus folgt die wichtigste Voraussetzung: Die Eigenschaft „kaputt“ muss monoton sein. Ist ein Bug aufgetaucht, wieder verschwunden und erneut aufgetaucht, findet bisect einen der Übergänge, aber nicht unbedingt den, den Sie suchen.

git bisect Schritt für Schritt: der manuelle Modus

1. Einen guten und einen schlechten Commit bestimmen

Der schlechte ist meist der aktuelle HEAD. Der gute ist ein beliebiger Commit, in dem garantiert alles funktionierte: der Tag des letzten Releases oder ein Commit von vor einer Woche. Kandidaten finden Sie mit git log --oneline, git tag oder git log --since="2 weeks ago".

2. Die Sitzung starten

git bisect start
git bisect bad                 # der aktuelle Commit ist kaputt
git bisect good v2.3           # im Release v2.3 hat alles funktioniert
Bisecting: 99 revisions left to test after this (roughly 7 steps)
[4f5e6d7c...] Frontend-Abhängigkeiten aktualisieren

Dasselbe geht in einer Zeile: git bisect start HEAD v2.3 – zuerst der schlechte, dann der gute Commit. Git schaltet das Arbeitsverzeichnis sofort auf den Commit in der Mitte (im Zustand detached HEAD).

3. Prüfen und markieren

Bauen Sie das Projekt, führen Sie den Test aus oder reproduzieren Sie den Bug von Hand. Melden Sie dann das Ergebnis:

git bisect good     # hier funktioniert es
Bisecting: 49 revisions left to test after this (roughly 6 steps)

git bisect bad      # hier ist es kaputt
Bisecting: 24 revisions left to test after this (roughly 5 steps)

4. Das Ergebnis erhalten

Bleibt nur noch ein Kandidat übrig, gibt Git ihn aus:

a1b2c3d4e5f6... is the first bad commit
commit a1b2c3d4e5f6...
Author: Max Müller <max@example.com>
Date:   Tue Sep 29 11:40:12 2026 +0200

    Ergebnis der Warenkorbberechnung cachen

 src/cart.js | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

5. Die Sitzung beenden

git bisect reset

Der Befehl bringt Sie zurück auf den Branch, auf dem Sie begonnen haben. Vergessen Sie diesen Schritt nicht: Solange die Sitzung offen ist, bleiben Sie im detached HEAD, und neue Commits gehen leicht verloren. git bisect reset HEAD lässt Sie auf dem gefundenen Commit stehen, git bisect reset <commit> auf einem beliebigen angegebenen.

Automatische Suche: git bisect run

Lässt sich die Prüfung als Befehl ausdrücken, überlassen Sie die ganze Arbeit Git. git bisect run führt bei jedem Schritt ein Skript aus und markiert den Commit anhand des Exit-Codes selbst:

Exit-CodeBedeutung
0good – der Commit ist gut
1–127, außer 125bad – der Commit ist schlecht
125skip – der Commit lässt sich nicht prüfen, überspringen
über 127 (oder <0)bisect abbrechen (etwa wenn das Skript durch ein Signal beendet wurde)

Beispielaufrufe:

git bisect start HEAD v2.3
git bisect run npm test
git bisect run pytest tests/test_cart.py -x
git bisect run make check

Für komplexere Prüfungen schreiben Sie ein kleines Skript. Wichtig ist, „baut nicht“ von „Bug reproduziert“ zu trennen, sonst hält bisect einen kaputten Build für den gesuchten Fehler:

#!/bin/sh
# check.sh
npm ci --silent || exit 125      # Abhängigkeiten ließen sich nicht installieren – überspringen
npm run build   || exit 125      # baut nicht – überspringen
node scripts/check-cart-total.js # 0 – ok, 1 – Bug
chmod +x check.sh
git bisect run ./check.sh

Halten Sie das Skript außerhalb der versionierten Dateien oder in einem Ordner, der in allen geprüften Commits existiert: bisect wechselt das Arbeitsverzeichnis, und eine kürzlich hinzugefügte Datei verschwindet in alten Commits. Am sichersten legen Sie es nach /tmp oder in einen beliebigen Ordner außerhalb des Repositorys.

Ein Test, den es früher noch nicht gab

Eine häufige Situation: Sie haben einen Test geschrieben, der den Bug reproduziert, aber in alten Commits fehlt diese Datei. Die Lösung ist wieder eine Kopie außerhalb des Repositorys:

cp tests/test_regression.py /tmp/
git bisect run pytest /tmp/test_regression.py

git bisect skip: wenn sich ein Commit nicht prüfen lässt

Manchmal lässt sich der Commit in der Mitte nicht bauen oder scheitert aus einem anderen Grund. Ihn als good oder bad zu markieren wäre falsch – das verfälscht das Ergebnis. Überspringen Sie ihn:

git bisect skip
git bisect skip v2.4..v2.4.3   # einen Bereich überspringen

Git wählt einen benachbarten Commit. Liegen übersprungene Commits genau an der Grenze, sehen Sie am Ende statt eines einzelnen Commits eine Liste „möglicher Schuldiger“ – dann prüfen Sie deren Diffs von Hand.

Eigene Begriffe statt good und bad

Bisect sucht nicht nur Bugs. Vielleicht wollen Sie den Commit finden, nach dem eine Seite schneller lädt. Schnelle Commits „schlecht“ zu nennen ist verwirrend, deshalb gibt es alternative Bezeichnungen:

git bisect start --term-old=slow --term-new=fast
git bisect fast HEAD
git bisect slow v2.3

Eingebaute Synonyme sind old und new: git bisect new, git bisect old. Es gilt nur eine Regel: Der „alte“ Zustand muss zum früheren Commit gehören.

Das Sitzungsprotokoll: log, replay, visualize

  • git bisect log – gibt alle Ihre Markierungen aus. Speichern Sie es in einer Datei, wenn die Sitzung lang ist.
  • git bisect replay datei – spielt die Sitzung anhand des Protokolls erneut ab. Beim sechsten Schritt vertan? Log speichern, falsche Zeilen löschen, git bisect reset und replay ausführen.
  • git bisect visualize (oder git bisect view) – zeigt die verbleibenden Kandidaten; mit --oneline über git log.
git bisect log > /tmp/bisect.log
# Log bearbeiten
git bisect reset
git bisect replay /tmp/bisect.log

Bisect und Merge-Commits

In einer Historie mit vielen Merges kann bisect Sie in einen gemergten Branch führen – zu Commits, die entstanden, bevor der Branch mit main synchronisiert wurde, und die deshalb auf einer anderen Basis gebaut sind. Wenn Sie zuerst wissen wollen, welcher Merge den Bug gebracht hat, verwenden Sie:

git bisect start --first-parent

Dann folgt Git nur den ersten Eltern der Merge-Commits, also der Historie des Hauptbranches. Haben Sie den schuldigen Merge gefunden, können Sie ein zweites bisect innerhalb des betreffenden Branches starten.

Typische Fehler

  • good und bad verwechselt. Das Ergebnis ist dann sinnlos. Stellen Sie die Sitzung mit git bisect log und replay wieder her, statt neu anzufangen.
  • Unsauberes Arbeitsverzeichnis. Nicht committete Änderungen behindern das Wechseln zwischen Commits und beeinflussen die Prüfung. Committen Sie vor dem Start oder nutzen Sie git stash.
  • Nicht bereinigte Build-Artefakte. Ein veralteter Cache oder node_modules aus einem anderen Commit liefern falsche Ergebnisse. Bauen Sie im Skript sauber neu.
  • Instabiler (flaky) Test. Schlägt ein Test gelegentlich von selbst fehl, markiert bisect einen zufälligen Commit. Führen Sie die Prüfung mehrmals aus oder reparieren Sie den Test vor der Suche.
  • reset vergessen. Im detached HEAD geblieben und weitergearbeitet. Verlorene Commits finden Sie über reflog wieder.

Beispiel: eine Regression von Anfang bis Ende aufspüren

Nutzer melden, dass die Warenkorbsumme mit Rabatt falsch berechnet wird. In Release v2.3 stimmte alles, in main nicht. Wir schreiben eine minimale Prüfung und starten die Suche:

cat > /tmp/check.sh <<'SH'
#!/bin/sh
npm ci --silent || exit 125
node -e "const c=require('./src/cart'); process.exit(c.total([{price:100}], 0.1) === 90 ? 0 : 1)"
SH
chmod +x /tmp/check.sh

git stash                       # nicht committete Änderungen beiseitelegen
git bisect start HEAD v2.3
git bisect run /tmp/check.sh
...
a1b2c3d4e5f6... is the first bad commit
git bisect log > /tmp/cart-bisect.log
git bisect reset
git stash pop

Die gesamte Suche über hundert Commits läuft ohne Ihr Zutun, während Sie sich mit anderem beschäftigen. Das gespeicherte Log ist nützlich, wenn Sie im Ticket zeigen wollen, wie genau der Schuldige gefunden wurde.

Was tun mit dem gefundenen Commit?

Ist der Schuldige gefunden, sehen Sie ihn sich vollständig an: git show a1b2c3d. Ein kleiner Commit mit verständlicher Nachricht verrät die Ursache sofort – einer der Gründe, warum Teams atomare Commits schätzen: Ein bisect über eine Historie aus riesigen „fix stuff“-Commits ist nahezu nutzlos. Danach gibt es zwei Wege: den Fehler mit einem neuen Commit beheben oder, wenn die Änderung als Ganzes misslungen und bereits veröffentlicht ist, sie mit git revert a1b2c3d rückgängig machen.

Fazit

git bisect verwandelt die Suche nach einer Regression vom Lesen Hunderter Diffs in einige wenige Antworten „funktioniert / funktioniert nicht“ und mit git bisect run in einen einzigen Befehl. Sie brauchen nur zwei Orientierungspunkte – einen guten und einen schlechten Commit – und eine reproduzierbare Prüfung. Das Lesen der Historie, die Navigation zwischen Commits und die Fehlersuche darin werden im Git-Kurs praktisch geübt.

Häufige Fragen

Wie viele Schritte braucht git bisect?

Ungefähr log2 der Anzahl der Commits im Bereich: etwa 7 Schritte für 100 Commits und etwa 10 für 1000. Git zeigt die Schätzung roughly N steps selbst an.

Kann man bisect starten, wenn kein guter Commit bekannt ist?

Mindestens einer ist nötig. Nehmen Sie einen sicher alten Commit oder einen Release-Tag und prüfen Sie ihn von Hand; die zusätzlichen Schritte durch einen breiten Bereich kosten kaum etwas.

Verändert git bisect die Historie des Repositorys?

Nein, es wechselt nur das Arbeitsverzeichnis zwischen Commits und speichert die Markierungen in internen Referenzen unter refs/bisect, die bei git bisect reset entfernt werden.

Kann man mehrere gute Commits angeben?

Ja, git bisect good akzeptiert mehrere Commits; das grenzt den Bereich ein, besonders in einer verzweigten Historie.

Funktioniert bisect nur für die Fehlersuche?

Nein, damit finden Sie jeden Zeitpunkt, an dem sich eine Eigenschaft geändert hat: wann eine Datei auftauchte, der Build schneller wurde oder sich ein Verhalten änderte. Dafür eignen sich die Begriffe old/new oder eigene über --term-old und --term-new.

Das Thema im Video lernen

Dieses Thema wird im Kurs „Git vom Anfänger zum versierten Entwickler“ ausführlich mit Praxis behandelt.

Zum Kurs