Warum enthalten Git-Commits nicht den Namen des Zweigs, in dem sie erstellt wurden?


20

Wenn ich mit Git in einem Team mit Feature-Zweigen arbeite, finde ich es oft schwierig, die Zweigstruktur in der Geschichte zu verstehen.

Beispiel:

Nehmen wir an, es gab ein Feature-Branch- Feature / einen Kaffee zum Zubereiten und die Fehlerbehebung auf dem Master wurde parallel zum Feature-Branch fortgesetzt .

Die Geschichte könnte so aussehen:

*     merge feature/make-coffee
|\
| *   small bugfix
| |
* |    fix bug #1234
| |
| *    add milk and sugar
| |
* |    improve comments
| |
* |    fix bug #9434
| |
| *    make coffe (without milk or sugar)
| |
* |    improve comments
|/
*

Problem

Auf den ersten Blick fällt es mir schwer zu sagen, auf welcher Seite sich der Feature-Zweig befindet. Normalerweise muss ich auf beiden Seiten mehrere Kommentare durchsuchen, um eine Vorstellung davon zu bekommen, welche welche ist. Dies wird noch komplizierter, wenn mehrere Feature-Zweige parallel vorhanden sind (insbesondere wenn es sich um eng verwandte Features handelt) oder wenn Feature-Zweige und Master in beide Richtungen zusammengeführt wurden.

Im Gegensatz dazu ist dies in Subversion erheblich einfacher, da der Filialname Teil des Verlaufs ist. So kann ich sofort feststellen, dass ursprünglich ein Commit für "feature / make-coffee" ausgeführt wurde.

Git könnte dies vereinfachen, indem der Name des aktuellen Zweigs in die Commit-Metadaten aufgenommen wird, wenn ein Commit erstellt wird (zusammen mit Autor, Datum usw.). Git tut dies jedoch nicht.

Gibt es einen fundamentalen Grund, warum dies nicht getan wird? Oder wollte nur niemand die Funktion? Wenn es das letztere ist, gibt es andere Möglichkeiten, den Zweck historischer Zweige zu verstehen, ohne den Namen zu sehen?


1
Verwandte Frage: Ermitteln, aus welchem ​​Zweig ein Commit stammt . Hier erfahren Sie, wie Sie diese Informationen finden, obwohl git sie nicht explizit aufzeichnet.
Sleske

1
Notiz an mich selbst: Interessanterweise in Mercurial der Commit nicht die Zweignamen enthalten. Es scheint also, dass die Mercurial-Entwickler eine andere Designentscheidung getroffen haben als die Git-Entwickler. Siehe zB felipec.wordpress.com/2012/05/26/… für Details.
Sleske

Antworten:


14

Wahrscheinlich, weil Filialnamen nur innerhalb eines Repositorys von Bedeutung sind. Wenn ich im make-coffeeTeam bin und alle meine Änderungen über einen Gatekeeper einreiche, wird mein masterZweig möglicherweise in den make-coffee-guiZweig des Gatekeepers gezogen , den er mit seinem make-coffee-backendZweig zusammenführt, bevor er zu einem make-coffeeZweig zurückkehrt, der in den zentralen masterZweig eingegliedert wird.

Sogar innerhalb eines Repositorys können sich die Filialnamen ändern, während sich Ihr Workflow entwickelt. masterkönnte sich später ändern development, um beispielsweise aufgerufen zu werden .

Wie CodeGnome angedeutet hat, hat git eine starke Designphilosophie, etwas nicht in die Daten zu backen, wenn es nicht benötigt wird. Die Benutzer werden voraussichtlich Optionen verwenden , in git logund für git diffdie Ausgabe der Daten an ihre nach der Tat mögen. Ich empfehle, einige davon auszuprobieren, bis Sie ein Format gefunden haben, das für Sie besser funktioniert. git log --first-parentBeispielsweise werden die Commits aus einem Zweig, in dem die Zusammenführung stattfindet, nicht angezeigt.


2
Es sollte jedoch beachtet werden, dass der erste Elternteil normalerweise der falsche ist. Denn normalerweise zieht man den Meister einfach in das hinein, woran er gerade arbeitet, und schiebt seine Arbeit heraus, so dass der erste Elternteil der zweite ist und er den zweiten beherrscht.
Jan Hudec

