2014-01-10 5 views

Antwort

14

Der checkout Befehl unterscheidet zwei Fälle (eigentlich „viele“, aber lassen Sie uns mit nur den beiden :-) Start):

  • „Ich will ’ auf einem Zweig zu ‘ bekommen, hier ist ein Zweigname ": zB git checkout branch.
  • "Ich möchte eine bestimmte Revision betrachten, und aus jeder Zweig; Hier ist ein Zweig-Kennung, die kein Zweig-Name ist": z. B. git checkout 6240c5c.

(Ich persönlich denke, diese verschiedenen Befehlsnamen verwenden sollten, aber das ist nur meine Meinung. Auf der anderen Seite wäre es all die Verrücktheit unten beschrieben beseitigen.)

Nun lassen Sie uns sagen, dass Sie das wollen ehemalige. Das Schreiben ist am einfachsten, wenn Sie einfach den Zweignamen ohne den refs/heads/ Teil schreiben.

Wenn Sie letztere wollen, können Sie eine Überprüfung durch eine der Methoden in gitrevisions aufgelistet angeben, außer für jede Methode, die in „auf dem Zweig bekommen“ führt.

Aus welchem ​​Grund auch immer gewählt der Algorithmus hier-es in der manual page dokumentiert ist, unter <branch> -is dies: Wenn Sie einen Namen geschrieben haben, dass, wenn refs/heads/ es, Namen ein Zweig hinzufügen, wird git checkout Sie setzen "auf diesem Zweig". Wenn Sie @{-N} oder - angeben, wird die N -te ältere Verzweigung in der HEAD Reflog (mit - Bedeutung @{-1}) nachschlagen. Andernfalls wählt es die zweite Methode und gibt Ihnen den "abgetrennten HEAD". Dies gilt auch dann, wenn der Name in gitrevisions zur Vermeidung von Mehrdeutigkeit vorgeschlagen wird, d. H. heads/xyz, wenn es einen anderen xyz gibt. (Aber: Sie können --detach hinzufügen, um den Fall zu vermeiden, selbst wenn es sonst auf den Zweig kommt.)

Dies widerspricht auch den im gitrevisions-Dokument aufgelisteten Auflösungsregeln.Um dies zu demonstrieren (obwohl es schwer zu sehen ist), habe ich einen Tag und Zweig mit dem gleichen Namen, derp2:

$ git checkout derp2 
warning: refname 'derp2' is ambiguous. 
Previous HEAD position was ... 
Switched to branch 'derp2' 

Das brachte mich auf dem Zweig, anstatt lösen und gehe in der getaggt Revision.

$ git show derp2 
warning: refname 'derp2' is ambiguous. 
... 

Dies zeigte mir die getaggte Version, die Art und Weise wie gitrevisions es sagt.


Eine Randbemerkung: „auf einem Zweig immer“ wirklich bedeutet, „einen symbolischen Verweis auf einen Zweig Namen in die HEAD im git Verzeichnis mit dem Namen Datei setzen“. Die symbolische Referenz ist der Literaltext ref: (mit nachhängendem Leerzeichen), gefolgt von dem vollständigen Verzweigungsnamen, z. B. refs/heads/derp2. Es scheint irgendwie inkonsistent, dass git checkout fordert den Namen ohne den refs/heads/ Teil, um den ref: refs/heads/ Teil hinzuzufügen, aber das ist Git für Sie. :-) Es gibt vielleicht einen historischen Grund dafür: Ursprünglich war die HEAD Datei eine symbolische Verbindung zur Datei, die immer eine Datei war. In diesen Tagen, teilweise aufgrund von Windows und teilweise nur durch Code-Evolution, hat es diese literale ref: Zeichenkette, und Verweise können "gepackt" werden und daher sowieso nicht als separate Datei verfügbar sein.

Umgekehrt bedeutet ein "losgelöster HEAD" wirklich "eine rohe SHA-1 in die HEAD Datei einfügen". Abgesehen davon, dass git in dieser Datei einen numerischen Wert hat, verhält sich git genauso wie bei "auf einem Zweig": Das Hinzufügen eines neuen Commits funktioniert immer noch, wobei das übergeordnete Element des neuen Commits das aktuelle Commit ist. Zusammenführungen können auch weiterhin durchgeführt werden, wobei die Eltern des Zusammenführungs-Commits die aktuellen und zu verschmelzenden Commits sind. Die Datei HEAD wird bei jedem neuen Commit aktualisiert. Zu jedem Zeitpunkt können Sie eine neue Verzweigung oder Tag-Beschriftung erstellen, die auf die aktuelle Festschreibung verweist, damit die neue Kette von Festlegungen auch nach dem Ausschalten des "abgetrennten HEAD" gegen zukünftige Speicherbereinigung erhalten bleibt. oder Sie können einfach wegschalten und die neuen Commits, falls vorhanden, mit der üblichen Müllsammlung entfernen lassen. (Beachten Sie, dass die HEAD reflog dies seit einiger Zeit verhindern wird, 30 Tage Verzug, denke ich.)

