Warum gibt es für meine Refs/Remotes/Origin keinen zu meisternden Ref?

Lesezeit: 8 Minuten

Während ich die innere Funktionsweise von Git erkundete, ging ich in das Verzeichnis refs/remotes/origin meines Git-Projekts und führte die Datei ls Befehl. Hier ist, was ich sehe.

$ ls
HEAD  sp2013dev

Dann rannte ich cat HEAD und hier ist, was gedruckt wurde.

$ cat HEAD
ref: refs/remotes/origin/master

Es gibt jedoch keine Datei oder kein Verzeichnis mit dem Namen master im Verzeichnis refs/remotes/origin. Dieses Verzeichnis enthält nur „HEAD“ und „sp2013dev“.

Übersehe ich hier etwas? Warum bezieht sich HEAD auf etwas (übrigens, ist ‘ref’ die korrekte Terminologie für dieses ‘etwas’?), das nicht existiert?

Warum gibt es fur meine RefsRemotesOrigin keinen zu meisternden Ref
Torek

Nur zur Betonung: Sie stochern im Inneren von Git herum; Sie haben ein Verzeichnis namens gefunden .git/refs/remotes/origin und es enthält zwei Dateien, HEAD und sp2013dev. Die Inhalte von .git/refs/remotes/origin/HEAD sind ref: refs/remotes/origin/master.

Eine Referenz, die aus der Literalzeichenfolge besteht ref: gefolgt von einem weiteren Referenznamen ist eine “symbolische” Referenz in Git-Begriffen. Es bedeutet “obwohl dies ein gültiger Name ist, wird der SHA-1, zu dem diese Referenz aufgelöst wird, durch Lesen einer anderen Referenz gefunden.” Aber wie Sie bemerken, gibt es keine Datei genannt master in dem .git/refs/remotes/origin Verzeichnis, Sie fragen sich also, wie das funktionieren kann.

Die Antwort ist, dass sich nicht alle Referenzen notwendigerweise in Dateien befinden. Verweise können “gepackt” sein und sind es auch. Derzeit befinden sich gepackte Referenzen in .git/packed-refs, bei der es sich um eine Nur-Text-Datei handelt. Ihr eigenes Git wird eine haben refs/remotes/origin/master gepaart mit einem SHA-1-Hash in Ihrem .git/packed-refs.

Hinweis: Ein Verweis kann sowohl in der packed-refs Datei und eine Datei in einem .git/refs Unterverzeichnis. In diesem Fall überschreibt die zweite Version die erste. Dies erlaubt git pack-refs (aufgerufen von git gc), um alle Refs zu packen und Refs dann nach Bedarf “entpacken” zu lassen, wenn sie aktualisiert werden. (Aber dies ist ein Implementierungsdetail, und Sie sollten es nicht tun davon ausgehen Das; in Skripten verwenden git update-ref und git symbolic-ref Verweise zu lesen und zu aktualisieren und diese Programme die Aktualisierungsregeln erzwingen zu lassen.)

Derzeit scheint es kein gepacktes Format für symbolische Referenzen zu geben, daher leben diese vorerst alle in “echten Dateien”.

Lange beiseite: wie das alles funktioniert (nur lesen, wenn ausreichend neugierig)

Wenn Sie ein anderes Repository klonen – oder, was das betrifft, jedes Mal, wenn Sie es ausführen git fetch oder git pushobwohl diese sich nicht damit befassen refs/remotes/origin/HEAD-es gibt zwei Repositorys beteiligt, wobei zwei Regelsätze von zwei verschiedenen Gits durchgesetzt werden, die diese beiden Repositorys steuern. Abgesehen vom Befehl git remote set-heades ist nur git clone das schafft die origin/HEAD in erster Linie, damit wir uns darauf konzentrieren können git clone selbst.

Da es zwei Repositories gibt, geben wir ihnen Namen. Wir können Ihr lokales Repository anrufen L und das Repository unter origindie Sie gerade klonen, Ö. Seit Ö ist ein Git-Repository, es hat sein eigenes HEAD. Dies HEAD ist normalerweise eine symbolische Referenz: HEAD -> master zum Beispiel. Welchen Zweig es auch immer nennt, es ist lokal Ö: es ist refs/heads/branchdie eine lokale Verzweigung ist Ö. Wenn Sie sich bei der Maschine anmelden, die das Repository hostet Öund sehen Sie sich ihre an .git/HEAD Datei, würde es enthalten ref: refs/heads/branch. Der Git an Ö setzt diese Regel durch, das HEAD nennt immer ein lokales (local-to-Ö das heißt) Zweig.

