Git merge Branch A in Branch B

Als Beispiel wird der Branch 3.12 in den Branch 3.13 gemerged.

Zum Testen des merge:

$ # Updaten der 'remote Heads'
$ git fetch
$ # Wechsel auf den Branch, in den gemerged werden soll
$ git checkout 3.13
$ # Testmerge ohne das Ergebnis einzutragen
$ git merge --squash origin/3.12
$ # Gab es Konflikte?
$ git status
# Auf Zweig 3.13
# zum Eintragen bereitgestellte Änderungen:
#   (benutzen Sie "git reset HEAD <Datei>..." zum Herausnehmen aus der Bereitstellung)
#
#       geändert:   nuclos-client/src/main/java/org/nuclos/client/dbtransfer/DBTransferExport.java
#       geändert:   nuclos-client/src/main/java/org/nuclos/client/dbtransfer/DBTransferImport.java
#       geändert:   nuclos-client/src/main/java/org/nuclos/client/livesearch/LiveSearchController.java
#       geändert:   nuclos-client/src/main/java/org/nuclos/client/livesearch/LiveSearchSettingsPanel.java
#       geändert:   nuclos-client/src/main/java/org/nuclos/client/main/SimpleSplash.java
#       geändert:   nuclos-common/src/main/java/org/nuclos/common/dal/vo/Delete.java
#       geändert:   nuclos-common/src/main/java/org/nuclos/server/livesearch/ejb3/LiveSearchFacadeRemote.java
#       geändert:   nuclos-installer/build.xml
#       neue Datei:   nuclos-installer/conf/3rdparty/apache-tomcat-7.0.39.zip.SHA1
#       neue Datei:   nuclos-installer/conf/3rdparty/postgresql-9.2.4-1-linux-x64.run.SHA1
#       neue Datei:   nuclos-installer/conf/3rdparty/postgresql-9.2.4-1-linux.run.SHA1
#       neue Datei:   nuclos-installer/conf/3rdparty/postgresql-9.2.4-1-osx.dmg.SHA1
#       neue Datei:   nuclos-installer/conf/3rdparty/postgresql-9.2.4-1-windows-x64.exe.SHA1
#       neue Datei:   nuclos-installer/conf/3rdparty/postgresql-9.2.4-1-windows.exe.SHA1
#       geändert:   nuclos-installer/src/main/java/org/nuclos/installer/Constants.java
#       geändert:   nuclos-server/src/main/java/org/nuclos/server/dbtransfer/TransferFacadeBean.java
#       geändert:   nuclos-server/src/main/java/org/nuclos/server/dbtransfer/content/EntityFieldNucletContent.java
#       geändert:   nuclos-server/src/main/java/org/nuclos/server/dbtransfer/content/ImportNucletContent.java
#       geändert:   nuclos-server/src/main/java/org/nuclos/server/dbtransfer/content/ResourceNucletContent.java
#       geändert:   nuclos-server/src/main/java/org/nuclos/server/livesearch/ejb3/DocumentHandler.java
#       geändert:   nuclos-server/src/main/java/org/nuclos/server/livesearch/ejb3/IndexQuery.java
#       geändert:   nuclos-server/src/main/java/org/nuclos/server/livesearch/ejb3/LiveSearchFacadeBean.java
#       geändert:   nuclos-server/src/main/java/org/nuclos/server/livesearch/ejb3/LuceneWriter.java
#       geändert:   nuclos-server/src/main/java/org/nuclos/server/livesearch/ejb3/NuclosCoordinate.java
#       geändert:   nuclos-server/src/main/java/org/nuclos/server/livesearch/ejb3/NuclosIndexer.java
#       geändert:   nuclos-server/src/main/java/org/nuclos/server/masterdata/ejb3/MasterDataFacadeHelper.java
#       geändert:   nuclos-server/src/main/resources/resources/data/localeresource.json
#
# Nicht zusammengeführte Pfade:
#   (benutzen Sie "git reset HEAD <Datei>..." zum Herausnehmen aus der Bereitstellung)
#   (benutzen Sie "git add/rm <Datei>..." um die Auflösung zu markieren)
#
#       von beiden geändert:nuclos-client/src/main/java/org/nuclos/client/eventsupport/EventSupportManagementController.java

$ # Aha, 'Nicht zusammengeführte Pfade' bedeutet Konflikt(e)
$ # Lösung des Konflikts z.B. mit 
$ # git mergetool (siehe unten)