[ Wenn Sie „auf einem Zweig“ sind, das gleiche Auto-Update passiert, es passiert einfach zu Der Zweig HEAD bezieht sich auf. Das heißt, wenn Sie auf Zweig sind B und Sie fügen ein neues Commit hinzu, HEAD sagt immer noch ref: refs/heads/B, aber jetzt die Commit-ID, die Sie mit git rev-parse B erhalten, ist das neue Commit, das Sie gerade hinzugefügt haben. So wachsen Verzweigungen: Neue Commits, die hinzugefügt werden, während "auf der Verzweigung" die Verzweigungsreferenz automatisch vorwärts bewegt. Wenn sich in diesem Status "Abgelöste HEAD" befinden, führen neue Commits dazu, dass HEAD automatisch weitergeht.

]

Für Vollständigkeit, hier ist eine Liste von anderen Dingen git checkout tun kann, dass ich in verschiedenen separaten Befehlen gesetzt haben könnte, wenn ich solche Kräfte habe:

  • Prüfung eine bestimmte Version eines -Pfad (s), über den Index zu schreiben: git checkout revspec -- path ...
  • eine Niederlassung erstellen: git checkout -b newbranch (plus Optionen für git branch)
  • erstellen Sie einen neuen Zweig, der, ob und wann Sie begehen ein auf sie, werden es tun ein Root-Commit sein: git checkout --orphan (dies bringt Sie auf eine Verzweigung, die noch nicht existiert, d. h. schreibt ref: refs/heads/branch-name in HEAD, erzeugt aber nicht die Verzweigung branch-name; dies ist auch, wie master ein ungeborener Zweig ist in einem neuen Repository)
  • erstellen oder neu erstellen eine Zusammenführung oder fusioniert Konflikt: git checkout -m ...
  • lösen einen Merge-Konflikt durch Kommissionierung eines oder die andere „Seite“ des merge: git checkout --ours , git checkout --theirs
  • interaktiv auswählen Patches zwischen Repository-Objekten und Arbeit Baum Dateien, ähnlich wie git add --patch: git checkout --patch
+0

Wow! Danke für die ausführliche Antwort. Du weißt, dass es eine gute Antwort ist, wenn du am Ende noch mehr Fragen hast ;-) Warum glaubt Git, dass die Angabe der Datei in 'refs/heads /' bedeutet, dass ich nicht "auf einen Ast" gehen will? Und außerdem, warum, wenn ich eine beliebige Datei mit einem SHA-1 darin anlege, macht git nicht dasselbe wie für die Dateien in 'refs/heads /'? Es scheint nur inkonsistent ... – darthbith

+2

Eine Verzweigung ist eine lokale Commit-Referenz, die 'git commit' aktualisiert, wenn' HEAD' daran angehängt ist, das ist alles. Zweige leben in 'refs/heads'. 'git checkout' fügt nur 'HEAD' hinzu, aber das will man nicht immer tun. Ob die Schreibweise 'refs/heads/master' behandelt werden soll, sollte wie eine (nicht-verzweigte) Checkbox mit beliebigem Commit behandelt werden, denn wenn Sie die Verzweigungs-Checkouts hätten, hätten Sie gerade' master' gesagt oder sollten wie eine Verzweigung behandelt werden Checkout, weil Sie, wenn Sie einen Non-Branch-Checkout wollten, sagten "Master^0" ist ein Urteilsspruch, ich denke, es gibt gute Argumente in beide Richtungen. – jthill

+1

Ich stimme mit Jthill überein. Manche Dinge schreien wirklich nach "Abhebung", andere schreien nach "Abzweigung", und einige, es ist nur eine Art willkürliche Pause, die jemand einlegt: "A bedeutet auf dem Zweig, B bedeutet Abtrennen vom Zweig". Wenn dies verschiedene Befehle wären ("git switchtobranch", "git detachcheckout" oder was auch immer), müssten Sie nicht willkürlich sein, Sie würden es entweder tun, weil es möglich ist, oder ablehnen, weil es nicht möglich ist. – torek

2

Sie suchen keinen Zweig ab; Sie checken nur ein Commit, das zufällig der Leiter einer Filiale ist. Zweige sind unidirektionale Zeiger: Bei einer Verzweigung können Sie das genaue Commit bestimmen, das der Kopf dieses Zweigs ist, aber Sie können kein beliebiges Commit verwenden und bestimmen, in welchem ​​Zweig es sich gerade befindet. Wenn Sie also ein neues Commit durchführen würden, würde Git nicht wissen, welche Verzweigung gegebenenfalls aktualisiert werden soll.

+0

So explizit Kasse zu sagen, eine Datei zu verwenden (durch den Weg zu geben) schaut in die Datei für einen SHA, und wenn vorhanden, überprüft, dass SHA? Das funktioniert nicht, wenn ich eine Datei mit einem Hash darin erstelle, also was ist das Besondere an den Dateien in 'refs/heads'? – darthbith

+1

Ich glaube nicht, dass dies die Frage beantwortet, warum die Befehlszeile "git checkout foo" analysiert, wenn sie einen Zweig überprüft und "gitch checkout refs/heads/foo" überprüft, wie die Verzweigung 'foo' aussieht zu. –

+0

Weil symbolische Commitches nützlich sind. Ich möchte in der Lage sein, den Kopf einer Verzweigung im losgelösten Modus auszugeben, und so stellen sie eine Syntax zur Verfügung, um dies zu tun. Warum sollten Sie wollen, dass die beiden Syntaxen dasselbe tun? Scheint überflüssig. – BnWasteland

Verwandte Themen