Jetzt arbeitet Ihr eigenes Git, das lokal auf Ihrem System ausgeführt wird, daran, ein Repository zu erstellen L. Dein Git an L erstellen will, auf Lein Remote-Tracking-Zweig, dessen vollständiger Name lautet refs/remotes/origin/HEAD. Dies wird ein symbolischer Verweis sein, und es wird darauf hinweisen refs/remotes/origin/branch. Aber es gibt zwei Komplikationen:

  1. Dein Git, weiter Lmüssen ihre Gits (on Ö) symbolisch HEAD. In unserem Fall sind es (ihre) refs/heads/branch.
  2. Dein Git, weiter Lmuss dann schaffen refs/remotes/origin/branch als Remote-Tracking-Zweig. (Ihr Git speichert dies in Ihrer .git/packed-refs Datei.) Ihr Git erstellt dann L‘S refs/remotes/origin/HEAD als symbolischer Hinweis auf refs/remotes/origin/branch.

An jedem dieser beiden Punkte kann etwas schief gehen. Schritt 2 schlägt fehl, wenn Sie verwenden git clone -b otherbranch --single-branch, zum Beispiel. Das sagst du deinem Git L sollte nicht haben refs/remotes/origin/branch überhaupt, aber nur refs/remotes/origin/otherbranch. Aber wenn Schritt 2 so fehlschlägt, erstellt Ihr Git einfach nichts refs/remotes/origin/HEAD überhaupt. Auf diese Weise müssen Sie nicht rein Lein refs/remotes/origin/HEAD zeigt auf den nicht existierenden Remote-Tracking-Zweig.

Schritt 1 „schlägt fehl“ (in gewisser Weise), wenn entweder Ihr Git, building Loder ihr Git, dient Ö zu Ihrem Git, ist zu alt. Es gibt ein definiertes Protokoll zum Nachschlagen von Referenznamen während dieser Internetverbindungs-“Telefonanrufe”, die Commits kopieren (git fetch, git push) und Branch- und Tag-Namen anzeigen (git ls-remote) und so weiter. Die clone Befehl verwendet das gleiche definierte Protokoll. Zu Beginn der Verbindung handeln Ihr Git und ihr Git die zu verwendenden Protokolloptionen aus. Ältere Gits haben keine Option zum Ausdrücken und Auflösen einer symbolischen Referenz. Wenn also Git die Option nicht unterstützt, Ö behauptet das nur Ö‘S HEAD ist eine bestimmte SHA-1-ID. Das Git, das den Klon erstellt L muss erraten welcher Zweig ist eigentlich HEAD an Ö. Dies geschieht durch Scannen durch die sich ausruhen der Zweignamen, für die es kommt Ö. Wenn Ö‘S HEAD ist 1234567und es gibt auch einen Zweig 1234567gut, das müssen ihre sein HEAD Punkte!

Das kann sein falsch, dh Ihr Git kann falsch raten. Aber wenn ja, fährt Ihr Git einfach mit der falschen Annahme fort und macht sich weiter Gedanken über Schritt 2.

Schritt 1 kann ganz anders fehlschlagen, wenn ihre (Ö‘S) HEAD ist abgelöst. In diesem Fall gibt es möglicherweise keine passende Verzweigung. Wenn ja, wird Ihr Git nicht falsch raten, es wird nur wissen, dass im Repository kein Zweig ausgecheckt ist Ö. Wenn sowohl Ihr Git als auch ihr Git nicht zu alt sind, wird Ihr Git die richtige Protokolloption aushandeln und Ihr Git wird sicher wissen, ob Ö hat einen abgetrennten HEAD, und wenn nicht, in welchem ​​Zweig ist er ausgecheckt Ö.

Es ist einfach, Schritt 2 absichtlich fehlschlagen zu lassen: Klonen Sie einfach ein Repository, dessen HEAD Sie wissen, bezieht sich auf einen bestimmten Zweig (wie z master) während Sie beide verwenden --single-branch und -b um Ihren Klon zu machen L vermeiden dieser Zweig. Es ist etwas schwieriger, Schritt 1 absichtlich fehlschlagen zu lassen, aber Sie können dies tun, indem Sie sich bei dem exportierenden System anmelden Ö und Ablösen ÖKOPF.