$ # Testmerge zurückrollen
$ git reset --hard HEAD

$ # Wir sind jetzt wieder im Branch 3.13, wie er vor dem Testmerge war...

Merge tatsächlich durchführen:

$ # Updaten der 'remote Heads'
$ git fetch
$ # Wechsel auf den Branch, in den gemerged werden soll
$ git checkout 3.13
$ # Richtiger Merge, der das Ergebnis sofort einträgt, falls keine Konflikte auftreten
$ git merge origin/3.12
$ # Gab es Konflikte?
$ git status
[...]

$ # Falls es keine Konflikte gab, ist jetzt der Merge bereits durchgeführt!
$ # D.h. es kann 'gepushed' werden...
 
$ # Konflikte lösen (siehe unten)
$ git mergetool

$ # Merge mit manuell gelösten Konflikten einchecken
$ git commit -s 

Git Konfliktmanagement

Wenn kein fast-forward und kein clean-merge vorliegt, dann gibt es Konflikte, die manuell gelöst werden müssen. Dies ist immer der Fall, wenn sich in den entsprechenden Dateien seit der Zeit, wo sie auseinander gelaufen sind, auf der gleichen Zeile auf beiden Seiten (d.h. bei mir und bei den anderen) nicht-gleiche Änderungen ergeben haben.

Ferner entstehen Konflikte dadurch, dass (nur) auf einer Seite eine Datei gelöscht bzw. auf beiden Seiten die Datei umbenannt wurde. Diese Rename Konflikte werden wir im folgenden jedoch nicht betrachten.

Dokumentation

Bei welchen git Kommandos kann ein Konflikt auftreten?

  • git merge (verfügbar: --abort)
  • git pull (führt entweder ein 'git merge' oder - falls rebase = true - ein 'git rebase' durch, sie Git)
  • git rebase (verfügbar: --continue, --abort, --skip)
  • git cherry-pick (verfügbar: --continue, --abort, --quit)
  • git stash (bei pop, apply and branch)

Bei 'git rebase x y' werden die Änderungen von Branch y auf x angewendet. Technisch wird also x der aktuelle Branch, auf denen dann die Patches/Diffs der Commits in y angewendet werden. Im praktischen Leben bedeutet dies (meist), dass die Tools zur manuellen Konfliktbeseitigung meine (ours) Änderungen als remote/theirs Anzeigen! Dies liegt daran, dass Rebase x zum aktuellen Branch macht!

 

Vorgehen bei einem Konflikt

  1. Wenn man den Konflikt manuell lösen möchte, ein Tool zu manuellen Konfliktbeseitigung benutzen (s.u.)
  2. Die gerade laufende git Operation (s.o.) weiterführen (mit --continue), abbrechen (mit --abort), oder überspringen (mit --skip). Diese Optionen stehen nicht bei allen Kommandos zur Verfügung (s.o.)!
  3. Mittels git status kann man sich immer über den gegenwärtigen Zustand Überblick verschaffen.
  4. Mittels git show kann man sich die 3 Konfliktdateien (base, ours, theirs) anzeigen lassen.
  5. Mittels 'git checkout [–base|–ours|–theirs]' kann man den Konflikt 'hart' für eine Datei lösen.
  6. Ebenfalls sinnvoll sind die Kommandos 'git diff [–base|--ours|--theirs]', 'git log --merge' und 'gitk --merge'

Tools zur manuellen Konfliktbeseitigung

  • git mergetool
    Dieses Tool arbeitet mit diversen 3-Wege-Diff GUIs zusammen (emerge, gvimdiff, kdiff3, meld, vimdiff, tortoisemerge). Unter Linux empfehle ich, kdiff3 zu installieren und zu benutzen. Anleitungen für kdiff3 und meld.
  • Die Team Synchronizing Perspective von Eclipse
    Kann ich nicht empfehlen, da das 3-Wege-Diff GUI innerhalb von Eclipse nur sehr wenige Optionen zur Verfügung stellt. Die Konfliktbeseitigung wird hier beschrieben.
  • Das 3-Wege-Diff GUI aus SourceTree (nur OsX)

Fortgeschrittene Feature

git rerere

Bei einem längere Benutzen Feature Branch kommt es vor, dass dieser mehrmals auf den Entwicklungsstand rebased werden soll. In diesem Fall müssen u.U. die gleichen Konflikte mehrfach gelöst werden. git rerere kann diese mehrfache Konfliktbeseitigung automatisieren.

 

  • Keine Stichwörter