1
@JanHudec: Eigentlich kommt es darauf an :-). Wenn die Person, die die Arbeit erledigt, sie zusammenführt, dann ja. Wenn die Zusammenführung später erfolgt, möglicherweise nach einer Überprüfung, ist es wahrscheinlicher, dass der Prüfer den Master ausgecheckt hat und den Feature-Zweig in Master zusammenführt, testet und pusht.
Sleske

5

Filialverlauf verfolgen mit --no-ff

In Git hat ein Commit Vorfahren, aber ein "Zweig" ist eigentlich nur der aktuelle Kopf einer Entwicklungslinie. Mit anderen Worten, ein Commit ist eine Momentaufnahme des Arbeitsbaums zu einem bestimmten Zeitpunkt und kann zu einer beliebigen Anzahl von Zweigen gleichzeitig gehören. Dies ist ein Teil dessen, was Git Branching im Vergleich zu anderen DVCS so leicht macht.

Git-Commits enthalten keine Verzweigungsinformationen, da sie für den Git-Verlauf nicht erforderlich sind. Zusammenführungen, die nicht schnell vorwärts gehen, können jedoch sicherlich zusätzliche Informationen darüber enthalten, welcher Zweig zusammengeführt wurde. Sie können sicherstellen, dass Ihr Verlauf diese Informationen enthält, indem Sie die --no-ffMarkierung immer an Ihre Zusammenführungen übergeben. git-merge (1) sagt:

   --no-ff
       Create a merge commit even when the merge resolves as a
       fast-forward. This is the default behaviour when merging an
       annotated (and possibly signed) tag.

Dadurch wird im Allgemeinen eine Zusammenführungsnachricht ähnlich der erstellt Merge branch 'foo', sodass Sie normalerweise Informationen zu "Ahnenzweigen" mit einer Zeile ähnlich der folgenden finden:

$ git log --regexp-ignore-case --grep 'merge branch'

Danke, aber das beantwortet (meistens) meine Frage nicht. Ich frage nicht, wie man den ursprünglichen Zweig auf andere Weise findet, sondern warum die Informationen nicht als reguläre Metadaten enthalten sind - es handelt sich eher um eine Entwurfsfrage.
Sleske

1
@sleske Ich denke, meine Antwort war ansprechend: Git verfolgt sie nicht, weil der Git-Verlauf sie nicht benötigt. Ich denke nicht, dass es grundlegender wird. Sie müssten die Quelle nach Einzelheiten durchsuchen, aber der Verlauf wird ab der Spitze des aktuellen Zweigs effektiv rückwärts berechnet. Sie können das immer mit anderen DVCS vergleichen, die Zweige als erstklassige Objekte behandeln, und sehen, ob Ihnen diese Designphilosophie besser gefällt. YMMV.
CodeGnome

1
Das letzte sollte sein git log --merges.
Dan

3

Die einfachste Antwort ist, dass die Namen der Zweige vergänglich sind. Was wäre, wenn Sie beispielsweise einen Zweig umbenennen würden ( git branch -m <oldname> <newname>)? Was würde mit all den Verpflichtungen gegen diesen Zweig passieren? Oder was ist, wenn zwei Personen Zweigniederlassungen mit demselben Namen in verschiedenen lokalen Repositorys haben?

Das einzige, was in git Bedeutung hat, ist die Prüfsumme des Commits. Dies ist die Grundeinheit für die Verfolgung.

Die Informationen sind da, Sie fragen einfach nicht danach und sie sind nicht genau da.

Git speichert die Prüfsumme des Kopfes jeder Verzweigung in .git/refs/heads. Beispielsweise:

... /. git / refs / heads $ ls test 
-rw-rw-r-- 1 michealt michealt 41 Sep 30 11:50 test
... /. git / refs / heads $ Katzentest 
871111111111111111111111111111111111d4

(Ja, ich überhäufte meine Git-Prüfsummen, es ist nichts Besonderes, aber es sind private Speicher, die ich in dem Moment betrachte, in dem nichts versehentlich durchgesickert sein muss).

Wenn Sie sich dies ansehen und jedes Commit, das dies als übergeordnetes Element enthält, oder das übergeordnete Element oder das übergeordnete Element des übergeordneten Elements nachverfolgen, können Sie herausfinden, in welchen Zweigen sich ein bestimmtes Commit befindet.

