blog · git · desktop · images · contact & privacy · gopher


Verzeichnisse mit Git „frisch“ synchronisieren

Angenommen, man hat drei Verzeichnisse "a", "b" und "c". Alle haben "so ungefähr" denselben Inhalt: Die meisten Dateien gibt es überall, manche aber gibt es nur in "b", andere unterscheiden sich in "a" und "c", sind dabei in "b" gar nicht vorhanden, und so weiter. Da möchte man jetzt Ordnung in dieses Chaos bringen.

Git wäre eine Möglichkeit, dies zu tun. Außerdem wollte ich das schon länger mal sauber aufschreiben. :)

Zuerst pro Verzeichnis ein Git-Repo initialisieren und einen ersten Commit erstellen (dabei entsteht ein Verzeichnis ".git" in den Verzeichnissen "a", "b" und "c"):

$ cd a
$ git init
$ git add .
$ git commit -m 'Initial a.'

Dasselbe eben entsprechend für "b" und "c". Bis jetzt sind diese drei Repositories noch völlig unabhängig voneinander.

Innerhalb des Verzeichnisses "a" wird nun der gemeinsame Stand erzeugt. Angefangen mit den Daten von "b":

$ cd a
$ git fetch ../b
$ git merge FETCH_HEAD

Falls es keine Konflikte gibt, war's das. Falls es doch zu Konflikten kommt (Dateien gleichen Namens mit unterschiedlichen Inhalten), muss man diese auflösen. Angenommen, die Datei "foo" ist eine solche Konfliktdatei. Betrachten wir mal den Sonderfall, dass man jetzt nicht "klassisch" den Konflikt auflösen, sondern beide Versionen der Datei speichern möchte -- also "foo.a" aus "a" und "foo.b" aus "b". Später kann man sich dann immernoch für eine endgültige Version entscheiden. So geht's:

$ git show :2:foo > foo.a
$ git show :3:foo > foo.b
$ git rm foo
$ git add foo.a foo.b

Wollte man stattdessen nicht zwei getrennte Versionen "foo.a" und "foo.b" haben, sondern den Konflikt tatsächlich auflösen und eine einzige Datei "foo" erstellen, würde sich das Mergetool anbieten:

$ git mergetool

Als Vim-Liebhaber würde ich vorher noch einmalig "git config --global merge.tool vimdiff" absetzen, aber das kann jeder tun, wie er möchte. Meld soll zum Beispiel toll sein.

Sind letztlich alle Konflikte abgearbeitet, erfolgt der abschließende Commit:

$ git commit -m 'Merge mit "b" fertig.'

Wenn "a" und "b" derart auf einen Stand gebracht wurden, kann man mit "c" weitermachen. Wieder ausgehend vom Verzeichnis "a":

$ git fetch ../c
$ git merge FETCH_HEAD

Hier geht das Spielchen dann von vorne los. Konflikte auflösen und so weiter.

Schlussendlich kann man dann noch die ".git"-Verzeichnisse aus "a", "b" und "c" löschen, falls man das möchte. Man kann alternativ aber auch die Gelegenheit nutzen und direkt Git für die Datenhygiene etablieren. Da man jetzt nämlich ohnehin schon eine gemeinsame Basis erzeugt hat und in "b" und "c" schon die Git-Repositories existieren, reicht es aus, dort einmal von "a" zu pullen:

$ cd ../b
$ git pull ../a
$ cd ../c
$ git pull ../a

Konflikte wird es hier nicht mehr geben.