Eine Möglichkeit, dies zu tun, ist die Umkehrung - entfernen Sie alles außer der Datei, die Sie behalten möchten.
Erstellen Sie im Grunde genommen eine Kopie des Repositorys und git filter-branch
entfernen Sie dann alles außer den Dateien / Ordnern, die Sie behalten möchten.
Zum Beispiel habe ich ein Projekt, aus dem ich die Datei tvnamer.py
in ein neues Repository extrahieren möchte :
git filter-branch --tree-filter 'for f in *; do if [ $f != "tvnamer.py" ]; then rm -rf $f; fi; done' HEAD
Damit wird git filter-branch --tree-filter
jedes Commit durchlaufen, der Befehl ausgeführt und der resultierende Verzeichnisinhalt erneut festgeschrieben. Dies ist äußerst destruktiv (Sie sollten dies also nur für eine Kopie Ihres Repositorys tun!) Und kann eine Weile dauern (ca. 1 Minute bei einem Repository mit 300 Commits und ca. 20 Dateien).
Der obige Befehl führt nur das folgende Shell-Skript für jede Revision aus, das Sie natürlich ändern müssten (damit Ihr Unterverzeichnis stattdessen ausgeschlossen wird tvnamer.py
):
for f in *; do
if [ $f != "tvnamer.py" ]; then
rm -rf $f;
fi;
done
Das größte offensichtliche Problem ist, dass alle Festschreibungsnachrichten hinterlassen werden, auch wenn sie nicht mit der verbleibenden Datei zusammenhängen. Das Skript git-remove-empty-commits behebt dieses Problem.
git filter-branch --commit-filter 'if [ z$1 = z`git rev-parse $3^{tree}` ]; then skip_commit "$@"; else git commit-tree "$@"; fi'
Sie müssen das -f
Force-Argument verwenden, das filter-branch
erneut ausgeführt wird, wenn etwas drin ist refs/original/
(was im Grunde eine Sicherung ist).
Natürlich wird dies niemals perfekt sein, zum Beispiel wenn Ihre Commit-Nachrichten andere Dateien erwähnen, aber es ist ungefähr so nah, wie es ein Git-Strom zulässt (soweit mir sowieso bekannt ist).
Führen Sie dies immer nur auf einer Kopie Ihres Repositorys aus! - aber zusammenfassend, um alle Dateien außer "thisismyfilename.txt" zu entfernen:
git filter-branch --tree-filter 'for f in *; do if [ $f != "thisismyfilename.txt" ]; then rm -rf $f; fi; done' HEAD
git filter-branch -f --commit-filter 'if [ z$1 = z`git rev-parse $3^{tree}` ]; then skip_commit "$@"; else git commit-tree "$@"; fi'