Wenn Sie dies jedoch tun, verwenden Sie – zurück auf Ihrem eigenen System – git clone zu machen Lfinden Sie einfach, dass Ihr Klon L hat Nein origin/HEAD. Dies behält die normalen Regeln bei, zu denen diese drei gehören (ich bin mir nicht sicher, ob es noch mehr gibt):

  1. Alle gewöhnlichen (nicht symbolischen) Referenzen enthalten eine gültige Hash-ID.
  2. Alle symbolischen Verweise (mit einer Ausnahme im Sonderfall, die unten beschrieben wird) enthalten den Namen eines vorhandenen Verweises.
  3. Die besondere Referenz HEADdas normalerweise (aber nicht immer) symbolisch ist, enthält nur einen Verweis auf a lokal Zweig, dh ein Name in der refs/heads/ Namensraum.

Die Ausnahme des Sonderfalls ist der spezielle Referenzname HEAD dürfen enthalten den Namen einer lokalen Niederlassung, die tatsächlich noch nicht existiert. Dies (verschiedentlich als “ungeborener Zweig” oder “verwaister Zweig” bezeichnet) ist wie master entsteht in einem neuen, leeren Repository: HEAD verweist auf master obwohl master existiert noch nicht. Ein Commit, das Sie in diesem Zustand vornehmen, bewirkt, dass der Zweig zu existieren beginnt und auf das gerade durchgeführte Commit zeigt; und das Commit hat gerade gemacht Nein parent, dh, ist ein Root-Commit.

Sie könnten denken, Sie könnten diese Regeln mit brechen git remote set-headaber tatsächlich lässt es Sie nicht:

Verwenden <branch> um die symbolische referenz zu setzen refs/remotes/<name>/HEAD
ausdrücklich. zB “git remote set-head origin master” setzt die symbolische Referenz refs/remotes/origin/HEAD zu
refs/remotes/origin/master. Das funktioniert nur, wenn
refs/remotes/origin/master ist bereits vorhanden; wenn nicht, muss es zuerst geholt werden.

(Hervorhebung von mir). Für mehr über git remote set-headsehen der git remote Dokumentation.

Sie kann Brechen Sie diese Regeln entweder mit direktem Zugriff auf die .git Verzeichnis oder mit git symbolic-ref. Offensichtlich, wenn Sie drinnen herumstöbern .gitdu kannst ziemlich gut durcheinander bringen, 🙂 das erfordert also Pflege. Die scharfen Kanten mit git symbolic-ref sind etwas überraschender, aber jetzt wissen Sie, dass Sie auch damit vorsichtig sein müssen.

  • Gibt es nicht eine viel einfachere Erklärung? Nämlich dass die geholt HEAD auf der origin Fernbedienung zeigt auf a Fernbedienung Filiale benannt master die das OP nicht geholt hat?

    – jpaugh

    7. Februar 2017 um 19:00 Uhr


  • @jpaugh: Nein – oder zumindest nicht normalerweise – weil der lokale HEAD auf nichts anderes als einen lokalen Zweignamen oder einen Commit zeigen darf. (Es ist möglich, dies zu brechen, indem Sie die Datei selbst schreiben, aber Git lässt Sie intern nicht auf einen Remote-Tracking-Branch gelangen: Sie erhalten einen abgetrennten HEAD, wobei HEAD stattdessen eine Roh-Hash-ID enthält.) Aber es ist ganz normal für ein Remote-Tracking HEAD ein symbolischer Hinweis auf ein Remote-Tracking sein origin/master während die remote-tracking origin/master ist eingepackt.

    – Torek

    7. Februar 2017 um 22:38 Uhr

  • Wir reden nicht über HEAD hier aber remotes/origin/HEAD. (Entschuldigung, dass ich Sie in einen alten Thread bringe.) Somit scheint der zweite Teil Ihres Kommentars meinen Verdacht zu bestätigen, nämlich dass die Fernbedienung HEAD zeigt auf einen Zweig, der noch nicht lokal abgerufen wurde, richtig?

    – jpaugh

    10. Februar 2017 um 20:57 Uhr


  • @jpaugh: Ich habe zwei lange Kommentare gelöscht und durch diesen ersetzt. Ich weiß, was du meinst, aber es ist falsch: siehe den neuen Abschnitt “Long aside”. Beachten Sie besonders “Schritt 2”: Ihr Git erstellt origin/HEADaber nur, wenn es auch den entsprechenden Remote-Tracking-Zweig erstellt.

    – Torek

    11. Februar 2017 um 1:51 Uhr


999140cookie-checkWarum gibt es für meine Refs/Remotes/Origin keinen zu meisternden Ref?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy