1 Punkte von GN⁺ 2025-01-20 | 1 Kommentare | Auf WhatsApp teilen
  • Git help.autocorrect=1 wartet nach der Korrektur eines vertippten Befehls nur 0,1 Sekunden und führt ihn dann aus – praktisch fast sofort, zu schnell, als dass Nutzer prüfen oder abbrechen könnten
  • Dieses Verhalten ist nicht der Git-Standard; in der Voreinstellung führt Git unbekannte Befehle nicht aus, sondern zeigt nur ähnliche Befehle an und beendet sich
  • In einer Diskussion von 2008 wurde help.autocorrect von einem Boolean zu einer Wartezeit in Dezisekunden geändert, sodass 1 nicht als true, sondern als 0,1 Sekunden Wartezeit interpretiert wird
  • Aktuell unterstützt help.autocorrect die Werte 0, positive Zahlen, immediate, prompt und never; wer vor der Ausführung bestätigen möchte, fährt mit prompt sicherer
  • Git schätzt Befehle auf Basis einer modifizierten Levenshtein-Distanz; Scott Chacon schlug einen Patch vor, der 1 und Boolean-Strings natürlicher behandelt

Bis git pushy als git push ausgeführt wird

  • Als @dhh git pushy eingab, vermutete Git git push und wartete vor der Ausführung nur 0,1 Sekunden
  • 0,1 Sekunden sind zu kurz, damit ein Nutzer den Befehl lesen, beurteilen und abbrechen kann
  • Dieses Verhalten ist nicht Git-Standard, sondern tritt auf, wenn die Einstellung help.autocorrect aktiviert ist

Standardverhalten und die Entstehung von help.autocorrect

  • Standardmäßig führt Git unbekannte Befehle nicht aus, sondern zeigt anhand der String-Ähnlichkeit mögliche Befehle an und beendet sich
    • Beispiel: Bei git pushy kann Git anzeigen, dass push der ähnlichste Befehl ist
  • Ursprünglich antwortete Git bei unbekannten Befehlen lediglich mit „kein Git-Befehl“
  • 2008 schlug Johannes Schindelin einen kleinen Patch vor, der bekannte Befehle durchsucht, den ähnlichsten findet und ihn ausführt, wenn es nur einen nahen Kandidaten gibt
  • Alex Riesen lieferte einen Patch, der dies über die Einstellung help.autocorrect steuerbar machte; anfangs war diese Einstellung ein Boolean
    • In der Git-Konfiguration kann der Boolean-Wert 1 als true interpretiert werden
    • Im ursprünglichen Kontext konnte help.autocorrect=1 daher wie ein Wert wirken, der Autokorrektur einschaltet

Warum 1 zu 0,1 Sekunden wurde

  • Junio Hamano schlug vor, help.autocorrect nicht als einfachen Boolean zu behandeln, sondern als Anzahl der Dezisekunden, die vor der Ausführung gewartet wird
    • Eine Dezisekunde entspricht 0,1 Sekunden
    • Die Absicht war, Nutzern eine Gelegenheit zu geben, ^C zu drücken
  • In dem später akzeptierten Patch wurde der Einstellungswert zu einer Wartezeit geändert
  • Dadurch bedeutet help.autocorrect=1 nicht „Funktion einschalten“, sondern „1 Dezisekunde, also 0,1 Sekunden warten und dann ausführen“
  • Warum Dezisekunden als geeignete Zeiteinheit gewählt wurden, ist in der Diskussion nicht überliefert

Welche Einstellungswerte es heute gibt

  • Laut Git-Dokumentation unterstützt help.autocorrect folgende Werte
    • 0: Standardwert; zeigt nur vorgeschlagene Befehle an
    • Positive Zahl: führt den vorgeschlagenen Befehl nach der angegebenen Anzahl Dezisekunden aus
    • immediate: führt den vorgeschlagenen Befehl sofort aus
    • prompt: zeigt den Vorschlag an und fragt vor der Ausführung nach Bestätigung
    • never: führt vorgeschlagene Befehle weder aus noch zeigt es sie an
  • Wer vor der Ausführung bestätigen möchte, für den ist prompt für die meisten Nutzer die sinnvollere Wahl
  • Eine Beispielkonfiguration sieht so aus
git config --global help.autocorrect prompt
  • Gibt man danach einen Befehl wie git pushy ein, fragt Git mit [y/N], ob push ausgeführt werden soll

Wie Git ähnliche Befehle auswählt

  • Git rät Befehle nicht wahllos, sondern geht ab einem bestimmten Punkt davon aus, dass die Eingabe zu weit entfernt ist, und gibt keinen Kandidaten aus
  • Beispielverhalten:
    • git bass ist nah genug an rebase, um eine Ausführungsbestätigung anzuzeigen
    • Bei git bassa entscheidet Git, dass es nicht mehr plausibel als rebase gelten kann, und führt keinen Kandidaten aus
    • git dm zeigt sowohl am als auch rm als ähnliche Befehle an
    • git dma wird eindeutig auf am gematcht
  • Diese Logik basiert auf einem modifizierten Levenshtein-Distanz-Algorithmus
    • Er berechnet die Kosten für Zeichenoperationen, die nötig sind, um einen String in einen anderen umzuwandeln
    • Einige Operationen werden teurer bewertet als andere
  • Git hat einen hart codierten Cutoff: Wenn die Kosten im Vergleich zu bekannten Befehlen zu hoch sind, geht Git davon aus, dass der Nutzer sich stark vertippt hat, und macht keine Vermutung

Patch zur Änderung der Interpretation von 1

  • Weil help.autocorrect=1 aus menschlicher Sicht praktisch immediate entspricht, schrieb Scott Chacon einen kleinen Patch, der 1 nicht als 0,1 Sekunden Wartezeit, sondern als sofortige Ausführung interpretiert
  • Junio Hamano bat darum, nicht nur "1" speziell zu behandeln, sondern auch Boolean-String-Werte wie yes, no, true und off korrekt zu interpretieren
  • Die zweite Version des Patches entwickelt sich in Richtung einer Behandlung auch dieser Boolean-Strings
  • Wenn der Patch übernommen wird, könnte die Verwirrung rund um help.autocorrect in künftigen Git-Versionen abnehmen

