2010-06-05 3 views
87

Diese Frage auf Detach subdirectory into separate Git repositoryDetach viele Unterverzeichnisse in eine neue, separate Git-Repository

basiert Statt ein einzelnes Unterverzeichnis des Abnehmens, möchte ich ein paar lösen. Zum Beispiel sieht meine aktuelle Verzeichnisbaum wie folgt aus:

/apps 
    /AAA 
    /BBB 
    /CCC 
/libs 
    /XXX 
    /YYY 
    /ZZZ 

Und ich würde dies stattdessen mag:

/apps 
    /AAA 
/libs 
    /XXX 

Das --subdirectory-filter Argument git filter-branch wird nicht funktionieren, weil es mit Ausnahme der von allem entledigt gegeben Verzeichnis beim ersten Mal es ausgeführt wird. Ich dachte, das --index-filter Argument für alle unerwünschten Dateien funktionieren würde, mit (wenn auch langweilig), aber wenn ich es versuchen laufen als einmal, erhalte ich die folgende Meldung:

Cannot create a new backup. 
A previous backup already exists in refs/original/ 
Force overwriting the backup with -f 

Irgendwelche Ideen? TIA

Antwort

17

Beantworten Sie meine eigene Frage hier ... nach viel Versuch und Irrtum.

Ich schaffte dies mit einer Kombination von git subtree und git-stitch-repo. Diese Anweisungen basiert auf:

Zuerst zog ich aus dem Verzeichnisse ich wollte in ihr eigenes separates Repository halten:

cd origRepo 
git subtree split -P apps/AAA -b aaa 
git subtree split -P libs/XXX -b xxx 

cd .. 
mkdir aaaRepo 
cd aaaRepo 
git init 
git fetch ../origRepo aaa 
git checkout -b master FETCH_HEAD 

cd .. 
mkdir xxxRepo 
cd xxxRepo 
git init 
git fetch ../origRepo xxx 
git checkout -b master FETCH_HEAD 

ich habe dann ein neues leeres Repository und importiert/stitche d die letzten beiden in sie:

cd .. 
mkdir newRepo 
cd newRepo 
git init 
git-stitch-repo ../aaaRepo:apps/AAA ../xxxRepo:libs/XXX | git fast-import 

Dies schafft zwei Zweige, master-A und master-B, die jeweils den Inhalt eines der genähten repos halten. Um sich zu kombinieren und aufzuräumen:

git checkout master-A 
git pull . master-B 
git checkout master 
git branch -d master-A 
git branch -d master-B 

Jetzt bin ich nicht ganz sicher, wie/wann dies geschieht, aber nach den ersten checkout und die pull, auf magische Weise der Code geht in den Master-Zweig (nicht nur die Einsicht auf, was los ist hier wird geschätzt!)

Alles scheint wie erwartet gearbeitet zu haben, mit der Ausnahme, dass, wenn ich die newRepo schauen durch die Geschichte begehen, gibt es Duplikate, wenn die changeset beide apps/AAA betroffen und libs/XXX. Wenn es eine Möglichkeit gibt, Duplikate zu entfernen, wäre es perfekt.

+0

Ordentlich Werkzeuge, die Sie hier finden. Insight auf "Kasse": "Git Pull" ist das gleiche wie "Git fetch && git merge". Der "Fetch" -Teil ist unschädlich, da Sie "lokal holen". Also denke ich, dass dieser Checkout-Befehl derselbe wie "git merge master-B" ist, was etwas selbstverständlicher ist. Siehe http://www.kernel.com.org/pub/software/scm/git/docs/git-pull.html – phord

+1

Leider ist das Git-Stich-Repo-Tool heute wegen der schlechten Abhängigkeiten kaputt. – Henrik

+0

@Henrik Welches Problem haben Sie genau erlebt? Es funktioniert für mich, obwohl ich 'exit PERL5LIB =" $ PERL5LIB:/usr/local/git/lib/perl5/site_perl/"' zu meiner Bash-Konfiguration hinzufügen musste, damit es Git.pm finden konnte. Dann habe ich es mit cpan installiert. –

2

Ja. Erzwingen Sie das Überschreiben der Sicherung, indem Sie das Flag -f bei nachfolgenden Aufrufen an filter-branch verwenden, um diese Warnung zu überschreiben. :) Ansonsten denke ich, du hast die Lösung (das heißt, lösche ein unerwünschtes Verzeichnis auf einmal mit filter-branch).

23

Warum möchten Sie filter-branch mehr als einmal ausführen?Sie können alles in einem Zug tun, so dass keine Notwendigkeit, es zu erzwingen (beachten Sie, dass Sie extglob für diese in der Shell aktiviert arbeiten müssen):

git filter-branch --index-filter "git rm -r -f --cached --ignore-unmatch $(ls -xd apps/!(AAA) libs/!(XXX))" --prune-empty -- --all 

Dies sollte alle Änderungen in den unerwünschten Unterverzeichnisse loszuwerden und halten sie alle Ihre Filialen und verpflichtet (es sei denn, sie werden nur Dateien in den beschnittenen Unterverzeichnisse beeinflussen, die aufgrund --prune-empty) - kein Problem mit doppelten verpflichtet usw.

nach dieser Operation die unerwünschten Verzeichnisse werden als untracked von git status aufgeführt werden.

Die $(ls ...) ist notwendig s.t. extglob wird von Ihrer Shell anstelle des Indexfilters ausgewertet, der sh builtin eval verwendet (wobei extglob nicht verfügbar ist). Weitere Informationen hierzu finden Sie unter How do I enable shell options in git?.

+1

Interessante Idee. Ich habe ein ähnliches Problem, konnte es aber nicht zur Arbeit bringen, siehe http://StackOverflow.com/Questions/8050687/How-Doi-Ineable-Shell-Options-in-Git – manol

+0

Das ist ziemlich genau das, was ich brauchte, obwohl ich sowohl Dateien als auch Ordner über mein Repository verteilt habe ... Danke :) – notlesh

+0

hm. sogar mit extglob eingeschaltet bekomme ich einen Fehler in der Nähe meiner Klammer: Syntaxfehler in der Nähe von unerwarteten Token '(' mein Befehl sieht aus wie: git filter-branch -f --index-filter" git rm -r - f --cached --ignore-unmatch src/css/themes /! (some_theme *) "--prune-empty - --all ein ls mit src/css/themes /! (some_theme *) gibt alle zurück andere themen so extglob scheint zu funktionieren ... – robdodson

87

Statt mit einer Subshell umgehen zu haben und mit ext glob (als Kynan vorgeschlagen), versuchen Sie diesen viel einfachen Ansatz:

git filter-branch --index-filter 'git rm --cached -qr --ignore-unmatch -- . && git reset -q $GIT_COMMIT -- apps/AAA libs/XXX' --prune-empty -- --all 
+0

danke David diese Lösung arbeitet mit mir im Gegensatz zu Git-Stich, die jedes commit mehr als einmal dupliziert –

+3

zusätzlich, die --ignore-unmatch-Flag sollte git rm übergeben werden, scheiterte für die erste commit für mich sonst (das Repository wurde erstellt mit git svn Klon in meinem Fall) – Pontomedon

+0

Alles, was ich von diesem Befehl bekomme, ist viele "doppelte Eltern" -Fehler. – aaa90210

5

ich einen git Filter writen habe genau dieses Problem zu lösen. Es hat den fantastischen Namen git_filter und bei GitHub hier zu finden:

https://github.com/slobobaby/git_filter

Es basiert auf der hervorragenden libgit2.

Ich musste ein großes Repository mit vielen Commits (~ 100000) aufteilen und die Lösungen auf Git Filter-Zweig dauerte mehrere Tage zu laufen. git_filter benötigt eine Minute, um das Gleiche zu tun.

+0

Gebraucht es, hat perfekt funktioniert. Vielen Dank! – Sankalp

6

Use 'git Splits' git Erweiterung

git splits ist ein Bash-Skript, das ein Wrapper um git branch-filter ist, dass ich als git Erweiterung erstellt, basierend auf jkeating's solution.

Es wurde genau für diese Situation gemacht. Versuchen Sie für Ihren Fehler, die Option git splits -f zu verwenden, um das Entfernen der Sicherung zu erzwingen. Da git splits auf einer neuen Verzweigung ausgeführt wird, wird die aktuelle Verzweigung nicht überschrieben, sodass die Sicherung nicht erforderlich ist. Siehe die Readme für weitere Details und sicher sein, dass Sie es für eine Kopie/Klon Ihres Repo verwenden (nur für den Fall!).

  1. git splits installieren.
  2. Split die Verzeichnisse in eine lokale Niederlassung #change into your repo's directory cd /path/to/repo #checkout the branch git checkout XYZ
    #split multiple directories into new branch XYZ git splits -b XYZ apps/AAA libs/ZZZ

  3. eine leere Repo irgendwo anlegen. Wir nehmen an, dass wir ein leeres Repo namens xyz auf GitHub mit dem folgenden Pfad erstellt haben: [email protected]:simpliwp/xyz.git

  4. Drücken Sie auf den neuen Repo. #add a new remote origin for the empty repo so we can push to the empty repo on GitHub git remote add origin_xyz [email protected]:simpliwp/xyz.git #push the branch to the empty repo's master branch git push origin_xyz XYZ:master

  5. Clone das neu erstellte Remote-Repo in ein neues lokales Verzeichnis
    #change current directory out of the old repo cd /path/to/where/you/want/the/new/local/repo #clone the remote repo you just pushed to git clone [email protected]:simpliwp/xyz.git

+0

Es scheint nicht möglich zu sein, Dateien zum Split hinzuzufügen und später zu aktualisieren, oder? – Alex

+0

Dies scheint zu langsam auf meinem Repo mit Tonnen von Commits zu laufen –

-3

die Sicherung in Refs vorhanden unter dem .git Verzeichnis löschen/Original wie die Nachricht vermuten lässt. Das Verzeichnis ist ausgeblendet.

14

Manuelle Schritte mit einfachen Befehlen git

Der Plan ist, einzelne Verzeichnisse in seine eigene repos zu spalten, so dass sie dann miteinander verschmelzen. Die folgenden manuellen Schritte verwenden keine Geek-to-Scripts, sondern einfach zu verstehende Befehle und können dazu beitragen, zusätzliche N Unterordner in einem anderen einzelnen Repository zusammenzuführen.

Teilen

Lassen Sie uns Ihre ursprünglichen Repo nehmen ist: original_repo

1 - Split apps:

git clone original_repo apps-repo 
cd apps-repo 
git filter-branch --prune-empty --subdirectory-filter apps master 

2 - Split Libs

git clone original_repo libs-repo 
cd libs-repo 
git filter-branch --prune-empty --subdirectory-filter libs master 

C wenn Sie mehr als 2 Ordner haben. Jetzt sollten Sie zwei neue und temporäre Git-Repositories haben.

Conquer von Anwendungen und Libs Merging

3 - die neue Repo-Marke vorbereiten:

mkdir my-desired-repo 
cd my-desired-repo 
git init 

Und Sie werden mindestens eine verpflichten zu machen brauchen. Wenn die folgenden drei Zeilen übersprungen werden soll, wird Ihre erste Repo sofort erscheinen im Root-Verzeichnis Ihrer Repo:

touch a_file_and_make_a_commit 
git add a_file_and_make_a_commit 
git commit -am "at least one commit is needed for it to work" 

Mit der temporären Datei commited, merge Befehl in späteren Abschnitt wird wie erwartet anhalten.

4 - erste Merge apps Repo:

git remote add apps-repo ../apps-repo 
git fetch apps-repo 
git merge -s ours --no-commit apps-repo/master 
git read-tree --prefix=apps -u apps-repo/master 
git commit -m "import apps" 

Jetzt sollten Sie apps Verzeichnis in Ihrem neuen Repository sehen. git log sollte alle relevanten historischen Commit-Nachrichten anzeigen.

5 - Merge Libs Repo nächste in der gleichen Art und Weise:

git remote add libs-repo ../libs-repo 
git fetch libs-repo 
git merge -s ours --no-commit libs-repo/master 
git read-tree --prefix=libs -u libs-repo/master 
git commit -m "import libs" 

weiter, wenn Sie mehr als 2 repos zu fusionieren haben.

Referenz: Merge a subdirectory of another repository with git

+1

Seit Git 2.9 müssen Sie --allow-nicht verwandten Geschichten auf die Zusammenführungsbefehle verwenden. Ansonsten scheint das gut für mich zu funktionieren. – Chris

Verwandte Themen