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/
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.
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.)
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
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
.
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
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-- all
name__. 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).
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.
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.
Erstellen Sie das neue Repo
mkdir <new-repo>
pushd <new-repo>
git init
git pull </path/to/big-repo> <name-of-new-branch>
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
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.
...
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
...
Um die neueste Version von git zu erhalten:
brew install git
Um für OS X gebräunt zu werden:
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.
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 machenDer 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.
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.
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.
Machen Sie den Klon und den Filter:
git clone --no-hardlinks foo bar; cd bar
git filter-branch --subdirectory-filter subdir/you/want
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
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 .
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
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 .
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/
Hier ist eine kleine Änderung an CoolAJ86 's "The Easy Way ™" Antwort , um mehrere Unterordner (sagen wir sub1
und sub2
) in ein neues Git-Repository zu teilen.
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 mv
command, sondern move
.
Letzte Anmerkung: Der einzigartige und große Unterschied zur Basisantwort ist die zweite Zeile des Skripts "git filter-branch...
".
Erstellen Sie das neue Repo
mkdir <new-repo>
pushd <new-repo>
git init
git pull </path/to/big-repo> <name-of-new-branch>
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
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 .
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.
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
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
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:
git filter-branch
nur Dateien in einem Unterverzeichnis, Push to new remoteEs 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:
git branch -a
git checkout --track Origin/branchABC
cp -r oldmultimod simple
cd simple
git rm otherModule1 other2 other3
git mv moduleSubdir1/* .
rmdir moduleSubdir1
git status
git remote set-url Origin http://mygithost:8080/git/our-splitted-module-repo
git remote -v
git Push
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!
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.
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:
MyTeam/mynewrepo
Bash Prompt:
$ cd c:/Dir1
$ 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.)
$ git remote add some_name [email protected]:MyTeam/mynewrepo.git
git remote add Origin etc
. funktionierte nicht, gab "remote Origin already exists
" zurück
$ git Push --progress some_name master
git splits
. Ich habe es als Git-Erweiterung erstellt, basierend auf der Lösung von jkeating . 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
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.
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
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
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
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
Öffnen Sie Git Bash.
Ändern Sie das aktuelle Arbeitsverzeichnis an den Ort, an dem Sie Ihr neues Repository erstellen möchten.
Klonen Sie das Repository, das den Unterordner enthält.
git clone OLD-REPOSITORY-FOLDER NEW-REPOSITORY-FOLDER
- Ändern Sie das aktuelle Arbeitsverzeichnis in Ihr geklontes Repository.
cd REPOSITORY-NAME
- 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
odergh-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.
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.
Ü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.
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'
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.
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
in diesem Befehl git filter-branch --Prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAME
Der BRANCH-NAME
lautet master
wenn der letzte Schritt beim Festschreiben aufgrund eines Schutzproblems fehlschlägt, folgen Sie - https://docs.gitlab.com/ee/user/project/protected_branches.html
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