Verwirrende Git-Terminologie
(jvns.ca)- Selbst wenn man Git lange benutzt, gibt es viele überlappende und wiederverwendete Begriffe, sodass es schwer ist, das tatsächliche Verhalten allein durch das Auswendiglernen von Befehlen vorherzusagen
- Dieselben Wörter und Symbole wie
HEAD,heads, detached HEAD,ours/theirs,../...ändern je nach Kontext ihre Bedeutung index,stagedundcachedhängen alle mit.git/indexzusammen, aberreset,revertundrestorehaben trotz ähnlicher Namen unterschiedliche Auswirkungen auf Commit-Historie, Working Tree und Branch-Pointer- Dass
maineinen Remote trackt, ist etwas anderes als ein Remote-Tracking-Branch wieorigin/main, undcheckoutvereint Branch-Wechsel und Dateiwiederherstellung in einem einzigen Befehl - Um Git zu verstehen, muss man neben einzelnen Befehlen auch das interne Modell betrachten, in dem Branches, Referenzen, Commits, Index und Remote-Tracking-Status zusammenwirken
HEAD, Branches, detached HEAD
- In Git bezeichnet heads die Branches; intern werden Branches im Verzeichnis
.git/refs/headsgespeichert- Das offizielle Git-Glossar unterscheidet zwischen branch als allen Commits darüber und head als dem neuesten Commit, man kann es aber auch als zwei Perspektiven auf dasselbe Objekt sehen
HEADzeigt auf den aktuellen Branch und wird in.git/HEADgespeichert- Schon die Formulierung „
headist ein Branch undHEADist der aktuelle Branch“ zeigt gut, wie verwirrend die Git-Terminologie ist
- Schon die Formulierung „
- Der detached HEAD state ist ein Zustand, in dem
HEADnicht auf einen Branch, sondern direkt auf eine Commit-ID zeigt- Wenn man einen Tag auscheckt, kann man in einen detached HEAD geraten, weil ein Tag kein Branch ist
- In diesem Zustand funktioniert
git pullnicht, undgit pushebenfalls nur auf besondere Weise git commit,git merge,git rebaseundgit cherry-picksind möglich, aber neue Commits sind mit keinem Branch verbunden und können dadurch schwer wiederzufinden sein- Man verlässt den detached-HEAD-Zustand, indem man einen neuen Branch erstellt oder zu einem bestehenden Branch wechselt
ours und theirs in merge und rebase
- Bei der Konfliktauflösung wählt
git checkout --ours file.txtdie Datei von „ours“, aber der Bezugspunkt ist bei merge und rebase unterschiedlich - Bei merge ist der aktuelle Branch
ours, der hereingemergte Branch isttheirs- Beispiel: Wenn man
git checkout merge-into-oursund danachgit merge from-theirsausführt, ist der aktuelle Branchours
- Beispiel: Wenn man
- Bei rebase ist der aktuelle Branch
theirs, der Ziel-Branch des rebase istours- Beispiel: Wenn man
git checkout theirsund danachgit rebase oursausführt, wird der Ziel-Branch zuours
- Beispiel: Wenn man
- Dieser Unterschied hängt damit zusammen, dass
git rebase mainintern die Commits des aktuellen Branches wiederholt in eine Kopie desmain-Branches hineinmerged- Ein passendes Beispiel findet sich in einem Shell-Skript, das
git rebasemitgit mergeimplementiert
- Ein passendes Beispiel findet sich in einem Shell-Skript, das
- ourstheirs erklärt die Begriffe
oursundtheirskurz- Auch in VSCode können „current change“ und „incoming change“ auf ähnliche Weise verwirren
Remote-Statusmeldungen und fast-forward
Your branch is up to date with 'origin/main'bedeutet nicht, dass das aktuellemainauf dem neuesten Stand des Remote ist- Es bedeutet, dass der lokale Branch mit
origin/mainübereinstimmt, wie es beim letztengit fetchodergit pullgespeichert wurde - Wenn der letzte fetch vor 5 Tagen war, ist der Stand also nur „nach dem Stand von vor 5 Tagen“ aktuell
- Es bedeutet, dass der lokale Branch mit
- Git speichert Informationen über den Zeitpunkt des letzten fetch im reflog, aber in der Statusmeldung wird die Zeit „bezogen auf den letzten fetch“ nicht angezeigt
can be fast-forwardedbedeutet, dass der Remote-Branch weiter vorne liegt als der lokale Branch und lokal keine zusätzlichen Commits existieren, sodass nur der Pointer nach vorn verschoben werden kann- Beispiel: Wenn
mainA-B-Cist undorigin/mainA-B-C-D-E, dann sind nachgit pullbeideA-B-C-D-E - In diesem Fall kann es keinen Merge-Konflikt geben
- Beispiel: Wenn
- Wenn fast-forward nicht möglich ist, sind beide Branches voneinander abgewichen
- Beispiel: Wenn
maineinen CommitXhat, denorigin/mainnicht hat, undorigin/maindie CommitsDundEhat, diemainnicht hat, dann ist fast-forward unmöglich - In diesem Fall zeigt Git an, dass die beiden Branches diverged sind und jeweils eine unterschiedliche Anzahl eigener Commits haben
- Beispiel: Wenn
Syntax zur Commit-Auswahl: ^, ~, .., ...
HEAD^undHEAD~zeigen beide auf den einen vorherigen CommitHEAD^^^,HEAD~~~undHEAD~3zeigen alle auf den Commit drei Schritte zurück
- Bei einem Merge-Commit mit mehreren Elternteilen ändert sich die Bedeutung von
HEAD^2undHEAD^3HEAD^ist der erste Eltern-CommitHEAD^2ist der zweite Eltern-CommitHEAD^3ist der dritte Eltern-CommitHEAD~3bedeutet der Eltern-Commit des Eltern-Commits des Eltern-Commits und ist daher nicht dasselbe wieHEAD^3
git log main..testundgit log main...testverhalten sich ebenfalls unterschiedlichmain..testzeigt die Commits, die nur intestvorhanden sindtest..mainzeigt die Commits, die nur inmainvorhanden sindmain...testzeigt die Commits, die jeweils nur auf einer Seite vorhanden sind
- In
git diffwerden..und...anders interpretiert als ingit loggit diff test..mainvergleicht unter Einbeziehung sowohl der Änderungen auftestals auch aufmaingit diff test...mainvergleicht den gemeinsamen Vorfahren mit dem Ende vonmainund zeigt nur einen einseitigen diff
- Weitere Informationen zur Verwirrung rund um die Punktnotation gibt es auch in pain in dots
reference, refspec, tree-ish
- In Git wird reference in mehreren Bedeutungen verwendet
- Branches und Tags wie
mainoderv0.2 HEAD, das auf den aktuellen Branch zeigt- Ausdrücke wie
HEAD^^^, die zu einer Commit-ID aufgelöst werden
- Branches und Tags wie
- Git-Dokumentation nennt Ausdrücke wie
HEAD^^^streng genommen „revision parameters“, im Alltag können sie aber wie Referenzen behandelt werden - Eine symbolic reference ist eine Referenz, die auf eine andere Referenz zeigt, wie etwa
HEADHEADist ein zentrales Konzept, das das Verhalten der Git-Kernbefehle stark beeinflusst
- Die Remote-Konfiguration in
.git/configenthält refspecs- Beispiel:
+refs/heads/main:refs/remotes/origin/main - Oft verwendet man einfach den Wert, den
git cloneodergit remote addstandardmäßig anlegt
- Beispiel:
tree-ishbezeichnet ingit checkout THING .alles, wasTHINGsein kann- eine Commit-ID
- eine Commit-Referenz wie
main,HEAD^^oderv0.3.2 - ein Unterverzeichnis innerhalb eines Commits wie
main:./docs - In der Praxis reicht oft die Faustregel „ein Commit oder eine Commit-Referenz“
index, staged, cached
index,stagedundcachedhängen alle mit.git/indexzusammen.git/indexist die Datei, die verwendet wird, wenn Änderungen mitgit addgestaged werden
- Verschiedene Ausdrücke für dasselbe Objekt sind über mehrere Befehle verstreut
git diff --cachedgit rm --cachedgit diff --staged.git/index
- Allerdings haben die Flags
--indexund--cachednicht immer dieselbe Bedeutung- Ein Beitrag des Git-Lead-Maintainers Junio Hamano erklärt die Unterschiede im Detail
- Aus Performance-Gründen listet der Index auch untracked files auf, aber normalerweise versteht man die staging area nicht so, dass sie untracked files einschließt
reset, revert, restore
reset,revertundrestoreklingen ähnlich, betreffen in Git aber unterschiedliche Zielegit revert COMMITerstellt auf dem aktuellen Branch einen neuen Commit, der die umgekehrte Änderung vonCOMMITausführt- Wenn
COMMITdrei Zeilen hinzugefügt hat, löscht der neue Commit diese drei Zeilen
- Wenn
git reset --hard COMMITsetzt den aktuellen Branch gewaltsam auf den Stand vonCOMMITzurück- Das ist ein sehr gefährlicher Vorgang, weil dadurch alle neuen Änderungen nach
COMMITgelöscht werden
- Das ist ein sehr gefährlicher Vorgang, weil dadurch alle neuen Änderungen nach
git restore --source=COMMIT PATHstellt die Dateien inPATHauf den Zustand zum Zeitpunkt vonCOMMITzurück- Andere Dateien oder die Commit-Historie werden nicht verändert
git reset --hardundgit restore .verhalten sich allein verwendet oft ähnlich, abergit reset --hard COMMITundgit restore --source COMMIT .verhalten sich völlig unterschiedlich
track, Remote-Tracking-Branch, untracked files
- Git verwendet das Wort track auf drei verschiedene Arten
Untracked files:ingit statusmeint Dateien, die Git nicht verwaltet und die nicht in einem Commit enthalten sind- Ein Remote-Tracking-Branch wie
origin/mainist eine lokale Referenz, die die Commit-ID enthält, auf diemainim Remoteoriginbeim letztengit pullodergit fetchgezeigt hat - Ein lokaler Branch kann so konfiguriert sein, dass er einen Remote-Branch trackt, wie in „branch foo set up to track remote branch bar from origin“
- Zu sagen,
mainsei ein Branch, der einen Remote trackt, ist etwas anderes als zu sagen,origin/mainsei ein Remote-Tracking-Branch mainist ein echter Branch, daher kann man darauf Commits erstellen und Merges durchführen- Wenn in
.git/configeingestellt ist, dass er den Remote-maintrackt, kann mangit pullundgit pushbequemer verwenden
- Wenn in
origin/mainist trotz des Namens „Remote-Tracking-Branch“ kein normaler Branch- Man kann nicht direkt darauf committen
- Er wird nur aktualisiert, wenn der neueste Stand von
mainaus dem Remote mitgit pullodergit fetchgeholt wird
checkout, reflog, merge/rebase/cherry-pick
git checkoutvereint zwei unterschiedliche Aufgaben in einem Befehlgit checkout BRANCHwechselt den Branchgit checkout file.txtverwirft unstaged Änderungen anfile.txt
- Um diese Verwirrung zu verringern, hat Git die Funktionen in
git switchundgit restoreaufgeteilt, aber das bestehendecheckoutkann weiterhin verwendet werden reflogsteht für reference log und ist das Protokoll darüber, worauf eine Referenz in der Vergangenheit gezeigt hat- reference ist ein Oberbegriff, der Branches, Tags und
HEADumfasst - reflog kann helfen, sich aus sehr schlechten Git-Situationen zu retten, etwa wenn ein wichtiger Branch versehentlich gelöscht wurde
- reference ist ein Oberbegriff, der Branches, Tags und
- merge, rebase und cherry-pick unterscheiden sich darin, wie sie Commits zusammenführen
- merge erzeugt einen neuen Commit, der zwei Branches zusammenführt
- rebase kopiert die Commits des aktuellen Branches nacheinander auf den Ziel-Branch
- cherry-pick ist ähnlich wie rebase, aber die Syntax ist anders und der Commit wird auf den aktuellen Branch kopiert
git rebase --onto main otherbranch mybranchkann verwendet werden, um nur einen Teil der Commits vonmybranchaufmainzu verschieben- In einer Beispielstruktur könnte man damit nur
FundGaufmainrebasen - Die Syntax mit drei Branch-Namen ist schwer zu merken
- In einer Beispielstruktur könnte man damit nur
commit und andere verwirrende Begriffe
commitwird in Git sowohl als Verb als auch als Substantiv verwendet- Verb: „committe häufig“
- Substantiv: der neueste Commit auf
main
- Ein Git-Commit kann auf drei Arten betrachtet werden
- als Snapshot des aktuellen Zustands aller Dateien
- als diff zum Eltern-Commit
- als History aller vorherigen Commits
- Verschiedene Befehle behandeln einen Commit unterschiedlich
git showbehandelt einen Commit wie einen diffgit logbehandelt einen Commit wie Historygit restorebehandelt einen Commit wie einen Snapshot
- Auch
blob,tree,origin,upstream,downstream, die Beziehung zwischenfetchundpull, sowiestash,worktree,subtreeundsubmodulegehören zu den verwirrenden Git-Begriffen - Unter den GitHub-Begriffen gelten „pull request“, „squash and merge“ und „rebase and merge“ als typische verwirrende Beispiele
Drei wiederkehrende Achsen der Verwirrung
- Besonders verwirrende Git-Terminologie lässt sich auf drei Punkte verdichten
headist ein Branch,HEADist der aktuelle Branch- „Remote-Tracking-Branch“ und „Branch, der einen Remote trackt“ sind verschiedene Dinge
index,stagedundcachedbezeichnen alle dasselbe Objekt
- Der Text the most confusing git terminology aus dem Jahr 2012 behandelt auch, wie Git-Begriffe mit Begriffen aus CVS und Subversion zusammenhängen
- Die Verwirrung in der Git-Terminologie taucht nicht nur bei einigen Spezialfunktionen auf, sondern wiederholt sich in den zentralen Funktionen insgesamt
- Besonders beim Thema Branches wird „tracking“ auf mehrere Arten verwendet, sodass man die Unterschiede beim ersten Lesen leicht übersieht
- Einige Erklärungen enthalten seltene Ecken von Git, daher bleibt der Hinweis, dass sich Fehler eingeschlichen haben könnten
1 Kommentare
Hacker-News-Kommentare
Branch-Namen,
HEADund Tags sind allesamt Pointer.HEADzeigt auf den Commit, den man gerade betrachtet, und ein Branch-Name wiemy-featurezeigt auf den neuesten Commit dieses Branches. Wenn man aufmaingit checkout -b my-featureausführt, zeigenmain,my-featureundHEADalle auf den neuesten Commit vonmainJedes Mal, wenn man auf
my-branchcommittet, wandernHEADundmy-branchweiter und zeigen auf den neuen Commit. detached HEAD bedeutet, dass kein Branch auf den Commit zeigt, auf denHEADzeigt. Der Unterschied zwischen Tags und Branches ist, dass Tags auf einen bestimmten Commit zeigen und sich nicht bewegenEin weiterer Punkt, der mich verwirrt hat, war, dass viele Befehle deshalb inkonsistent wirken, weil Git Standardargumente annimmt.
git checkout file.txtist dasselbe wiegit checkout HEAD -- file.txt, und wenn man aufmy-branchist, istgit rebase maindasselbe wiegit rebase main my-branch. Die zweite Form kann man allerdings auch von einem anderen Branch aus ausführenUnd schließlich ist der Befehl, der einen aus jedem seltsamen Zustand rettet, wenn alles verknotet ist,
git reflog. Er zeigt alle Commits, auf dieHEADgezeigt hat. Trotzdem ist es schön zu sehen, dass Git diese Verwirrung anerkennt und Befehle mit weniger überraschenden und einfacheren Interfaces entwickeltreflogWas viele Git-Nutzer außerdem nicht auf dem Schirm haben: Auch die vom Remote geholten Branch- oder Tag-Refs sind ganz normale Refs und können überall referenziert werden, wo man einen Ref-Namen verwenden kann
Wenn man zum Beispiel sagen will: „Egal, was in diesem Branch ist, kein Fast-Forward, kein Merge, kein Rebase, überschreibe einfach meinen lokalen Branch mit dem Inhalt des Remote“, dann geht das so:
git checkout foo,git reset --hard origin/fooHEAD-Pointer nicht direkt auf einen Commit, sondern normalerweise auf einen Branch-Pointer wiemy-branch, und dieser Branch-Pointer zeigt dann auf den Commit. Der detached-HEAD-Zustand ist die AusnahmeWenn man auf
my-branchcommittet, bewegen sich nichtHEADundmy-branchbeide zum neuen Commit;HEADzeigt weiterhin auf den Pointermy-branch, und nurmy-branchwird weiterbewegt, sodass er auf den neuen Commit zeigt. Wenn manHEADfolgt und übermy-branchweiter zum Commit geht, landet man natürlich beim neuen CommitDetached HEAD bedeutet, dass
HEADdirekt auf den Commit zeigt statt auf einen Branch-Pointer. Auch in einem detached-HEAD-Zustand könnenHEADund ein Branch-Pointer beide auf den neuesten Commit zeigen. Ingit log --decoratewird der neueste Commit dann statt des üblichen(HEAD -> my-branch)als(HEAD, my-branch)angezeigtAnnotated Tags dagegen können eine Nachricht, einen Zeitstempel, SHA usw. enthalten. Das sind richtige Git-Objekte und sie verhalten sich Commit-Objekten ziemlich ähnlich, verweisen aber meist weiterhin auf ein anderes Git-Objekt, in der Regel einen Commit
git rev-parse HEADauszuführen und diesen String an einen sicheren Ort zu kopierenDas gibt einem zusätzlich die Sicherheit, den Zustand, von dem man sicher weiß, dass er in Ordnung war, exakt markiert zu haben. Man kann dann meist zum letzten bekannten guten Zustand zurückkehren statt zu irgendeinem Punkt, an dem man schon ein paar Schritte tief im Chaos war. Vorausgesetzt natürlich, man hat nichts wie
git gcodergit filter-branchunvorsichtig benutztEs klingt wie ein Witz, ist aber keiner: Die Aussage, man brauche für Git wirklich einen Informatikabschluss, ist nicht ganz falsch. Ich stimme zu, dass Gits Standardargumente eine sehr inkonsistente User Experience erzeugen
git checkout .,git reset --hard/softundgit cleanupsehen alle extrem ähnlich aus, sind in Wirklichkeit aber sehr verschieden. Trotzdem ist Git immer noch besser als Perforce oder SVN. Früher mochte ich Mercurial etwas lieber; ob das heute noch so wäre, weiß ich nichtgit reflogist der König und zeigt die WahrheitIch meine mich zu erinnern, etwas von Linus Torvalds gelesen zu haben, in dem er überrascht war, dass Leute Git direkt benutzten, statt eine freundlichere Schicht darüberzulegen. Wenn die Branche zu Selbstreflexion fähig wäre, hätte sie eingeräumt, dass die Entscheidung für Git ein Fehler war, und wäre zu einem anderen Versionsverwaltungssystem gewechselt. Stattdessen verschwenden wir gewaltige Mengen an Zeit mit einem Werkzeug, das im Kern nur Text speichert
Natürlich kann es besser werden. Trotzdem überrascht mich der Hass, den Git abbekommt, immer wieder. Git ist ein großartiges Werkzeug und Word oder Google Docs, die für Nichtentwickler gemacht wurden, weit voraus
Vielleicht liegt das auch daran, dass ich alt genug bin, mich an die Zeit zu erinnern, als Subversion König war
Jede Woche sehe ich Kollegen, die von Git verwirrt sind, ich sehe Hilfegesuche im Netz, und wieder einmal sehe ich einen Beitrag wie diesen hier, der versucht, etwas neu zu erklären, das einfach sein sollte
Ich kann mich nicht daran erinnern, jemals Leute gesehen zu haben, die beim Coden stundenlang damit verschwendet haben, ihr eigenes Chaos in SVN, TFVC, Perforce usw. rückgängig zu machen
Werkzeuge sollen das Leben einfacher machen. Wenn sie das nicht tun, sind sie die investierte Zeit nicht wert
Ich wünschte, es gäbe noch immer diese Vielfalt. Die Git-Monokultur bedeutet auch, dass man, um Git zu ersetzen, zuerst Git neu implementieren muss. Deshalb werden wir daran fast für immer gebunden sein, wie an ASCII oder die Scroll-Lock-Taste.
Die zentrale Sorge ist, dass GitHub so gut ist, dass wir an Git gebunden bleiben, solange GitHub Git nicht von der Zeichenverwaltungs-Engine trennt und keine anderen Engines zulässt.
https://trolololo.xyz/github
https://news.ycombinator.com/item?id=38098109
Begriffe wie leaky abstraction.
cache, und das war der informatischste Begriff.Später hat Junio es anscheinend in das stärker auf verteilte Versionsverwaltungssysteme zugeschnittene
indexgeändert, und die meisten Nutzer nannten es einfach staging area. Heute ist diese Entwicklung der Begriffe wie ein Fossil in Git-UI und Interna erhalten.pull.origin/masterbedeutet nicht master auf origin, sondern den Commit, auf den das zuletzt bekannteorigin/mastergezeigt hat. Dieser Wert wird beifetchaktualisiert, undpullmacht automatisch einfetch.Wenn du
ls -l .git/refs/remotes/origin/masteransiehst, merkst du, dassorigin/masternur eine Datei auf deinem System ist. Du kannst sogar sehen, wann sie geändert wurde. Sie wird nicht auf magische Weise aktualisiert.Wenn du
git fetch originausführst und es Änderungen gibt, ändern sich Zeitstempel und Inhalt. Mitcat .git/refs/remotes/origin/masterkannst du das prüfen.Die Grundlagen von Git sind sehr einfach, und die zentralen Datenstrukturen sowie einige Operationen könnte man in einem Tag implementieren. Das zu wissen ist wirklich wertvoll. Irgendwie hat Git es geschafft, auf einem ziemlich einfachen Kern eine sehr komplexe Benutzeroberfläche aufzubauen.
master-Branch einfach. Normalerweise kann ich ohnehin nicht nachmasterpushen oder will dort sowieso nicht direkt arbeiten. Dann gibt es auch keinen Grund, einen lokal änderbarenmaster-Branch zu behalten.Also muss ich nur
origin/masteraktualisieren, und dafür reichtfetch.git fetch && git pullIch warte auf den Tag, an dem ich in drei Jahren in Rente gehe und mit diesem kaputten Müll endlich nichts mehr zu tun habe.
git statusparst, und der Schalter--porcelainhilft wirklich. Er erzeugt eine kompaktere Ausgabe, die sich leichter programmatisch parsen lässt.Dadurch wurde ich neugierig, bei wie vielen Befehlen es noch besser maschinenlesbare Ausgaben gibt, und landete schließlich auf der git-scm-Seite „Git Internals - Plumbing and Porcelain“. Kurz gesagt wurde Git anfangs eher als Werkzeugsammlung zum Umgang mit Versionsverwaltung geschrieben als als ausgefeiltes Versionsverwaltungssystem.
Viele Leute, die Git früh benutzt haben, lernten Versionsverwaltungsaufgaben mit diesen Low-Level-Befehlen und gaben diesen Workflow an andere weiter. Das ist die plumbing-Schicht. Später bekam Git eine stärker polierte Schicht, und die nennt sich porcelain.
Ich weiß noch nicht ganz, welche Befehle zu welcher Schicht gehören, aber es hat mir geholfen, die in den letzten Jahren empfohlenen neuen Workflows besser zu verstehen. Es hilft mir auch, fundierter zu entscheiden, wenn ich meinen eigenen Workflow ändere.
https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Po...
Leider wurde dieses UI später fest einkompiliert, um es schneller zu machen, aber nicht verbessert.
Rückblickend war ich am Anfang sicher extrem verwirrt, aber ich glaube, ich habe so getan, als wäre das nicht so, um cool zu wirken.
https://news.ycombinator.com/item?id=28143078
„Your branch is up to date with ‘origin/main’“ ist tatsächlich etwas irreführend. Man kann es so verstehen, dass der Branch
mainaktuell ist, aber in Wirklichkeit ist das nicht so.Allerdings muss man hier nicht zu sehr auf „streng genommen“ pochen. Gilt hier nicht das Zwei-Generäle-Problem? Wenn man es wirklich penibel betrachtet, kann man nicht wissen, ob es genau in diesem Moment „aktuell“ ist. Auch wenn man vor
statuseinfetchmacht, gilt dasselbe.Was wäre dann eine vernünftige Erwartung? Etwa, dass der Ref in der Objektdatenbank auf meinem Computer mit dem Ref in einer weit entfernten anderen Objektdatenbank übereinstimmt, und zwar so, wie ich es zuletzt überprüft habe.
Ein einfacher Aufruf von
statuskann nicht jedes Mal ein Netzwerk-fetchdurchführen oder die Grundprinzipien des gerade verwendeten Werkzeugs in Erinnerung rufen. Ich persönlich sehe das so. Überraschenderweise meinen jedoch viele Kommentare unter der StackOverflow-Antwort, dass genau diese beiden Dinge nötig seien.Eine Formulierung wie „is up to date with the origin’s main as of your last fetch 5 days ago“ wäre etwas vernünftiger. Sie teilt nur mit, wie lange der letzte
fetchher ist.[1] https://stackoverflow.com/questions/27828404/why-does-git-st...
Noch etwas: Ich dachte,
ORIG_HEADhätte wieFETCH_HEADmit dem „Head von origin“ zu tun. Aber das ist nicht so. Dieser „pseudoref“ scheint als Sicherungspunkt vor komplexeren Umschreibungen wie Rebase verwendet zu werden und wurde implementiert, bevor es Reflogs gab. Vermutlich bedeutet es „original head“.„Your branch is up to date with ‘origin/main’“ ist technisch korrekt, aber der Ausdruck up to date impliziert beim flüchtigen Lesen ungefähr zwei Dinge: dass
maingleichorigin/mainist und dass auchorigin/mainaktuell ist, also während des Befehls aktualisiert wurde oder automatisch auf dem neuesten Stand gehalten wird und die letzte Synchronisierung erfolgreich war.Das ist kein maschinenlesbares Signal, das für genau einen CPU-Zyklus wahr sein muss, sondern eine für Nutzer sichtbare Statusmeldung. Auch ohne Netzwerktheorie ist diese Interpretation vernünftig.
„Up to date“ bedeutet eher, zeitlich aufgeholt zu haben, nicht räumlich. Die Position eines lokalen Branches ist eher räumlich im Sinn von „Auf welchen Punkt zeigt dieser Branch?“, während der Zustand eines Remote-Refs eher zeitlich ist im Sinn von „Wann habe ich diesen Remote-Ref zuletzt aktualisiert?“. Natürlich ist das sehr subjektiv, und beides kann in beide Richtungen verstanden werden.
Eine bessere Formulierung könnte etwas sein wie „Your branch matches origin/main“, „Your branch’s head is the same as origin/main“ oder „Your branch is pointing to the same commit as origin/main“. Das wäre ein Kompromiss zwischen Klarheit und Ausführlichkeit. Dazu könnte man wie vom Autor vorgeschlagen in Klammern „remote ref last updated 5 days ago“ anhängen.
status-Aufruf ein Netzwerk-fetchmachen würde. Meiner Meinung nach sollten Netzwerkoperationen explizit und nicht implizit sein. Wenn ichgit statusausführe, möchte ich den Zustand meines Repositories im Dateisystem kennen.Wenn ich wissen will, was sich auf einem anderen Remote tut, kann ich selbst
fetchausführen und dann vergleichen.status-Befehls aktuell sind. Zwischen dem Ermitteln der Informationen und ihrer Ausgabe im Terminal kann es Race Conditions geben, aber das ist nur ein sehr kleines Zeitfenster.Im Großen und Ganzen bedeutet das, dass man
fetchwill. Das Zwei-Generäle-Problem gilt nur für die Remote-Seite. Das Remote kann bei Bedarf eine Weile weiter erneut senden, wenn es keine Bestätigung erhält, dass der Client die Daten bekommen hat. Das ist nicht das Problem des Clients.Wenn der Client die Daten nicht vom Server erhalten kann, wäre das korrekte Verhalten wohl, stehen zu bleiben und nach einem Timeout einen Fehler auszugeben; vermutlich macht
fetchdas bereits so.Dieses Tool wird oft geteilt und passt auch hier sehr gut. Es visualisiert das interne Modell von Git und die Auswirkungen verschiedener Befehle.
https://learngitbranching.js.org/
Ich habe in 10 Minuten mit diesem Tool mehr gelernt als in ungefähr den 10 Jahren Git-Erfahrung davor. Sehr empfehlenswert.
„Pull“ ist die Aktion, Remote-Änderungen in ein lokales Repository zu übernehmen. Was der Nutzer tatsächlich anfragt, ist, dass der Server seine Remote-Änderungen in einen bestimmten Branch zusammenführt. GitLabs „merge request“ ist die treffendere Bezeichnung.
Ich habe einmal gesehen, wie jemand nach einem
fetchdachte, Commits seien verschwunden. Tatsächlich waren sie nur verborgen, weil das Repository zeitlich zurückgesprungen war. Git versteckt solche Details instatus; wenn man nichtgit-promptoderpowerline-shellnutzt, arbeitet man praktisch im Dunkeln.git-request-pull(1)weiterlebt, war, dass wir alle unsere eigenen Git-Repositories auf Orten wie kernel.org/git oder redhat.com/git hätten und uns per E-Mail darum bitten würden, aus Repositories auf unterschiedlichen Servern, in unterschiedlichen Organisationen und Domains zu pullen.GitHub ließ sich vom Git-Befehl
request-pullinspirieren, interpretierte ihn aber als Zusammenführen von einem GitHub-Repository in ein anderes GitHub-Repository um.Zumindest habe ich es immer so verstanden.
Kurz gesagt ist es keine Anfrage an den Server, sondern an eine andere Person. Man bittet die andere Person, den eigenen Branch zu pullen, damit sie sich die Änderungen ansehen kann, die man zum Projekt beitragen möchte.
[0] https://git-scm.com/book/en/v2/Distributed-Git-Contributing-...