Git: Wie funktioniert das merge, rebase und pull intern?

Hi, ich würde gerne etwas mehr über Git und dessen Mechanismen erfahren. Was geschieht beim merge, rebase und pull-Algorithmus intern? Also wann und wieso können Merge-Konflikte auftreten oder wie kann ich diese im Vorhinein vermeiden? Gibt es vielleicht ähnlich leistende Alternativen zu Git?

Danke für jede Antwort. :slight_smile:

Das Auftreten von Konflikten hat nichts mit der internen Arbeitsweise von git zu tun. Konflikte entstehen dadurch, dass die selbe Zeile in einer Datei in zwei unterschiedlichen Zweigen parallel geändert wird. Die werden also nicht von git, sondern von Dir als Programmierer verursacht.

Konflikte lasen sich auch prinzipiell nicht vermeiden. Lediglich die Auswirkungen und den Aufwand für die Nachbearbeitung kann man minimieren. Mein Tipp dazu: „Minimal Clean Commits“ und so lange wie möglich auf Rebase setzten.

Ein Commit ist „clean“, wenn das Projekt vor und nach der committeten Änderung compiliert und alle automatisierten Tests erfolgreich durch laufen (also „grün“ sind).
Ein Commit ist minimal, wenn er nicht mehr Änderungen enthält, als mindestens notwendig waren, diesen Zustand wieder zu erreichen.

Dieses Verfahren führt dazu, dass man sehr viele Commits mit relativ kleinen Änderungen erhält. Das allein ist noch kein Vorteil, erst in Kombination mit Rebase.

Was macht Rebase? Es nimmt jeden einzelnen Commit aus dem Quellbranch und wendet die darin enthaltenen Änderungen auf dem Zielbranch erneut an, wobei es jeweils einen neuen Commit im Zielbranch anlegt. https://i.stack.imgur.com/CNK9P.png
Wenn ein Konflikt auf tritt betrifft der also immer nur eine kleine Änderung für die man zu dem eine (hoffentlich) zielführende Kommitmessage hat. Für diese kleine Änderung lässt sich viel leichter erkennen, wie der Zielzustand sein sollte. Ob man bei der Konfliḱtauflösung alles richtig gemacht hat weiß man, wenn das Projekt wieder kompiliert und alle Tests grün sind, bevor man git add -u && git rebase --continue aufruft.

Dieses Vorgehen ergänzt sich optimal mit dem TestDrivenDevelopement, wo man dann nach jedem Durchlauf des Microcycles einen Commit machen könnte, spätestens aber, bevor man mit der nächsten UnitTest-Methode an fängt.

bye
TT

Nachtrag

Was vor allem anderen Konflikte vermeiden hilft ist ein „vertikaler Programmierstil“, also so wenig wie möglich in eine Zeile zu schreiben. Das betrifft ins besondere Parameterlisten in Methodensignaturen oder Methodenaufrufen oder einzelnenen Methodenaufrufen in „fluent APIs“.

Statt

void doSomething(int start, int end, String base) throw IllegalArgumentException,MyOwnException {
  doSomethingElse(start, end, base, returnSomethingBasedOn(A_CONSTANT, start + end));
  IntStream.range(start,end).map(i->i*i).sum();
}

besser so:

void doSomething(
        int start, 
        int end, 
        String base
) throws IllegalArgumentException,
         MyOwnException 
{
  doSomethingElse(
     start, 
     end, 
     base, 
     returnSomethingBasedOn(
            A_CONSTANT, 
            start + end));
  IntStream.range(
              start,
              end)
           .map(i->i*i)
           .sum();
}

Das minimiert die Wahrscheinlichkeit, dass eine Zeile in verschiedenen branches parallel geändert wird und so ein Konflikt entsteht einfach deshalb, weil weniger in einer Zeile drin steht.

Würde zum Beispiel in einem Branch die Methode doSomethingElse() umbenannt und in einem parallelen Branch die Konstante A_CONSTANT wäre das im oberen Beispiel ein Konflikt, weil die Änderung in der selben Zeile ist, im unteren Beispiel aber nicht.

