2010-08-05 8 views
5

Als eine Teilmenge der Frage detach-subdirectory bereits vor und unter Berücksichtigung der Tatsache, dass, obwohl eine Menge Fragen über den Prozess der Aufteilung und Zusammenführung von Git-Repositories gemacht wurden, konnte ich nicht finde einen, der das Thema der Spaltung berührt, wenn Submodule vorhanden sind.Aufteilen eines Unterverzeichnisses mit Submodulen in ein separates Git-Repository

So in das folgende Szenario:

.git/ 
.gitmodules 
folder/ 
    data/ 
    content/ 
     other_data/ 
     submoduleA/ 
     submoduleB/ 

Ich möchte zwei Repositories mit der folgenden Struktur erhalten:

.git/ 
data/ 

und

.git/ 
.gitmodules 
content/ 
    other_data/ 
    submoduleA/ 
    submoduleB/ 

Der erste Fall ist kein Problem und kann leicht mit der in detach-subdirectory beschriebenen Methode gelöst werden.

Die zweite nicht so sehr. Die Existenz von Submodulen und die Tatsache, dass .gitmodules den vollständigen Pfad für folder/content/submoduleA und folder/content/submoduleB enthält, verursacht einen Teil des Verlaufs inkonsistent, da .gitmodules auf eine nicht vorhandene Verzeichnisstruktur verweist (sobald der Filterzweig verwendet wird).

So würde ich gerne wissen, ob es eine Möglichkeit gibt, dies zu tun, ohne inkonsistente Geschichte zu verursachen.

Antwort

1

Ich vermute (nicht getestet), dass eine zweite git filter-branch die Möglichkeit hätte, den Inhalt .gitmodules für jedes commits des neuen Repo zu ändern.

Aber eigentlich eine git submodule split command was in discussion early 2009.

Proposed Nutzung:

git submodule split [--url submodule_repo_url] submodule_dir \ 
    [alternate_dir...] 

ersetzen submodule_dir mit einem neu erstellten Submodul, hält die ganze Geschichte von submodule_dir.
Dieser Befehl schreibt auch jedes Commit im aktuellen Repository-Verlauf so um, dass es die korrekte Version von sumodule_dir und die entsprechenden .gitmodules Einträge enthält.

Allerdings sehe ich es nicht in der latest what's cooking.
Das Skript im vorgeschlagenen Patch kann Ihnen eine Vorstellung von der Art des Neustrukturierens des Baumes geben, die notwendig ist, um die Datei .gitmodules zu aktualisieren.

+0

einen zweiten git filter-branch Befehl verwenden konnte ich .gitmodules mit einem sed-Befehl neu zu schreiben, aber die tatsächlichen Submodul-Ordner bleiben unberührt (beide mit Index-Filter und Tree-Filter). Nur der Unterverzeichnisfilter konnte sie ändern, aber dann wird .gitmodules entfernt. Der Split-Befehl des Git-Submoduls scheint genau das zu tun, was ich vorhabe, aber beim Lesen des Threads hatte ich den Eindruck, dass es ein paar Probleme hat, daher fühle ich mich nicht wohl dabei. – Unode

+0

@Unode: Ich verstehe. Ich glaube nicht, dass dieser bestimmte Patch gerade aktiv entwickelt wird. – VonC

5

hatte ich genau das gleiche Problem wie Unode und schaffte es mit dem folgenden Verfahren zu beheben:

git clone [email protected]:kdeldycke/kev-code.git 
cd kev-code 
git filter-branch --tree-filter "test -f ./.gitmodules && mv ./.gitmodules ./cool-cavemen/gitmodules || echo 'No .gitmodules file found'" -- --all 
git filter-branch --force --prune-empty --subdirectory-filter cool-cavemen --tag-name-filter cat -- --all init..HEAD 
git filter-branch --force --tree-filter "test -f ./gitmodules && mv ./gitmodules ./.gitmodules || echo 'No gitmodules file found'" -- --all 
git filter-branch --force --tree-filter "test -f ./.gitmodules && sed -i 's/cool-cavemen\///g' ./.gitmodules || echo 'No .gitmodules file found'" -- --all 
git remote rm origin 
rm -rf .git/refs/original/ 
git reflog expire --all 
git gc --aggressive --prune 
git remote add origin [email protected]:kdeldycke/cool-cavemen.git 
git push -u origin master --force --tags 

Wie Sie sehen, ist der Trick, vorübergehend die .gitmodules Datei umbenennen und sed seinen Inhalt neu zu schreiben, verwenden. Sie können alle Details und die context of this procedure on my blog bekommen.

+0

Sie können die Option '--tag-name-filter cat' in allen filter-branch-Befehlen einschließen, um die Tags nach dem Filtern beizubehalten. – kolyuchiy

+0

Danke für die Dokumentation. Zwei Dinge, die ich optimieren musste, um das zu erreichen. Zuerst denke ich, dass Sie ein initiales Commit angenommen haben, das als "init" für den Bereich "init..HEAD" markiert ist. Zweitens musste ich dem Befehl sed "-e" hinzufügen, d. H .: 'sed -i -e's/cool-cavemen \ /// g './. Gitmodules' – Von

0

Um Kevins Antwort zu erklären: Angenommen, dass keine Submodule jemals außerhalb cool/cavemen existierte - der Ordner wird gelöst (sonst aufwändiger Bearbeitung von.gitmodules werden diese zusätzlichen Abschnitte) entfernen benötigt, kann diese viel schneller und in einem Schritt erreicht werden unter Verwendung eines index-filter:

$ git filter-branch --subdirectory-filter cool/cavemen --index-filter $' 
hash=$(git rev-parse --verify $GIT_COMMIT:.gitmodules 2>/dev/null) && 
git update-index --add --cacheinfo 100644 $(git cat-file -p $hash | 
sed \'s/cool\\/cavemen\\///g\' | git hash-object -w --stdin) .gitmodules || 
true' --tag-name-filter cat --prune-empty -- --all 

Als zusätzlichen Vorteil, wenn cool/cavemen nicht in jeder Revision oder Zweig gab es nur Diese Revisionen oder Zweige, die cool/cavemen enthalten haben, werden betrachtet.

Ist dies der Fall, dass Sie den folgenden entfernen unverändert Referenzen ausführen mögen:

$ git for-each-ref --format='%(refname)' | 
grep -vF "$(git for-each-ref --format='%(refname)' refs/original | 
sed 's/refs\/original\///g')" | xargs -n 1 git update-ref -d 
Verwandte Themen