Git macht die merge
Magie und lässt dann den Benutzer echte Konflikte lösen, was so ist, wie es sein sollte. Ich bin auf der Suche nach einer Low-Level-Beschreibung des Wie und Warum des grundlegenden Git-Merge und wie es den Staging-Bereich verwendet.
Ich habe gerade die Git-Parabel gelesen und die kommentieren hier , dass
Selbst wenn man bedenkt, dass es sich um "Parabel" handelt und nicht um die Geschichte von Git (die man übrigens auf Git Wiki finden kann), bleibt ein Punkt: Es ist IMVHO schlechtes Üben Erklären Sie den Staging-Bereich im Sinne der Aufspaltung von Änderungen in mehr als einen Commit und / oder Commit mit Dity Tree, dh mit einigen Änderungen unkompiliert. Staging-Bereich Hauptstärke (abgesehen davon, dass explizite Version von anderen SCM implizit zuzusetzenden Bereich) ist mit CONFLICTED MERGE, und das ist, wie es erklärt werden sollte, denke ich.
Die git merge
man-Seite identifiziert die Phase 1 / 2/3 Elemente der Zusammenführung, aber offensichtlich geht nicht ins Detail von Warum und Wozu.
Kann Folk bei allen Artikeln darüber beraten, wie und warum git die Ergebnisse erzielt, die andere nicht erreichen (über den Linus V Bram hinaus in Wincent's Blog ), dh der angebliche Trivial -Teil?
Die meisten Web-Artikel gehen davon aus, dass "nur zufällig" zusammengeführt wird, und ich habe nichts gefunden, was die Probleme erklärt (z. B. die Notwendigkeit kleiner Commits, den Wert eines gemeinsamen Commits usw.).
Fast jeder VCS verwendet das Grundkonzept einer dreifachen Zusammenführung. Dadurch werden zwei Zweige mit einem gemeinsamen Vorfahren verglichen. Wenn also eine Codezeile zwischen den beiden Zweigen unterschiedlich ist, wissen Sie, durch welchen Zweig sie geändert wurde. Wenn sie beide geändert haben, haben Sie einen Zusammenführungskonflikt, der von einem Menschen gelöst werden muss.
Es gibt einige Fälle, in denen es schwierig ist, einen geeigneten gemeinsamen Vorfahren zu bestimmen. Eine Menge Forschung ging in verschiedene Algorithmen dafür ein, von denen viele die Verfolgung zusätzlicher Metadaten mit den Commits beinhalteten.
Linus 'wesentliche Neuerung war das Verfolgen von Bäumen anstelle von Dateien . Das ist eine Art subtile Unterscheidung. Um das Beispiel aus Wincents Blog zu veranschaulichen, betrachten Sie eine Datei foo
in der Zweigstelle A
. Sie verzweigen, um den Zweig B
zu erstellen. Im Zweig A
foo
wurde in bar
umbenannt. Im Zweig B
wird es gelöscht. Sie versuchen dann, zu verschmelzen.
Wenn Sie Dateien nachverfolgen, sieht das so aus:
Vor der Verzweigung wird Version 1 der Datei foo
erstellt.
Nach dem nächsten Commit zeigt der Zweig A
auf Version 2 von foo
, was eine gelöschte Datei ist, und Version 1 der neuen Datei bar
.
Nach dem nächsten Commit zeigt der Zweig B
auf Version 2.1 von foo
, was eine gelöschte Datei ist.
Beim Zusammenführen werden Version 2 und 2.1 von foo
verglichen und als identisch erkannt. Kein Zusammenführungskonflikt dort. Branch B
hat nicht einmal eine Datei namens bar
, also auch keinen Konflikt. Sie haben am Ende den Zusammenführungsalgorithmus, der stillschweigend das Umbenennen der Verzweigung A
annimmt, obwohl ein echter Konflikt zwischen foo
, der gelöscht und umbenannt wird, aufgetreten ist.
Wenn Sie Bäume verfolgen, geht das so:
Vor der Verzweigung wird ein Blob mit dem Hash dcb8bd7a97ab39f4c156a1a96d4b10720a39fb81 erstellt. Ein Baum wird mit einem Eintrag erstellt, der das Label foo
enthält, das auf den Hash verweist.
Nach dem nächsten Commit zeigt die Verzweigung A
auf einen Baum mit einem Eintrag, der die Bezeichnung bar
enthält, die auf denselben Hash verweist.
Nach dem nächsten Commit zeigt der Zweig B
auf einen leeren Baum.
Beim Zusammenführen werden die Bäume verglichen, wobei B
eine Löschung und A
eine Umbenennung des Blobs dcb8bd7a97ab39f4c156a1a96d4b10720a39fb81 zeigt. Der Mensch wird gefragt, welchen er bevorzugt.
Sie können den Effekt mit einem Datei-Tracking-VCS etwas abschwächen, indem Sie Metadaten für Umbenennungen hinzufügen, aber git's way verwendet seine normale Standard-Datenstruktur. Außerdem hat der Metadatenweg Schwierigkeiten mit komplexen Zusammenführungen, bei denen es viele mögliche Alternativen für den gemeinsamen Vorfahren gibt. Sie könnten eine Milliarde mögliche Pfade zwischen dem gemeinsamen Vorfahren und den beiden Zweigköpfen setzen, und git wird immer noch einen Blob mit demselben Hash sehen und in der Lage sein, ein Umbenennen und ein Löschen zu erkennen. Es ist auch schwierig, Metadaten zu erhalten, wenn Sie beispielsweise Änderungen in einem Patch per E-Mail akzeptieren.
Es wird etwas komplizierter mit einer umbenannten Datei, die sich gleichzeitig ändert, aber durch das Verfolgen der Bäume hat git alle benötigten Informationen. Es sieht blob dcb8bd7a97ab39f4c156a1a96d4b10720a39fb81 von beiden Zweigen weg, aber es sieht auch einen neuen Baumeintrag, der auf ein neues Blob zeigt, und kann die zwei vergleichen. Wenn ein wesentlicher Teil der Datei übereinstimmt, wird dies als Umbenennung betrachtet. Offensichtlich bricht dies zusammen, wenn Sie eine Menge Änderungen in einer umbenannten Datei vornehmen, aber irgendwann wird Ihnen kein Mischalgorithmus mehr helfen können.
Sehen Sie diese E-Mail von Linus, um mehr über seine Philosophie zu diesem Thema zu erfahren.