ich selber nutze Subversion und habe mir angewöhnt meine Commits über Terminal zu machen

svn commit -m "blabla"

in dem blabla passt normal nicht viel rein - außerdem wird das svn log etwas übersichtlicher

hand, mogel

Ich würde unbedingt davon abraten ein Formatierung etc. an ein VCS anzupassen… Abgesehen davon, dass das in einigen Programmiersprachen überhaupt nicht geht, da harte Formatvorgaben einzuhalten sind …z.B. Python und auch Go oder auch Rust…

Welche alternative soll es denn geben? Ich meine eine die auch wirklich genutzt und unterstützt wird (in IDE’s, anderen Werkzeugen)… Das verhindert aber keine Konflikte…Da alle VCS auf Zeilen orientierter Betrachtung der eingecheckten Daten gehen…

Soweit ich mich erinnere betreffen die Formatierungsvorgaben in Python (und wahrscheinlich auch in go und rust) Einrückungen und Leerzeilen. Darüber hinaus sind Formatierungsfragen in erster Linie eine Abstimmungsfrage zwischen den Teammitgliedern.

Und wo genau siehst Du jetzt das Nogo dagegen, bei den Formatierungsregeln die Konfliktvermeidung im SCM zu berücksichtigen? Am Ende spart es doch Zeit und damit Geld, wenn so ein Rebase mit höherer Wahrscheinlichkeit erfolgreich durch läuft.

bye
TT

Hi @Timothy_Truckle , vielen Dank für den Hinweis auf clean und minimal!

Den „vertikalen Programmierstil“ regelt ja ohnehin das Tooling, also die vorgegebene Formierung. :slight_smile: Darauf kann man (und sollte man auch nicht) also keinen Einfluss nehmen.

@kama Nur, weil es in anderen Programmiersprachen keine Codestyles gibt, heißt das nicht, dass die besser wären…

Um git zu verstehen, kann man sich den diff Befehl unter Linux anschauen und ein bisschen mit herumspielen. Der findet die Unterschiede zwischen 2 Dateien und speichert sie in einer dritten.

Datei A

Hallo

Datei B

Welt

Diff Datei

- Hallo
+ Welt

Diese diff Datei kann man jetzt auf Datei A „patchen“ und man erhält Datei B. Das geht natürlich auch andersherum um aus B → A zu erhalten.

Wenn wir jetzt einfach Datei A im Nachhinein editieren und noch ein „Byte-Welt“ in der zweiten Textzeile dranhängen…

Hallo
Byte-Welt

und die bereits erstellte A-B diff Datei auf die editierte Datei A patchen erhalten wir den folgenden Output

Welt
Byte-Welt

Das geht also auch. Ohne Konflikte.

Und so funktioniert auch git. Damit kann man sich herleiten wie Konflikte entstehen. Und zwar dann wenn mehrere diffs sich gegenseitig widersprechen.

Wie schon erwähnt, sind Konflikte bzw. vermeiden dieser keine Funktion von Git.

Das liegt an der Arbeitsweise der Entwickler, aber auch daran, was geändert wird.
Eine einzige XML Datei die von allen Entwicklern bearbeitet wird? Da braucht man Kommunikation, sonst gibt es Konflikte.
Hatte das mit einem Entwickler der neben mir sass, wir waren immer noch zu weit entfernt, was die Kommunikation betraf :wink:

Ansonsten sind Formatierungsregeln super (vor allem wenn man an OCD leidet :wink: ), ändert nix daran dass man als Team spielen muss, und da hapert es oft.
Da diskutiert man oft lieber Code anstatt wie man besser als Team wird…

Edit:
ach, der User ist schon gesperrt…

Jo, eagle und @Marco13 wollen mich im Discord und hier anscheinend nicht. Erzeugt wohl zu viel Unruhe…

Dennoch Danke für das „Sich-Gedanken-Machen“.

es ist mal wieder ein CB