Das Speichern des Namens eines Zweigs (der sich wie oben erwähnt ändern kann), in dem sich ein Commit befindet, ist ein zusätzlicher Aufwand für das Commit, der nicht hilft. Speichern Sie die übergeordneten Elemente des Commits und dessen Gut.

Sie können die Zweige anzeigen, indem Sie den Befehl git log mit dem entsprechenden Flag ausführen.

git log --branches --source --pretty = oneline --graph
git log --all --source --pretty = oneline --graph

Es gibt viele verschiedene Möglichkeiten, um auszuwählen, was Sie dafür wollen - schauen Sie sich die Git-Log- Dokumentation an - den -allAbschnitt und die wenigen Optionen, die folgen.

* 871111111111111111111111111111111111d4 test Zweig 'test1' in test zusammenführen
| \  
| * 421111111111111111111111111111111111e8 test1 Update: Sachen hinzufügen
* | dd111111111111111111111111111111111159 test Zweig 'test3' in test zusammenführen
| \ \  

Diese Zweige wurden mit 'test', 'test1' und 'test2' belegt.

Beachten Sie, dass die Git-Log-Dokumentation sehr umfangreich ist und es durchaus möglich ist, fast alles herauszuholen, was Sie wollen.


3

Warum enthalten Git-Commits nicht den Namen des Zweigs, in dem sie erstellt wurden?

Nur eine Designentscheidung. Wenn Sie diese Informationen benötigen, können Sie einen Prepare-Commit-msg- oder Commit-msg-Hook hinzufügen, um dies für ein einzelnes Repository zu erzwingen.

Nach der BitKeeper-Katastrophe entwickelte Linus Torvalds git passend zum Linux-Kernel-Entwicklungsprozess. Dort wird ein Patch, bis er akzeptiert wird, überarbeitet, bearbeitet, mehrmals poliert (alles per E-Mail), abgemeldet (= Commit bearbeiten), von Kirschen gepflückt und zu Zweigen des Leutnants gewandert -Picks und so weiter, bis sie schließlich von Linus flussaufwärts zusammengeführt werden.

In einem solchen Workflow gibt es möglicherweise keinen bestimmten Ursprung eines Commits, und oft wird ein Commit nur in einem temporären Debugging-Zweig in einem unwichtigen privaten Zufalls-Repository mit lustigen Zweignamen erstellt, während Git verteilt wird.

Vielleicht ist diese Designentscheidung nur zufällig getroffen worden, aber sie passt genau zum Linux-Kernel-Entwicklungsprozess.


2

Denn in Git werden Commits wie "Kaffee machen" als Teil beider Zweige betrachtet, wenn der Feature-Zweig zusammengeführt wird. Es gibt sogar einen Befehl, um das zu überprüfen:

% git branch --contains @
  feature/make-coffee
  master

Auch sind Niederlassungen billig, lokal und ätherisch; Sie können problemlos auf dem Server hinzugefügt, entfernt, umbenannt, verschoben und gelöscht werden.

Git folgt dem Prinzip, dass alles möglich ist, weshalb Sie einen Zweig einfach von einem Remote-Server entfernen und den Verlauf einfach umschreiben können.

Nehmen wir an, ich war in der 'Master'-Branche und habe zwei Commits gemacht:' Kaffee kochen 'und' Milch und Zucker hinzufügen '. Dann entscheide ich mich, eine neue Branche zu verwenden, und setze' Master 'wieder auf' Ursprung 'zurück /Meister'. Kein Problem, die ganze Geschichte ist noch sauber: "Kaffee kochen" und "Milch und Zucker hinzufügen" gehören nicht zum Master, sondern nur zu Feature / Kaffee kochen.

Mercurial ist das Gegenteil; es will nichts ändern. Zweige sind permanent, das Umschreiben des Verlaufs ist verpönt. Sie können einen Zweig nicht einfach vom Server löschen.

Kurz gesagt: Git ermöglicht es Ihnen, alles zu tun, Mercurial möchte die Dinge vereinfachen (und macht es wirklich schwierig, Sie tun zu lassen, was Sie wollen).

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.