Git Octopus Merge mit nicht verwandten Repositories

Lesezeit: 5 Minuten

Benutzer-Avatar
Erich

Ich habe eine Reihe von Git-Repositories, die jeweils eine Datei enthalten. Ich möchte sie alle zusammenführen, am besten in einem Schritt. Was ich anstrebe, ist diese Grafik:

*----¬ mergedrepo/master
| \ \ \
| | | * repoA/master
| | * repoB/master
| | |
| | * repoB/...
| * repoC/master
* repoD/master
|
* repoD/...

Ich habe versucht, a git mergeaber es scheint, dass die Octopus-Strategie für disjunkte Bäume nicht funktioniert

$ git merge a/master b/master c/master d/master
Unable to find common commit with a/master
Automatic merge failed; fix conflicts and then commit the result.

Das wurde mir auch gesagt git merge --squash würde helfen, aber das gab den gleichen Fehler.

Dies erzeugt das richtige Diagramm, verliert aber alle Dateien:

$ git merge -s ours a/master b/master c/master d/master

Wie mache ich das?

  • Ihre Octopus-Zusammenführung wird funktionieren, Sie müssen nur die Konflikte beheben, wie in der Nachricht angegeben. Sobald Sie die Konflikte behoben haben, sollten Sie einfach festschreiben können.

    – CB Bailey

    3. Juni 2012 um 21:52 Uhr

  • @CharlesBailey: Es gibt keine Konflikte!

    – Erich

    3. Juni 2012 um 22:18 Uhr

  • Ja, es gibt: “Automatisches Zusammenführen fehlgeschlagen; Konflikte beheben und Ergebnis dann festschreiben.”. Um den Konflikt zu lösen, möchten Sie wahrscheinlich nur alle widersprüchlichen Pfade hinzufügen, wenn die Dateien in den Repositorys nicht dieselben Namen haben.

    – CB Bailey

    3. Juni 2012 um 23:21 Uhr

Benutzer-Avatar
Schwindel

Ich habe es geschafft, das Problem mit der Oktopus-Merge von nicht verwandten Branches zu lösen. Leider gilt das Folgende nur für ziemlich einfache Fälle, in denen keine wirklichen Zusammenführungskonflikte bestehen.

  1. Führen Sie eine Zusammenführung durch, wie im OP beschrieben.

    git merge --allow-unrelated-histories a/master b/master c/master d/master

    Es wird „fehlschlagen“, Konflikte zu behaupten. Aber die Zusammenführung wurde durchgeführt und diese Tatsache aufgezeichnet, obwohl es keine Änderungen im Index gibt.

  2. Fügen Sie den Inhalt von Zweigen mit dem dem Index hinzu read-tree Befehl:

    git read-tree a/master b/master c/master d/master

    Dies wirkt sich nicht auf den Arbeitsbaum aus, nur der Index wird aktualisiert. (Es ist möglich, dass Sie Ihren aktuellen Zweig am Ende hinzufügen möchten. Sie müssen alle in einem Befehl hinzufügen.)

    Wenn Zweige nicht vollständig unabhängig sind, passen Sie ihre Reihenfolge an, wobei Sie bedenken, dass letztere den Inhalt früherer Zweige überschreiben.

  3. Bestätigen Sie normal. (git commit -m "octopus-merged remote 'a', 'b', 'c', 'd'")
  4. Führen Sie einen Hard-Reset durch (git reset --hard), um einen konsistenten Arbeitsbaum zu erhalten.

