
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 merge
aber 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?

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.
-
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.
-
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.
- Bestätigen Sie normal. (
git commit -m "octopus-merged remote 'a', 'b', 'c', 'd'"
)
- 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.
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
10146900cookie-checkGit Octopus Merge mit nicht verwandten Repositoriesyes
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