Ein Update von Oh My Zsh verlangt plötzlich Benutzername und Passwort für ein öffentliches Repository. Die Anmeldedaten sind nicht das Problem – die Verbindung ist es. Zwei Zeilen beweisen das.
Beim Update fragt Git nach Zugangsdaten für github.com. In Skripten und in CI, wo keine Eingabe möglich ist, sieht dasselbe Problem so aus:
fatal: could not read Username for 'https://github.com/': terminal prompts disabled\nfatal: expected flush after ref listing
Die zweite Zeile ist der eigentliche Hinweis: Die Ref-Kommunikation ist abgebrochen. Manchmal steht unmittelbar davor noch curl 16 Error in the HTTP2 framing layer.
Bevor man anfängt, Tokens zu erzeugen, lohnt sich dieser Vergleich. Erst der normale Aufruf:
git ls-remote github.com/ohmyzsh/ohmyzsh.git HEAD
– fragt nach Benutzername und Passwort. Und nun derselbe Aufruf, nur mit HTTP/1.1:
git -c http.version=HTTP/1.1 ls-remote github.com/ohmyzsh/ohmyzsh.git HEAD
9112b53fa8b5ab556c7c893aa8be8a247ac512a0 HEAD
Dieselbe URL, dieselben (nicht vorhandenen) Zugangsdaten, ein anderer Transport – und es funktioniert. Damit ist ausgeschlossen, dass es an der Authentifizierung liegt.
Zwei Dinge sprechen von vornherein dagegen, dass es ein Berechtigungsproblem ist: Das Repository ist öffentlich und braucht zum Lesen überhaupt keine Anmeldung. Und selbst wenn – GitHub nimmt seit August 2021 keine Kontopasswörter mehr für Git über HTTPS an, sondern nur noch Tokens. Ein eingegebenes Passwort kann also gar nicht funktionieren.
Was passiert: Der HTTP/2-Transport scheitert während der Ref-Kommunikation. Git kann einen abgebrochenen Stream nicht von einer abgelehnten Anfrage unterscheiden und landet anschließend im Pfad für Zugangsdaten. Die Passwortabfrage ist ein Folgesymptom, keine Ursache.
Das ist kein Einzelfall und keine Eigenheit einer alten Git-Version. Dieselbe Meldung wird aus GitHub Actions berichtet, ebenfalls bei öffentlichen Repositories, wo ohnehin keine Anmeldung nötig wäre. Auch aus dem curl-Umfeld gibt es ältere Fälle, in denen Klonvorgänge über HTTP/2 scheiterten und dieselbe Umstellung half.
Es ist also weniger ein Fehler bei GitHub als ein Problem im Zusammenspiel von Git, libcurl, HTTP/2 und der Gegenstelle. Betroffen war bei mir eine Umgebung mit Git 2.43 und curl 8.5 mit nghttp2 1.59 – Berichte mit deutlich neueren Versionen gibt es aber ebenfalls. Die Git-Version vorschnell als Ursache anzunehmen führt in die falsche Richtung.
Am besten nur für den Host, der es braucht – alles andere bleibt bei HTTP/2:
git config --global http.https://github.com/.version HTTP/1.1
Mit der Brechstange für alle Hosts:
git config --global http.version HTTP/1.1
Oder einmalig zum Ausprobieren, ohne etwas dauerhaft zu ändern:
git -c http.version=HTTP/1.1 pullDer HTTP/2-Pfad lässt sich auch ganz umgehen. Auf einem Server, auf dem ohnehin ein SSH-Schlüssel für GitHub liegt, ist das die angenehmere Variante – und für private Repositories spart sie den Umgang mit Tokens:
cd ~/.oh-my-zsh\ngit remote set-url origin git@github.com:ohmyzsh/ohmyzsh.git\ngit fetch
Ob der Schlüssel greift, beantwortet:
ssh -T git@github.com
Erwartete Antwort ist sinngemäß „Hi <username>! You’ve successfully authenticated, but GitHub does not provide shell access." Für ein öffentliches Repository braucht man SSH nicht – hier ist es ein sauberer Weg um das Problem herum.
Ein einmaliger Aufruf mit -c löst das Problem für genau diesen Befehl. Beim nächsten automatischen Update ist die Abfrage zurück, und die Suche beginnt von vorn. Ob die Einstellung wirklich gesetzt ist, beantwortet:
git config --get-regexp '^http\..*version'
Kommt dort keine Ausgabe, ist nichts gesetzt.
Und im Blick behalten sollte man, dass HTTP/1.1 eine Umgehung ist und keine Reparatur. Kommt die Störung aus dem Netz oder von einer Appliance dazwischen, kann HTTP/2 anderswo völlig problemlos laufen.