Ich nehme an, man kann diesen Commit später bearbeiten und ändern, aber ich persönlich habe das nicht versucht.

  • Du meinst wahrscheinlich git read-tree ... anstatt git read-subtree .... Ich wette auch, dass die Leser es zu schätzen wissen, wenn Sie Codebeispiele für jeden Schritt geben, wie z git reset --hard für Schritt 4.

    – Schlomo Georg Konwisser

    20. September 2016 um 0:44 Uhr

  • Falls jemand anderes Schwierigkeiten hat, dies herauszufinden: Sie geben zwar nicht den Namen des Zweigs an, in den Sie fusionieren, in die git merge Befehl, sollten Sie ihn in die einfügen git read-tree Befehl.

    – dave4420

    13. September 2017 um 13:15 Uhr

  • Für mich hat das Hinzufügen des Inhalts der Branches nicht funktioniert, weil ich 11 davon integrieren musste und git read-tree mir sagte: fatal: Ich kann nicht mehr als 8 Bäume lesen. Allerdings durch Einlesen der Bäume einzeln in den Index mit git read-tree a/master und bringt sie dann mit in den Arbeitsbereich git checkout-index -a Es ist möglich, alle Dateien auf einmal festzuschreiben und somit diese Einschränkung zu überwinden.

    – Jadephantom

    16. September 2019 um 8:22 Uhr


Erstellen Sie ein leeres Commit

git commit -m "Common commit" --allow-empty

Betrachten Sie seinen Hash mit log -1 und fügen Sie es ohne Eltern zur Grafts-Datei hinzu

echo HASH_OF_COMMON_COMMIT >> .git/info/grafts

Finden Sie dann alle anderen Wurzeln mit log --max-parents=0 und fügen Sie für jede ihren Hash mit dem obigen Hash als übergeordnetem Hash zur Graft-Datei hinzu

each HASH_OF_ROOT HASH_OF_COMMON_COMMIT >> .git/info/grafts

und jetzt verschmelzen!

Die Grafts-Datei ist eine Möglichkeit, die Eltern eines Commits zu ändern, und sobald alle Ihre Repos einen gemeinsamen Commit haben, sollte Ihr Repo die Zusammenführung akzeptieren.

Ich musste viele nicht verwandte Zweige von einer alten SVN-Struktur in ein neu initialisiertes Git-Repo zusammenführen. Die Antwort von Vertigo hat mich fast bis zum Ziel gebracht, aber git read-tree kann nur bis zu 8 Bäume gleichzeitig lesen.

Meine Lösung bestand darin, nach jedem Lesen einen neuen Baum zu schreiben und diesen neuen Baum dann beim nächsten Lesen zu verwenden:

tree_head=HEAD
to_merge="a/master ... z/master"

# If you're using a variable here you want word splitting, so don't use quotes.
git merge --allow-unrelated-histories $to_merge

for merging in $to_merge; do
    git read-tree "$tree_head" "$merging"
    tree_head=$(git write-tree)
done

git checkout-index -fua
git commit -m "All repos merged."

Obwohl es komplizierter aussieht, denke ich, dass die Lösung von @akuhn die einzige ist, die tatsächlich so funktioniert, wie Git es beabsichtigt. Auch für mich funktionieren die anderen Lösungen nur, wenn ich die nicht verwandten Zweige einmal zusammenführe. In meinem Anwendungsfall wollte ich aufeinanderfolgende Zusammenführungen mit verschiedenen Versionen der nicht verwandten Branches durchführen. Die anderen Lösungen werfen keine Fehler, aber der Dateistatus wird durcheinander gebracht.

Die skizzierte Lösung ist seit Git 1.6.5, das die eingeführt hat, tatsächlich viel einfacher geworden git replace Befehl. Die Idee ist jedoch immer noch die gleiche: Sie lassen Git denken, dass Ihre Commits einen gemeinsamen Commit haben, damit die Zusammenführung funktioniert. Dazu müssen Sie den SHA-1 des anfänglichen Commit Ihres aktuellen Zweigs herausfinden:

common_commit=$(git rev-list --max-parents=0 HEAD)

Sobald Sie das haben, teilen Sie git mit, dass jeder der Zweige, die Sie zusammenführen möchten, von diesem Commit stammt:

for branch in a/master b/master c/master d/master
do
  branch_initial_commit=$(git rev-list --max-parents=0 $branch)
  git replace --graft $branch_initial_commit $common_commit
done

Danach können Sie einfach den Zusammenführungsbefehl ausführen. Git wird sich nicht beschweren, da alle Zweige jetzt aus demselben gemeinsamen Commit stammen.

git merge a/master b/master c/master d/master

1014690cookie-checkGit Octopus Merge mit nicht verwandten Repositories

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy