webentwicklung-frage-antwort-db.com.de

Trennen Sie das Unterverzeichnis in ein separates Git-Repository

Ich habe ein Git Repository, das eine Reihe von Unterverzeichnissen enthält. Jetzt habe ich festgestellt, dass eines der Unterverzeichnisse nicht mit dem anderen zusammenhängt und in einem separaten Repository getrennt werden sollte.

Wie kann ich dies tun, während der Verlauf der Dateien im Unterverzeichnis beibehalten wird?

Ich vermute, ich könnte einen Klon erstellen und die unerwünschten Teile von jedem Klon entfernen, aber ich denke, dies würde mir den vollständigen Baum geben, wenn Sie eine ältere Revision auschecken Zwei Repositorys haben keine gemeinsame Historie.

Um es klar zu machen, habe ich folgende Struktur:

XYZ/
    .git/
    XY1/
    ABC/
    XY2/

Aber ich hätte das lieber:

XYZ/
    .git/
    XY1/
    XY2/
ABC/
    .git/
    ABC/
1643
matli

Update : Dieser Vorgang ist so häufig, dass das Git-Team ihn mit einem neuen Tool, git subtree, viel einfacher gemacht hat. Siehe hier: nterverzeichnis Detach (move) in separates Git-Repository


Sie möchten Ihr Repository klonen und dann git filter-branch verwenden, um alles außer dem Unterverzeichnis zu markieren, das in Ihrem neuen Repository müllsammelbar sein soll.

  1. So klonen Sie Ihr lokales Repository:

    git clone /XYZ /ABC
    

    (Hinweis: Das Repository wird mithilfe von Hardlinks geklont. Dies ist jedoch kein Problem, da die Hardlinks selbst nicht geändert werden. Es werden neue Dateien erstellt.)

  2. Behalten wir nun die interessanten Zweige bei, die wir ebenfalls umschreiben möchten, und entfernen Sie dann den Origin, um ein Verschieben zu vermeiden und sicherzustellen, dass alte Commits nicht vom Origin referenziert werden:

    cd /ABC
    for i in branch1 br2 br3; do git branch -t $i Origin/$i; done
    git remote rm Origin
    

    oder für alle entfernten Niederlassungen:

    cd /ABC
    for i in $(git branch -r | sed "s/.*Origin\///"); do git branch -t $i Origin/$i; done
    git remote rm Origin
    
  3. Jetzt möchten Sie möglicherweise auch Tags entfernen, die keine Beziehung zum Unterprojekt haben. Sie können dies auch später tun, müssen Ihr Repo jedoch möglicherweise erneut beschneiden. Ich habe dies nicht getan und einen WARNING: Ref 'refs/tags/v0.1' is unchanged für alle Tags erhalten (da sie nicht mit dem Teilprojekt zusammenhängen). Außerdem wird nach dem Entfernen solcher Tags mehr Speicherplatz zurückgefordert. Anscheinend sollte git filter-branch andere Tags umschreiben können, aber ich konnte dies nicht verifizieren. Wenn Sie alle Tags entfernen möchten, verwenden Sie git tag -l | xargs git tag -d.

  4. Verwenden Sie dann filter-branch und reset, um die anderen Dateien auszuschließen, damit sie gelöscht werden können. Fügen wir auch --tag-name-filter cat --Prune-empty hinzu, um leere Commits zu entfernen und Tags neu zu schreiben (beachten Sie, dass dies die Signatur entfernen muss):

    git filter-branch --tag-name-filter cat --Prune-empty --subdirectory-filter ABC -- --all
    

    oder alternativ, um nur den Zweig HEAD umzuschreiben und Tags und andere Zweige zu ignorieren:

    git filter-branch --tag-name-filter cat --Prune-empty --subdirectory-filter ABC HEAD
    
  5. Löschen Sie dann die Backup-Rückmeldungen, damit der Speicherplatz wirklich zurückgefordert werden kann (obwohl der Vorgang jetzt destruktiv ist).

    git reset --hard
    git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
    git reflog expire --expire=now --all
    git gc --aggressive --Prune=now
    

    und jetzt haben Sie ein lokales Git-Repository des ABC-Unterverzeichnisses mit all seiner Geschichte erhalten.

Hinweis: Für die meisten Verwendungszwecke sollte git filter-branch tatsächlich den hinzugefügten Parameter -- --all haben. Ja das ist wirklich --space-- allname__. Dies muss der letzte Parameter für den Befehl sein. Wie Matli herausgefunden hat, bleiben die Projektzweige und Tags im neuen Repo enthalten.

Bearbeiten: Verschiedene Vorschläge aus den Kommentaren unten wurden aufgenommen, um beispielsweise sicherzustellen, dass das Repository tatsächlich verkleinert ist (was vorher nicht immer der Fall war).

1190
Paul

Der einfache Weg ™

Es stellt sich heraus, dass dies eine so übliche und nützliche Praxis ist, dass die Overlords von git es wirklich einfach gemacht haben, aber Sie müssen eine neuere Version von git haben (> = 1.7.11 Mai 2012). Im Anhang finden Sie Informationen zur Installation des neuesten Git. Außerdem gibt es ein real-world Beispiel in der Komplettlösung.

  1. Bereiten Sie das alte Repo vor

    pushd <big-repo>
    git subtree split -P <name-of-folder> -b <name-of-new-branch>
    popd
    

    Hinweis:<name-of-folder> darf KEINE führenden oder nachgestellten Zeichen enthalten. Zum Beispiel muss der Ordner subproject als subproject übergeben werden, NOT ./subproject/

    Hinweis für Windows-Benutzer: Wenn Ihre Ordnertiefe> 1 ist, muss <name-of-folder> das * nix-Format für das Ordner-Trennzeichen (/) haben. Zum Beispiel muss der Ordner mit dem Namen path1\path2\subproject als path1/path2/subproject übergeben werden.

  2. Erstellen Sie das neue Repo

    mkdir <new-repo>
    pushd <new-repo>
    
    git init
    git pull </path/to/big-repo> <name-of-new-branch>
    
  3. Verknüpfen Sie das neue Repo mit Github oder wo auch immer

    git remote add Origin <[email protected]:my-user/new-repo.git>
    git Push Origin -u master
    
  4. Aufräumen, falls gewünscht

    popd # get out of <new-repo>
    pushd <big-repo>
    
    git rm -rf <name-of-folder>
    

    Note: Dadurch werden alle historischen Verweise im Repository belassen. Siehe Anhang unten, wenn Sie tatsächlich die Sorge haben, ein Kennwort übergeben zu haben, oder die Dateigröße Ihres .git-Ordners verringern müssen.

...

Komplettlösung

Dies sind die gleichen Schritte wie oben, folgen jedoch genau meinen Schritten für mein Repository, anstatt <meta-named-things> zu verwenden.

Hier ist ein Projekt, das ich zur Implementierung von JavaScript-Browsermodulen im Knoten habe:

tree ~/Code/node-browser-compat

node-browser-compat
├── ArrayBuffer
├── Audio
├── Blob
├── FormData
├── atob
├── btoa
├── location
└── navigator

Ich möchte einen einzelnen Ordner, btoa, in ein separates Git-Repository aufteilen

pushd ~/Code/node-browser-compat/
git subtree split -P btoa -b btoa-only
popd

Ich habe jetzt einen neuen Zweig, btoa-only, der nur für btoa ein Commit hat, und ich möchte ein neues Repository erstellen.

mkdir ~/Code/btoa/
pushd ~/Code/btoa/
git init
git pull ~/Code/node-browser-compat btoa-only

Als Nächstes erstelle ich ein neues Repo auf Github oder Bitbucket oder was auch immer und füge es als Origin hinzu (übrigens, "Origin" ist nur eine Konvention und nicht Teil des Befehls - Sie könnten es "Remote-Server" oder was auch immer Sie möchten nennen)

git remote add Origin [email protected]:node-browser-compat/btoa.git
git Push Origin -u master

Glücklicher Tag!

Hinweis: Wenn Sie ein Repo mit README.md, .gitignore und LICENSE erstellt haben, müssen Sie zuerst ziehen:

git pull Origin -u master
git Push Origin -u master

Zum Schluss möchte ich den Ordner aus dem größeren Repo entfernen

git rm -rf btoa

...

Blinddarm

Letzter Git auf OS X

Um die neueste Version von git zu erhalten:

brew install git

Um für OS X gebräunt zu werden:

http://brew.sh

Letzter Git auf Ubuntu

Sudo apt-get update
Sudo apt-get install git
git --version

Wenn das nicht funktioniert (Sie haben eine sehr alte Version von Ubuntu), versuchen Sie es

Sudo add-apt-repository ppa:git-core/ppa
Sudo apt-get update
Sudo apt-get install git

Wenn das immer noch nicht funktioniert, versuchen Sie es