1 Kommentare

 
GN⁺ 2025-01-20
Meinungen auf Hacker News
  • In den 70ern brachte Hal Finney einen BASIC-Interpreter für die Mattel Intellivision in ein 2-KB-ROM unter, und jedes einzelne Byte war kostbar.
    Ich finde es immer noch lustig, dass er alle Fehlermeldungen auf EH? verkürzte, um Syntaxfehler anzuzeigen, und darauf ziemlich stolz war.

    • EH? würde auch gut als Antwort eines Textparsers in alten Interactive-Fiction-Spielen passen.
      Ein wenig verwandt damit: In einigen alten BASIC-Varianten konnte man die PRINT-Anweisung auch als ? schreiben; das diente wohl eher dazu, im REPL Tippzeit zu sparen, als Speicher zu sparen.
    • Ziemlich verschwenderisch. ed verwendet für alle Fehler nur ein einziges ?, also dreimal so sparsam.
    • Das früheste Beispiel, das ich für Eh? als Interpreter-Antwort gesehen habe, war JOSS von RAND.
      [https://en.wikipedia.org/wiki/JOSS#/media/File:JOSS_Session....](https://en.wikipedia.org/wiki/JOSS#/media/File:JOSS_Session.jpg)
      https://en.wikipedia.org/wiki/JOSS
      Der Speicher lag bei etwa 5 KB, aber verglichen mit der Intellivision wog die Maschine ungefähr 5.000 Pfund.
    • Ziemlich cool. Ich wusste nicht, dass Hal damals ein Personal-Computer-Hacker war; wenn ich von Hal höre, denke ich immer an Bitcoin.
    • Ich betreibe xordle, ein von Wordle abgeleitetes Spiel, bei dem zwei Wordle-Rätsel auf einem Board stecken.
      Dadurch kann man ein Wort raten, bei dem alle fünf Buchstaben grün werden, das aber trotzdem keine der beiden richtigen Lösungen ist. In so einem Fall lasse ich rechts einfach Huh? anzeigen, und die Leute mögen diesen Teil.
  • Die eigentliche Ursache ist, dass der Name der Einstellung schlecht gewählt ist.
    Wenn die ursprüngliche Einstellung boolesch klingend wie help.autocorrect_enabled geheißen hätte, wäre die Forderung, einen Integer-Wert zu akzeptieren und ihn als Zehntelsekunden zu interpretieren, unsinnig gewesen. Stattdessen hätte man eine andere Einstellung wie help.autocorrect_accept_after_dsec gebraucht, und dsec ist so ungebräuchlich, dass Nutzer es zwangsläufig nachschlagen müssten.
    In Code-Reviews verlange ich so etwas immer: Wenn etwas mehrdeutig sein kann, muss die Einheit im Variablennamen stehen. Zum Beispiel sollte aus int timeout ein int timeout_msec werden.
    Bei Einstellungsnamen ist das 100-mal wichtiger, weil Einstellungen Teil der öffentlichen Schnittstelle sind und sich später nicht mehr ändern lassen.

    • Sehe ich genauso. Allerdings hadere ich immer noch damit, wenn das ins Typsystem verlagert wird.
      Im C++-Kontext lautet meine grobe Faustregel: void FooBar(std::chrono::milliseconds timeout); ist in Ordnung, weil man beim Blick auf die Funktionssignatur auch den Typ sieht.
      Bei Variablen ist timeout dagegen nicht in Ordnung. In 99 % der Fälle sieht die tatsächliche Verwendung eher wie auto timeout = gl_timeout; oder FooBar(timeout); aus.
      Weil auto in C++ so häufig verwendet wird, wird es ziemlich lästig, genau dann den exakten Typ nachzuverfolgen, wenn es wichtig ist.
      Bei C++-Arbeit nutze ich zwar eine IDE oder einen Editor mit Language Server, aber ich habe keine Zeit, alle fünf Sekunden mit der Maus über etwas zu fahren, um den Typ zu prüfen.
    • Genau, und dass hier eine Zeiteinheit verwendet wurde, die ich im ganzen Leben buchstäblich noch nie benutzt habe, nämlich Zehntelsekunden (Deciseconds), macht die Sache noch schlimmer.
      Wenn die Meldung „wird in 1 ms ausgeführt“ gelautet hätte, hätte man sofort die Einstellung überprüft.
    • Dann landet man irgendwann in einem Zustand wie bei systemd, wo sowohl TimoutSec=60 als auch TimeoutSec=1min möglich sind.
      Ich denke, es wäre besser gewesen, die Einheit gar nicht in den Namen aufzunehmen. Abgesehen von diesem Sonderfall stimme ich aber völlig zu.
    • Ich mache das zwar auch so, kann aber den Gedanken nicht abschütteln, dass es nach ungarischer Notation riecht.
      Die beste Alternative, die ich bisher gefunden habe, ist, die Einheit im Wert selbst zu verlangen. Also etwa 5 seconds oder 5s zu erlauben und ein bloßes 1 als ungültigen Wert zu behandeln.
    • In Code-Reviews würde ich eine solche Verwendung von int selbst markieren und stattdessen eine Wertklasse empfehlen, die die Einheit korrekt mittransportiert.
      Zum Beispiel Second(2) oder Millisecond(2000).
      Natürlich hängt das von den Fähigkeiten und Konventionen der jeweiligen Sprache ab.
  • xmobar verwendet ebenfalls Zehntelsekunden, allerdings an einer noch problematischeren Stelle: in der Konfiguration, die festlegt, wie oft die einzelnen Sektionen aktualisiert werden.
    Die Zahlen in der Beispielkonfiguration sind zu klein, als dass es Millisekunden sein könnten, sodass man vernünftigerweise Sekunden annimmt und Befehle am Ende zehnmal häufiger ausführt als beabsichtigt.
    Ich habe mehrfach unbeabsichtigte Lastspitzen gesehen, die aus diesem Problem entstanden sind.

  • Das wirkt nach ziemlich schlechtem Design.
    Allerdings war Punkt 1 das Ergebnis einer falschen Lektüre des Artikels; der „vorherige Wert“ hat in git nie existiert.

    1. Eine Änderung, die einen bestehenden Konfigurationswert stillschweigend mit einer anderen Bedeutung neu interpretiert, etwa 1=true in 1=0.100ms Bestätigungsverzögerung umzudeuten, sollte man fast immer vermeiden. Wenn es einen bestehenden Wert gegeben hätte, würde man ihn vielleicht entfernen wollen, aber der Name der Einstellung müsste dann ebenfalls geändert werden.
    2. Dass das Argument der Einstellung help.autocorrect eine Zeit ist und in einer für die meisten Nutzer unüblichen Einheit gemessen wird, ist einfach schlecht. Die Aktivierung sollte als Boolean erfolgen, und die Bestätigungszeit sollte sich über einen Dezimalwert einstellen lassen.
    • Zu Punkt 1 scheinst du die zeitliche Reihenfolge missverstanden zu haben.
      Diese Änderung geschah 2008 während des Code-Reviews des ursprünglichen Patches, der die Option als Boolean hinzufügen wollte, und zwar bevor sie in den Hauptbaum von git committet wurde.
    • Wenn man „Design“ sagt, denkt man an einen absichtlichen Plan in einem größeren Zusammenhang.
      Das hier ist weniger Design als eher ein organisch gewachsener Seitenast.
  • Ich halte das für ein gutes Beispiel für Feature Creep (creeping featurism).
    Im besten Fall bringt es unnötige Komplexität hinein; im schlechteren Fall sorgt es dafür, dass Leute, die sich darauf verlassen, weniger sorgfältig darauf achten, was sie eigentlich tun.

    • Genau so ist git. Auf einer eleganten Datenstruktur liegen mehrere Schichten unnötiger Müll, die sich über die Jahre angesammelt haben.
    • Ich verstehe nicht, warum man automatische Ausführung überhaupt zulassen möchte.
      Ist es wirklich so schwer, Pfeil nach oben zu drücken und den Fehler zu korrigieren? Etwas „ungefähr Passendes“ automatisch auszuführen ist ein Rezept dafür, unbeabsichtigte Dinge zu tun.
  • Der Fehler lag genau hier: Man hätte die bestehende Einstellung nicht für eine andere Bedeutung wiederverwenden, sondern eine neue Einstellung hinzufügen sollen
    help.autocorrect hätte in Ein/Aus aufgeteilt werden sollen, und help.autocorrect.milliseconds darin, wie lange gewartet wird
    Ähnliche Fehler gibt es auch in anderen Systemen. Bei MySQLs innodb_flush_log_at_trx_commit zum Beispiel bedeutet 0 deaktiviert, 1 aktiviert, und 2 wurde später mit einer speziellen Bedeutung hinzugefügt

    • Das eigentliche Problem ist eine typfreie Konfigurationssprache, die zu erraten versucht, was 1 bedeuten soll
      Jetzt bleibt 1 boolesch wahr, während andere Ganzzahlen zu Einheiten von 0,1 Sekunden gemacht werden; damit verstrickt man sich nur noch tiefer
      Das ist eine ähnlich fragwürdige Logik wie das berüchtigte no == false in YAML
    • Ich weiß nicht, wofür es am besten geeignet wäre, aber 0,1 Sekunden sind kein völlig unsinniger Wert
      Die schnellste dokumentierte zufällige Reaktionszeit liegt ungefähr bei 1,5 ds, und zufällig liegt auch die durchschnittliche Reaktionszeit von Gamern etwa dort; nicht-zufällige Reaktionen können aber deutlich schneller sein. Zum Beispiel, wenn man im Takt reagiert
      Wenn man so schnell sein möchte, geht das, und auch die Aufrufgeschwindigkeit sollte relativ stabil sein. Sie dürfte ungefähr im Bereich weniger Millisekunden liegen
  • Ich habe die Autokorrektur vor einem Jahr eingeschaltet und auf 3 Sekunden gesetzt, und mir sind zwei Dinge aufgefallen

    1. Sie unterscheidet nicht zwischen gefährlichen und sicheren Aktionen
    2. Sie verschmutzt die Shell-History mit falsch eingegebenen Befehlen
      Nachdem ich diesen Artikel gelesen habe, hatte ich nach einem Jahr genug Anlass, sie wieder auszuschalten
    • Für häufige Tippfehler ist es besser, einfach Aliasse (alias) anzulegen
      Natürlich „verschmutzen“ auch die die Shell-History
    • Zu Punkt 2: Der eigentliche Verursacher der Verschmutzung ist man selbst
      Das Gleiche gilt, wenn man in der History zurückgeht und den letzten falschen Befehl einfach wiederverwendet, nur weil er ja trotzdem funktioniert
  • Einheiten von 0,1 Sekunden sind wirklich eine seltsame Wahl
    Latenzen gibt man besser in Millisekunden oder Sekunden an; beides ist in der Informatik deutlich üblicher

    • Ich war kurz ziemlich verwirrt. Ich dachte, deciseconds sei eine Git-spezifische Einheit und bedeute so etwas wie decision-seconds, also „Sekunden, die man braucht, um eine Entscheidung zu treffen“ xD
      Zur Einordnung: Englisch ist nicht meine Muttersprache, aber ich komme aus einem zivilisierten Teil der Welt, der das metrische System verwendet
    • Für menschliche Reaktionszeiten ist die Einheit okay, aber sie ist unüblich
      Der Unterschied zwischen 0 und 1 Sekunde ist beim Warten auf etwas deutlich spürbar, aber der Unterschied zwischen n Millisekunden und n+1 Millisekunden ist zu fein, um nützlich zu sein
  • Reaktionszeiten hängen von der Art des Reizes ab; akustische Reize sind etwas schneller als visuelle, taktile noch etwas schneller, etwa 90–180 ms
    Wenn Git einem statt einer Fehlermeldung also eine verpasst, hätte man vielleicht gerade noch Zeit zu reagieren

    • Damit sich dieses Schlaggerät wirklich wie ein Treffer anfühlt, müsste es Trägheit aufbauen
      Reichen dafür 10 ms?
  • Beim Lesen dieses Artikels musste ich an Software-Archäologie und den Begriff „Programmierer-Archäologen“ denken
    Für Letzteres ist Vernor Vinge zu danken

    • Das ist wirklich ein Punkt, der mich stört. Hacker haben den Eindruck erweckt, dieses Buch habe das Konzept der „Software-Archäologie“ eingeführt, und ich freute mich sehr darauf, 『A Fire Upon The Deep』 zu lesen
      Aber das Konzept wird nur im Prolog kurz angedeutet und taucht danach überhaupt nicht mehr auf. Die Auswirkungen der Archäologie sind für die Handlung relevant, aber „Software-Archäologen“ waren keine erzählerisch bedeutsamen Figuren
      Ich fühlte mich geködert
    • Man sagt ja, die Gefahr der Software-Archäologie bestehe letztlich darin, dass man auf Koprolithen stößt
    • Ich werde das Gefühl nicht los, dass du mich gerade „alt“ nennst