Sudo chmod +x /usr/share/doc/git/contrib/subtree/git-subtree.sh
Sudo ln -s \
/usr/share/doc/git/contrib/subtree/git-subtree.sh \
/usr/lib/git-core/git-subtree

Vielen Dank an rui.araujo von den Kommentaren.

ihre Geschichte löschen

Standardmäßig werden Dateien nicht aus git entfernt, sondern nur, dass sie nicht mehr vorhanden sind. Wenn Sie die historischen Referenzen tatsächlich entfernen möchten (d. H. Sie haben ein Kennwort festgelegt), müssen Sie Folgendes tun:

git filter-branch --Prune-empty --tree-filter 'rm -rf <name-of-folder>' HEAD

Danach können Sie überprüfen, ob Ihre Datei oder Ihr Ordner überhaupt nicht mehr im git-Verlauf angezeigt wird

git log -- <name-of-folder> # should show nothing

Sie können jedoch keine "Push" -Löschungen an github und dergleichen vornehmen. Wenn Sie es versuchen, erhalten Sie eine Fehlermeldung und Sie müssen git pull, bevor Sie git Push können - und dann haben Sie wieder alles im Verlauf.

Wenn Sie also den Verlauf aus dem "Origin" löschen möchten, dh aus Github, Bitbucket usw. löschen möchten, müssen Sie das Repo löschen und eine bereinigte Kopie des Repos erneut drücken. Aber warte - es gibt noch mehr! - Wenn Sie wirklich daran interessiert sind, ein Passwort oder ähnliches loszuwerden, müssen Sie die Sicherung bereinigen (siehe unten).

.git kleiner machen

Der zuvor erwähnte Befehl zum Löschen des Verlaufs hinterlässt immer noch eine Reihe von Backup-Dateien - weil git Ihnen sehr hilft, Ihr Repo nicht aus Versehen zu ruinieren. Letztendlich werden verwaiste Dateien über die Tage und Monate hinweg gelöscht. Sie werden jedoch eine Zeitlang dort belassen, falls Sie feststellen, dass Sie versehentlich etwas gelöscht haben, das Sie nicht wollten.

Wenn Sie also wirklich den Papierkorb leeren wollen, um die Klongröße eines Repos sofort zu reduzieren, müssen Sie all diese wirklich seltsamen Dinge tun:

rm -rf .git/refs/original/ && \
git reflog expire --all && \
git gc --aggressive --Prune=now

git reflog expire --all --expire-unreachable=0
git repack -A -d
git Prune

Ich würde jedoch empfehlen, diese Schritte nicht auszuführen, es sei denn, Sie wissen, dass Sie dies tun müssen - nur für den Fall, dass Sie das falsche Unterverzeichnis beschnitten haben, wissen Sie? Die Sicherungsdateien sollten beim Push des Repos nicht geklont werden, sie befinden sich nur in Ihrer lokalen Kopie.

Kredit

1189
CoolAJ86

Paul's Antwort erstellt ein neues Repository mit/ABC, entfernt/ABC jedoch nicht aus/XYZ. Der folgende Befehl entfernt/ABC aus/XYZ:

git filter-branch --tree-filter "rm -rf ABC" --Prune-empty HEAD

Testen Sie es natürlich zuerst in einem Repository "clone --no-hardlinks", und folgen Sie den Paul-Listen von reset, gc und Prune.

131
pgs

Ich habe festgestellt, dass Sie nach dem Schritt filter-branch etwas mehr Arbeit ausführen müssen, um den alten Verlauf ordnungsgemäß aus dem neuen Repository zu löschen.

  1. Machen Sie den Klon und den Filter:

    git clone --no-hardlinks foo bar; cd bar
    git filter-branch --subdirectory-filter subdir/you/want
    
  2. Entfernen Sie jeden Verweis auf die alte Geschichte. "Origin" hat Ihren Klon im Auge behalten, und "Original" ist der Ort, an dem der Filterzweig das alte Zeug speichert:

    git remote rm Origin
    git update-ref -d refs/original/refs/heads/master
    git reflog expire --expire=now --all
    
  3. Sogar jetzt könnte Ihr Verlauf in einer Packdatei stecken, die fsck nicht berührt. Zerreißen Sie es in Stücke, erstellen Sie eine neue Packdatei und löschen Sie nicht verwendete Objekte:

    git repack -ad
    

Es gibt eine Erklärung dazu im Handbuch zum Filterzweig .

94
Josh Lee

Edit: Bash-Skript hinzugefügt.

Die hier gegebenen Antworten haben für mich nur teilweise funktioniert; Viele große Dateien blieben im Cache. Was hat endlich funktioniert (nach Stunden in #git auf freenode):

git clone --no-hardlinks file:///SOURCE /tmp/blubb
cd blubb
git filter-branch --subdirectory-filter ./PATH_TO_EXTRACT  --Prune-empty --tag-name-filter cat -- --all
git clone file:///tmp/blubb/ /tmp/blooh
cd /tmp/blooh
git reflog expire --expire=now --all
git repack -ad
git gc --Prune=now

Bei den vorherigen Lösungen betrug die Repository-Größe etwa 100 MB. Dies hat es auf 1,7 MB reduziert. Vielleicht hilft es jemandem :)


Das folgende Bash-Skript automatisiert die Aufgabe:

!/bin/bash

if (( $# < 3 ))
then
    echo "Usage:   $0 </path/to/repo/> <directory/to/extract/> <newName>"
    echo
    echo "Example: $0 /Projects/42.git first/answer/ firstAnswer"
    exit 1
fi


clone=/tmp/${3}Clone
newN=/tmp/${3}

git clone --no-hardlinks file://$1 ${clone}
cd ${clone}

git filter-branch --subdirectory-filter $2  --Prune-empty --tag-name-filter cat -- --all

git clone file://${clone} ${newN}
cd ${newN}

git reflog expire --expire=now --all
git repack -ad
git gc --Prune=now
39

Dies ist nicht mehr so ​​komplex, dass Sie einfach den Befehl git filter-branch für einen Klon Ihres Repos verwenden können, um die nicht gewünschten Unterverzeichnisse zu löschen, und dann auf die neue Fernbedienung drücken.

git filter-branch --Prune-empty --subdirectory-filter <YOUR_SUBDIR_TO_KEEP> master
git Push <MY_NEW_REMOTE_URL> -f .
22
jeremyjjbrown

Update: Das git-subtree-Modul war so nützlich, dass das git-Team es in den Kern zog und es git subtree machte. Siehe hier: Unterverzeichnis in separates Git-Repository trennen (verschieben)

git-subtree kann hierfür nützlich sein

http://github.com/apenwarr/git-subtree/blob/master/git-subtree.txt (nicht mehr empfohlen)

http://psionides.jogger.pl/2010/02/04/sharing-code-between-projects-with-git-subtree/

19
D W

Hier ist eine kleine Änderung an CoolAJ86 's "The Easy Way ™" Antwort , um mehrere Unterordner (sagen wir sub1und sub2) in ein neues Git-Repository zu teilen.

The Easy Way ™ (mehrere Unterordner)

  1. Bereiten Sie das alte Repo vor

    pushd <big-repo>
    git filter-branch --tree-filter "mkdir <name-of-folder>; mv <sub1> <sub2> <name-of-folder>/" HEAD
    git subtree split -P <name-of-folder> -b <name-of-new-branch>
    popd
    

    Hinweis:<name-of-folder> darf KEINE führenden oder nachgestellten Zeichen enthalten. Zum Beispiel muss der Ordner subproject als subproject übergeben werden, NOT ./subproject/

    Hinweis für Windows-Benutzer: Wenn Ihre Ordnertiefe> 1 ist, muss <name-of-folder> das * nix-Format für das Ordner-Trennzeichen (/) haben. Zum Beispiel muss der Ordner mit dem Namen path1\path2\subproject als path1/path2/subproject übergeben werden. Verwenden Sie nicht mvcommand, sondern move.

    Letzte Anmerkung: Der einzigartige und große Unterschied zur Basisantwort ist die zweite Zeile des Skripts "git filter-branch...".

  2. Erstellen Sie das neue Repo

    mkdir <new-repo>
    pushd <new-repo>
    
    git init
    git pull </path/to/big-repo> <name-of-new-branch>
    
  3. Verknüpfen Sie das neue Repo mit Github oder wo auch immer

    git remote add Origin <[email protected]:my-user/new-repo.git>
    git Push Origin -u master
    
  4. Aufräumen, falls gewünscht

    popd # get out of <new-repo>
    pushd <big-repo>
    
    git rm -rf <name-of-folder>
    

    Note: Damit bleiben alle historischen Verweise im Repository erhalten. Sehen Sie in der Originalantwort den Appendix, wenn Sie wirklich daran interessiert sind, ein Kennwort festgelegt zu haben, oder die Dateigröße Ihres .git-Ordners verringern müssen .

16
Anthony O.

Die ursprüngliche Frage möchte, dass aus XYZ/ABC/(* -Dateien) ABC/ABC/(* -Dateien) werden. Nachdem ich die akzeptierte Antwort für meinen eigenen Code implementiert hatte, stellte ich fest, dass XYZ/ABC/(* -Dateien) tatsächlich in ABC/(* -Dateien) geändert wird. Die Filter-Branch-Manpage sagt sogar: 

Das Ergebnis enthält dieses Verzeichnis (und nur das) als Projektwurzel . " 

Mit anderen Worten, der oberste Ordner "nach oben" wird um eine Ebene erhöht. Das ist eine wichtige Unterscheidung, weil ich zum Beispiel in meiner Geschichte einen Ordner auf oberster Ebene umbenannt habe. Durch die Förderung von Ordnern "auf" einer Ebene verliert git die Kontinuität bei dem Commit, bei dem ich die Umbenennung vorgenommen habe.

I lost contiuity after filter-branch

Meine Antwort auf die Frage ist, dass Sie zwei Kopien des Repositorys erstellen und die Ordner, die Sie behalten möchten, manuell löschen. Die Manpage unterstützt mich dabei:

[...] vermeiden Sie die Verwendung dieses Befehls, wenn ein einfaches Commit ausreicht, um Ihr Problem zu beheben

11
MM.

Um zu Pauls Antwort hinzuzufügen, habe ich festgestellt, dass ich zur endgültigen Wiederherstellung des Speicherplatzes HEAD in ein sauberes Repository verschieben muss und die Größe des Verzeichnisses .git/objects/pack verringert.

d.h.

 $ mkdir ... ABC.git 
 $ cd ... ABC.git 
 $ git init --bare 

Nach dem gc Prune mache auch:

 $ git Push ... ABC.git HEAD 

Dann kannst du es tun

 $ git clone ... ABC.git 

und die Größe von ABC/.git ist reduziert

Tatsächlich sind einige der zeitaufwendigen Schritte (z. B. git gc) mit dem Push-to-Clean-Repository nicht erforderlich, d. H .:

 $ git Klon --no-hardlinks/XYZ /ABC
$ git filter-branch - Unterverzeichnis-Filter ABC HEAD 
 $ git reset --hard 
 $ git Push ... ABC. git HEAD 
7
Case Larsen

Der richtige Weg ist jetzt der folgende:

git filter-branch --Prune-empty --subdirectory-filter FOLDER_NAME [first_branch] [another_branch]

GitHub hat jetzt sogar kleiner Artikel über solche Fälle.

Achten Sie jedoch darauf, dass Sie Ihr ursprüngliches Repo zuerst in ein separates Verzeichnis klonen (da dadurch alle Dateien und anderen Verzeichnisse gelöscht würden und Sie wahrscheinlich mit ihnen arbeiten müssen).

Ihr Algorithmus sollte also sein:

  1. klonen Sie Ihr Remote Repo in ein anderes Verzeichnis
  2. verwenden Sie git filter-branch nur Dateien in einem Unterverzeichnis, Push to new remote
  3. erstellen Sie ein Commit, um dieses Unterverzeichnis von Ihrem ursprünglichen Remote-Repo zu entfernen
6

Es scheint, dass die meisten (alle?) Antworten hier auf irgendeine Form von git filter-branch --subdirectory-filter und seiner Sorte angewiesen sind. Dies kann "meistens" funktionieren, jedoch in einigen Fällen, beispielsweise wenn Sie den Ordner umbenannt haben, z.

 ABC/
    /move_this_dir # did some work here, then renamed it to

ABC/
    /move_this_dir_renamed

Wenn Sie einen normalen Git-Filterstil verwenden, um "move_me_renamed" zu extrahieren, verlieren Sie den Dateiänderungsverlauf, der vor dem Zeitpunkt von move_this_dir ( ref ) aufgetreten ist.

Es scheint also, dass die einzige Möglichkeit, den Änderungsverlauf von all wirklich zu behalten (wenn Ihr Fall ein Fall wie dieser ist), im Wesentlichen das Repository zu kopieren (ein neues Repo erstellen, das als Ursprung festlegen), dann alles andere nuke und benennen Sie das Unterverzeichnis wie folgt in das übergeordnete Verzeichnis um:

  1. Klonen Sie das Multi-Modul-Projekt lokal
  2. Branchen - prüfen, was da ist: git branch -a
  3. Führen Sie für jeden Zweig einen Checkout aus, der in die Aufteilung aufgenommen werden soll, um eine lokale Kopie auf Ihrer Workstation zu erhalten: git checkout --track Origin/branchABC
  4. Erstellen Sie eine Kopie in einem neuen Verzeichnis: cp -r oldmultimod simple
  5. Gehen Sie in die neue Projektkopie: cd simple
  6. Entfernen Sie die anderen Module, die in diesem Projekt nicht benötigt werden: 
  7. git rm otherModule1 other2 other3
  8. Jetzt bleibt nur noch das Unterverzeichnis des Zielmoduls 
  9. Entfernen Sie das Modul-Unterverzeichnis, damit der Modulstamm zum neuen Projektstamm wird
  10. git mv moduleSubdir1/* .
  11. Löschen Sie das Relikt-Unterverzeichnis: rmdir moduleSubdir1
  12. Überprüfen Sie die Änderungen an einem beliebigen Punkt: git status
  13. Erstellen Sie das neue Git-Repo und kopieren Sie dessen URL, um dieses Projekt darin zu zeigen:
  14. git remote set-url Origin http://mygithost:8080/git/our-splitted-module-repo
  15. Stellen Sie sicher, dass dies gut ist: git remote -v
  16. Übertragen Sie die Änderungen bis zum Remote-Repo: git Push
  17. Gehen Sie zum Remote-Repo und prüfen Sie, ob alles vorhanden ist
  18. Wiederholen Sie es für jeden anderen Zweig, der benötigt wird: git checkout branch2

Dies folgt das github-Dokument "Einen Unterordner in ein neues Repository aufteilen" Schritte 6 bis 11, um das Modul in ein neues Repo zu verschieben.

Dies spart Ihnen keinen Speicherplatz in Ihrem .git-Ordner, behält jedoch Ihren gesamten Änderungsverlauf für diese Dateien bei, auch wenn sie umbenannt wird. Und das ist es vielleicht nicht wert, wenn nicht "viel" Geschichte verloren geht usw. Aber zumindest verlieren Sie garantiert keine älteren Commits!

5
rogerdpack

Ich hatte genau dieses Problem, aber alle Standardlösungen auf Basis von git filter-branch waren extrem langsam. Wenn Sie ein kleines Repository haben, ist dies möglicherweise kein Problem, es war für mich. Ich habe ein weiteres git-Filterprogramm auf Basis von libgit2 geschrieben, das als ersten Schritt Verzweigungen für jede Filterung des primären Repositorys erstellt und diese dann als nächstes in saubere Repositorys pusht. Auf meinem Repository (500 MB 100000 Commits) dauerte die Standardgit-Filter-Branch-Methode Tage. Mein Programm dauert Minuten, um dieselbe Filterung durchzuführen.

Es hat den sagenhaften Namen von git_filter und lebt hier: 

https://github.com/slobobaby/git_filter

auf GitHub.

Ich hoffe es ist jemandem nützlich.

4
slobobaby

Was es wert ist, hier ist, wie man GitHub auf einem Windows-Rechner verwendet. Angenommen, Sie haben ein geklontes Repo in C:\dir1. Die Verzeichnisstruktur sieht folgendermaßen aus: C:\dir1\dir2\dir3. Das dir3-Verzeichnis möchte ich als neues separates Repo verwenden. 

Github:

  1. Erstellen Sie Ihr neues Repository: MyTeam/mynewrepo

Bash Prompt:

  1. $ cd c:/Dir1
  2. $ git filter-branch --Prune-empty --subdirectory-filter dir2/dir3 HEAD
    Zurückgegeben: Ref 'refs/heads/master' was rewritten (bei fyi: dir2/dir3 ist die Groß- und Kleinschreibung zu beachten.)

  3. $ git remote add some_name [email protected]:MyTeam/mynewrepo.git
    git remote add Origin etc. funktionierte nicht, gab "remote Origin already exists" zurück

  4. $ git Push --progress some_name master 

4
James Lawruk

Der einfachere Weg

  1. install git splits . Ich habe es als Git-Erweiterung erstellt, basierend auf der Lösung von jkeating
  2. Teilen Sie die Verzeichnisse in einen lokalen Zweig auf #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 XY1 XY2

  3. Erstellen Sie irgendwo ein leeres Repo. Wir gehen davon aus, dass wir auf GitHub ein leeres Repo namens xyz erstellt haben, das den Pfad: [email protected]:simpliwp/xyz.git hat.

  4. Zum neuen Repo wechseln . #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. Klonen Sie 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

3
AndrewD

Verwenden Sie diesen Filterbefehl, um ein Unterverzeichnis zu entfernen, während Sie Ihre Tags und Verzweigungen beibehalten:

git filter-branch --index-filter \
"git rm -r -f --cached --ignore-unmatch DIR" --Prune-empty \
--tag-name-filter cat -- --all
3
cmcginty

Ich empfehle GitHub's Anleitung, um Unterordner in ein neues Repository zu unterteilen . Die Schritte sind ähnlich wie Pauls Antwort , aber ich fand ihre Anweisungen leichter verständlich.

Ich habe die Anweisungen so geändert, dass sie sich für ein lokales Repository und nicht für ein auf GitHub gehostetes Archiv bewerben.


Aufteilen eines Unterordners in ein neues Repository

  1. Öffnen Sie Git Bash.

  2. Ändern Sie das aktuelle Arbeitsverzeichnis an den Ort, an dem Sie Ihr neues Repository erstellen möchten.

  3. Klonen Sie das Repository, das den Unterordner enthält.

git clone OLD-REPOSITORY-FOLDER NEW-REPOSITORY-FOLDER
  1. Ändern Sie das aktuelle Arbeitsverzeichnis in Ihr geklontes Repository.

cd REPOSITORY-NAME
  1. Um den Unterordner aus den restlichen Dateien im Repository herauszufiltern, führen Sie git filter-branch aus und geben Sie folgende Informationen an:
    • FOLDER-NAME: Der Ordner in Ihrem Projekt, in dem Sie ein separates Repository von ..__ erstellen möchten.
      • Tipp: Windows-Benutzer sollten / verwenden, um Ordner zu begrenzen.
    • BRANCH-NAME: Der Standardzweig für Ihr aktuelles Projekt, z. B. master oder gh-pages.

git filter-branch --Prune-empty --subdirectory-filter FOLDER-NAME  BRANCH-NAME 
# Filter the specified branch in your directory and remove empty commits
Rewrite 48dc599c80e20527ed902928085e7861e6b3cbe6 (89/89)
Ref 'refs/heads/BRANCH-NAME' was rewritten

Wie ich oben erwähnt , musste ich die umgekehrte Lösung verwenden (alle Commits löschen, ohne meinen dir/subdir/targetdir zu berühren), die ziemlich gut zu funktionieren schien, um etwa 95% der Commits zu entfernen (wie gewünscht). Es gibt jedoch noch zwei kleine Probleme.

FIRST, filter-branch löste auf Hochtouren Commits, die Code einführen oder ändern, aber anscheinend Merge Commits befinden sich im Gitiverse unter seiner Station.

Dies ist ein kosmetisches Problem, mit dem ich wahrscheinlich leben kann (er sagt ... mit abgewandten Augen langsam zurückweichen) .

SEKUNDEN die wenigen verbleibenden Commits sind so ziemlich ALLE dupliziert! Ich habe anscheinend eine zweite, redundante Zeitachse erhalten, die sich über die gesamte Projektgeschichte erstreckt. Das Interessante (was Sie auf dem Bild unten sehen können) ist, dass sich meine drei lokalen Niederlassungen nicht alle auf der gleichen Zeitachse befinden (weshalb es auf jeden Fall existiert und nicht nur Müll gesammelt wird).

Das einzige, was ich mir vorstellen kann, ist, dass es sich bei einem der gelöschten Commits möglicherweise um das einzelne Merge-Commit handelt, das filter-branch tatsächlich löschte und das die parallele Timeline als erstellt hat Jeder jetzt nicht zusammengeschlossene Strang nahm eine eigene Kopie der Commits. ( Achselzucken Wo ist mein TARDiS?) Ich bin mir ziemlich sicher, dass ich dieses Problem beheben kann, obwohl ich wirklich gerne verstehen würde wie es passiert ist.

Im Falle von verrücktem mergefest-O-RAMA werde ich diesen wahrscheinlich in Ruhe lassen, da er sich so fest in meiner Commit-Geschichte verankert hat - was mich bedroht, wenn ich näher komme -, dass es nicht wirklich verursacht keine nicht-kosmetischen Probleme und weil es in Tower.app ziemlich hübsch ist.

3
Jay Allen

Möglicherweise benötigen Sie vor der Speicherbereinigung etwas wie "git reflog expire - now = all -", um die Dateien tatsächlich zu bereinigen. git filter-branch entfernt lediglich Verweise in der Historie, entfernt jedoch nicht die Reflog-Einträge, die die Daten enthalten. Testen Sie dies natürlich zuerst.

Meine Festplattennutzung sank dabei drastisch, obwohl meine Ausgangsbedingungen etwas anders waren. Vielleicht - subdirectory-filter negiert dieses Bedürfnis, aber ich bezweifle es.

2

Überprüfen Sie das git_split-Projekt unter https://github.com/vangorra/git_split

Verwandeln Sie git-Verzeichnisse in ihre eigenen Repositorys an ihrem eigenen Ort. Kein witziges Geschäft. Dieses Skript übernimmt ein vorhandenes Verzeichnis in Ihrem Git-Repository und wandelt dieses Verzeichnis in ein eigenständiges Repository um. Dabei wird der gesamte Änderungsverlauf für das von Ihnen angegebene Verzeichnis übernommen. 

./git_split.sh <src_repo> <src_branch> <relative_dir_path> <dest_repo>
        src_repo  - The source repo to pull from.
        src_branch - The branch of the source repo to pull from. (usually master)
        relative_dir_path   - Relative path of the directory in the source repo to split.
        dest_repo - The repo to Push to.
2
vangorra

Fügen Sie dies in Ihre gitconfig ein:

reduce-to-subfolder = !sh -c 'git filter-branch --tag-name-filter cat --Prune-empty --subdirectory-filter cookbooks/Unicorn HEAD && git reset --hard && git for-each-ref refs/original/ | cut -f 2 | xargs -n 1 git update-ref -d && git reflog expire --expire=now --all && git gc --aggressive --Prune=now && git remote rm Origin'
1
grosser

Ich bin sicher, git subtree ist alles in Ordnung und wunderbar, aber meine Unterverzeichnisse von git verwalteter Code, die ich verschieben wollte, waren alles in Eclipse. Wenn Sie also egit verwenden, ist es schmerzhaft einfach. Nehmen Sie das Projekt Sie möchten es verschieben und im Team zusammenarbeiten -> die Verbindung trennen und dann das Team -> am neuen Speicherort freigeben. Es wird standardmäßig versucht, den alten Repo-Speicherort zu verwenden, Sie können jedoch die Auswahl für die Verwendung vorhandener Objekte deaktivieren und den neuen Speicherort auswählen, um ihn zu verschieben.

1
stu

Sie können das https://help.github.com/enterprise/2.15/user/articles/splitting-a-subfolder-out-into-a-new-repository/ ganz einfach ausprobieren. _

Das hat bei mir funktioniert. Die Probleme, mit denen ich in den oben genannten Schritten konfrontiert war, sind 

  1. in diesem Befehl git filter-branch --Prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAME Der BRANCH-NAME lautet master

  2. wenn der letzte Schritt beim Festschreiben aufgrund eines Schutzproblems fehlschlägt, folgen Sie - https://docs.gitlab.com/ee/user/project/protected_branches.html

0

Ich habe eine recht einfache Lösung gefunden. Die Idee ist, das Repository zu kopieren und dann nur unnötige Teile zu entfernen. So funktioniert es:

1) Klonen Sie ein Repository, das Sie teilen möchten

git clone [email protected]:testrepo/test.git

2) In Git-Ordner verschieben

cd test/

2) Entfernen Sie nicht benötigte Ordner und legen Sie sie fest

rm -r ABC/
git add .
enter code here
git commit -m 'Remove ABC'

3) Entfernen Sie nicht benötigte Ordner aus dem Verlauf mit BFG

cd ..
Java -jar bfg.jar --delete-folders "{ABC}" test
cd test/
git reflog expire --expire=now --all && git gc --Prune=now --aggressive

für mehrere Ordner können Sie ein Komma verwenden

Java -jar bfg.jar --delete-folders "{ABC1,ABC2}" metric.git

4) Vergewissern Sie sich, dass der Verlauf nicht die gerade gelöschten Dateien/Ordner enthält

git log --diff-filter=D --summary | grep delete

5) Jetzt haben Sie ein sauberes Repository ohne ABC. Verschieben Sie es einfach in neues Origin

remote add Origin [email protected]:username/new_repo
git Push -u Origin master

Das ist es. Sie können die Schritte wiederholen, um ein anderes Repository zu erhalten.

entfernen Sie einfach XY1, XY2 und benennen Sie XYZ -> ABC in Schritt 3 um

0