Mam repozytorium Git, które zawiera wiele podkatalogów. Teraz odkryłem, że jeden z podkatalogów nie jest powiązany z drugim i powinien zostać odłączony do osobnego repozytorium.
Jak mogę to zrobić, zachowując historię plików w podkatalogu?
Myślę, że mógłbym utworzyć klon i usunąć niechciane części każdego klonu, ale przypuszczam, że dałoby to pełne drzewo podczas sprawdzania starszej wersji itp. Może to być dopuszczalne, ale wolałbym móc udawać, że dwa repozytoria nie mają wspólnej historii.
Żeby było jasne, mam następującą strukturę:
XYZ/
.git/
XY1/
ABC/
XY2/
Ale chciałbym to zamiast tego:
XYZ/
.git/
XY1/
XY2/
ABC/
.git/
ABC/
git filter-branch
patrz moja odpowiedź poniżej.Odpowiedzi:
Aktualizacja : Ten proces jest tak powszechne, że zespół git stało się znacznie prostsze z nowym narzędziu
git subtree
. Zobacz tutaj: Odłącz (przenieś) podkatalog do osobnego repozytorium GitChcesz sklonować swoje repozytorium, a następnie użyć
git filter-branch
do zaznaczenia wszystkiego oprócz podkatalogu, który chcesz, aby nowe repozytorium zostało zużyte.Aby sklonować lokalne repozytorium:
(Uwaga: repozytorium zostanie sklonowane za pomocą dowiązań twardych, ale nie stanowi to problemu, ponieważ dowiązane pliki nie będą same w sobie modyfikowane - zostaną utworzone nowe).
Teraz zachowajmy interesujące gałęzie, które również chcemy przepisać, a następnie usuń początek, aby uniknąć pchania się tam i aby upewnić się, że stare zatwierdzenia nie będą odwoływać się do źródła:
lub dla wszystkich zdalnych oddziałów:
Teraz możesz również chcieć usunąć tagi, które nie mają związku z podprojektem; możesz to zrobić później, ale może być konieczne ponowne przycięcie repozytorium. Nie zrobiłem tego i otrzymałem
WARNING: Ref 'refs/tags/v0.1' is unchanged
tag dla wszystkich (ponieważ wszystkie nie były powiązane z podprojektem); dodatkowo po usunięciu takich tagów zostanie odzyskanych więcej miejsca. Najwyraźniejgit filter-branch
powinien być w stanie przepisać inne tagi, ale nie mogłem tego zweryfikować. Jeśli chcesz usunąć wszystkie tagi, użyjgit tag -l | xargs git tag -d
.Następnie użyj gałęzi filter i zresetuj, aby wykluczyć inne pliki, aby mogły zostać przycięte. Dodajmy również,
--tag-name-filter cat --prune-empty
aby usunąć puste zatwierdzenia i przepisać tagi (pamiętaj, że będzie to musiało usunąć ich podpis):lub alternatywnie, aby przepisać tylko gałąź HEAD i zignorować tagi i inne gałęzie:
Następnie usuń dzienniki kopii zapasowych, aby przestrzeń mogła zostać naprawdę odzyskana (chociaż teraz operacja jest destrukcyjna)
a teraz masz lokalne repozytorium git podkatalogu ABC z zachowaną całą jego historią.
Uwaga: W przypadku większości zastosowań
git filter-branch
należy rzeczywiście dodać parametr-- --all
. Tak, to naprawdę --space--all
. To muszą być ostatnie parametry polecenia. Jak odkrył Matli, zachowuje gałęzie projektu i tagi zawarte w nowym repozytorium.Edycja: uwzględniono różne sugestie z poniższych komentarzy, aby na przykład upewnić się, że repozytorium faktycznie się zmniejszyło (co nie zawsze tak było wcześniej).
źródło
--no-hardlinks
? Usunięcie jednego twardego linku nie wpłynie na drugi plik. Obiekty Git również są niezmienne. Tylko jeśli zmienisz uprawnienia właściciela / pliku, których potrzebujesz--no-hardlinks
.filter-branch
jest--prune-empty
usunięcie teraz pustych zatwierdzeń.-- --all
. Ja również prowadziłgit remote rm origin
, agit tag -l | xargs git tag -d
przedgit filter-branch
poleceniem. To zmniejszyło mój.git
katalog z 60M do ~ 300K. Zauważ, że musiałem uruchomić oba te polecenia, aby uzyskać zmniejszenie rozmiaru.Easy Way ™
Okazuje się, że jest to tak powszechna i przydatna praktyka, że zwierzchnicy Gita sprawili, że było to naprawdę łatwe, ale musisz mieć nowszą wersję Git (> = 1.7.11 maja 2012 r.). Zobacz dodatek, aby dowiedzieć się, jak zainstalować najnowszą wersję Git. Ponadto, nie jest przykładem w świecie rzeczywistym w poradniku poniżej.
Przygotuj stare repozytorium
Uwaga:
<name-of-folder>
NIE może zawierać wiodących ani końcowych znaków. Na przykład folder o nazwiesubproject
MUSI zostać przekazany jakosubproject
NIE./subproject/
Uwaga dla użytkowników systemu Windows: gdy głębokość folderu wynosi> 1,
<name-of-folder>
musi mieć separator folderów w stylu * nix (/). Na przykład folder o nazwiepath1\path2\subproject
MUSI zostać przekazany jakopath1/path2/subproject
Utwórz nowe repozytorium
Połącz nowe repozytorium z GitHub lub gdziekolwiek
Oczyszczanie w środku
<big-repo>
, jeśli jest to pożądaneUwaga : pozostawia to wszystkie historyczne odniesienia w repozytorium.Zobacz dodatek poniżej, jeśli naprawdę obawiasz się, że podałeś hasło lub chcesz zmniejszyć rozmiar pliku w
.git
folderze....
Przewodnik
Są to te same kroki, co powyżej , ale wykonuję moje dokładne kroki dla mojego repozytorium zamiast używać
<meta-named-things>
.Oto projekt, który mam zaimplementować moduły przeglądarki JavaScript w węźle:
Chcę podzielić pojedynczy folder
btoa
na osobne repozytorium GitMam teraz nowy oddział,
btoa-only
który tylko zatwierdzabtoa
i chcę utworzyć nowe repozytorium.Następnie tworzę nowe repozytorium na GitHub lub Bitbucket lub cokolwiek innego i dodam jako
origin
Szczęśliwy dzień!
Uwaga: jeśli utworzyłeś repozytorium za pomocą
README.md
,.gitignore
iLICENSE
, musisz najpierw pobrać:Na koniec chcę usunąć folder z większego repozytorium
...
dodatek
Najnowsza wersja Git na macOS
Aby uzyskać najnowszą wersję Git za pomocą Homebrew :
Najnowsza wersja Git na Ubuntu
Jeśli to nie zadziała (masz bardzo starą wersję Ubuntu), spróbuj
Jeśli to nadal nie działa, spróbuj
Dzięki rui.araujo z komentarzy.
Wyczyść swoją historię
Domyślnie usuwanie plików z Gita tak naprawdę ich nie usuwa, po prostu potwierdza, że już ich tam nie ma. Jeśli chcesz faktycznie usunąć odniesienia historyczne (tj. Masz zatwierdzone hasło), musisz to zrobić:
Następnie możesz sprawdzić, czy Twój plik lub folder w ogóle nie pojawia się w historii Git
Nie można jednak „usunąć” operacji usuwania do GitHub i tym podobnych. Jeśli spróbujesz, pojawi się błąd i będziesz musiał to zrobić,
git pull
zanim będziesz mógłgit push
- a następnie wrócisz do posiadania wszystkiego w swojej historii.Więc jeśli chcesz usunąć historię z „pochodzenia” - co oznacza, że chcesz usunąć ją z GitHub, Bitbucket itp. - musisz usunąć repozytorium i ponownie wcisnąć przyciętą kopię repozytorium. Ale czekaj - jest więcej ! - Jeśli naprawdę martwisz się usunięciem hasła lub czegoś takiego, musisz przyciąć kopię zapasową (patrz poniżej).
Dokonywanie
.git
mniejszyWyżej wspomniane polecenie usuwania historii wciąż pozostawia kilka plików kopii zapasowych - ponieważ Git jest zbyt uprzejmy, pomagając ci nie zepsuć repozytorium przez przypadek. W końcu usunie osierocone pliki w ciągu dni i miesięcy, ale pozostawia je tam na chwilę, na wypadek, gdybyś zdał sobie sprawę, że przypadkowo usunąłeś coś, czego nie chciałeś.
Jeśli więc naprawdę chcesz opróżnić kosz, aby natychmiast zmniejszyć rozmiar klonu repozytorium, musisz wykonać wszystkie te naprawdę dziwne rzeczy:
To powiedziawszy, nie zalecałbym wykonywania tych kroków, chyba że wiesz, że musisz - na wypadek, gdybyś wyciął niewłaściwy podkatalog, wiesz? Pliki kopii zapasowej nie powinny zostać sklonowane po naciśnięciu repozytorium, będą one tylko w lokalnej kopii.
Kredyt
źródło
git subtree
jest nadal częścią folderu „contrib” i nie jest domyślnie instalowany na wszystkich dystrybucjach. github.com/git/git/blob/master/contrib/subtreepopd
ipushd
sprawiają, że jest to raczej niejawne i trudniejsze do zrozumienia, co zamierza zrobić ...Odpowiedź Paula tworzy nowe repozytorium zawierające / ABC, ale nie usuwa / ABC z / XYZ. Następujące polecenie usunie / ABC z / XYZ:
Oczywiście najpierw przetestuj go w repozytorium „klon-no-hardlinks” i postępuj zgodnie z poleceniami resetowania, gc i przycinania, które znajdują się na listach Paula.
źródło
git filter-branch --index-filter "git rm -r -f --cached --ignore-unmatch ABC" --prune-empty HEAD
i będzie znacznie szybciej. filtr indeksu działa na indeksie, podczas gdy filtr drzewa musi sprawdzać i ustawiać wszystko dla każdego zatwierdzenia .--index-filter
metody, możesz to zrobićgit rm -q -r -f
, aby każde wywołanie nie drukowało wiersza dla każdego usuwanego pliku.Przekonałem się, że aby poprawnie usunąć starą historię z nowego repozytorium, musisz wykonać trochę więcej pracy po
filter-branch
kroku.Wykonaj klon i filtr:
Usuń każde odniesienie do starej historii. „Origin” śledził twój klon, a „oryginał” to miejsce, w którym gałąź filtra zapisuje stare rzeczy:
Nawet teraz twoja historia może utknąć w pliku pakietu, którego fsck nie dotknie. Rozerwij go na strzępy, tworząc nowy plik pakietu i usuwając nieużywane obiekty:
Istnieje wyjaśnienie tego w instrukcji dla branży filtracyjnej .
źródło
git gc --aggressive --prune=now
wciąż brakuje, prawda?git gc --aggressive --prune=now
zmniejszyłem wiele nowych repoEdycja: dodano skrypt Bash.
Odpowiedzi podane tutaj działały dla mnie tylko częściowo; Wiele dużych plików pozostało w pamięci podręcznej. Co w końcu zadziałało (po godzinach w #git na freenode):
W przypadku poprzednich rozwiązań rozmiar repozytorium wynosił około 100 MB. Ten obniżył go do 1,7 MB. Może to komuś pomaga :)
Poniższy skrypt bash automatyzuje zadanie:
źródło
To nie jest już tak skomplikowane, że możesz po prostu użyć polecenia git filter-branch na klonie repozytorium, aby wyrzucić podkatalogi, których nie chcesz, a następnie przełączyć na nowy pilot.
źródło
The result will contain that directory (and only that) as its project root.
i rzeczywiście to otrzymasz, tj. Oryginalna struktura projektu nie zostanie zachowana.Aktualizacja : moduł git-poddrzewo był tak przydatny, że zespół git wciągnął go do rdzenia i stworzył
git subtree
. Zobacz tutaj: Odłącz (przenieś) podkatalog do osobnego repozytorium Gitgit-subtree może być do tego użyteczny
http://github.com/apenwarr/git-subtree/blob/master/git-subtree.txt (wycofany)
http://psionides.jogger.pl/2010/02/04/sharing-code-between-projects-w-git-subtree/
źródło
Oto mała modyfikacja CoolAJ86 „s «Easy Way ™»odpowiedź aby rozdzielić wiele podfoldery (powiedzmy
sub1
asub2
) do nowego repozytorium git.The Easy Way ™ (wiele podfolderów)
Przygotuj stare repozytorium
Uwaga:
<name-of-folder>
NIE może zawierać wiodących ani końcowych znaków. Na przykład folder o nazwiesubproject
MUSI zostać przekazany jakosubproject
NIE./subproject/
Uwaga dla użytkowników systemu Windows: gdy głębokość folderu wynosi> 1,
<name-of-folder>
musi mieć separator folderów w stylu * nix (/). Na przykład folder o nazwiepath1\path2\subproject
MUSI zostać przekazany jakopath1/path2/subproject
. Ponadto nie używajmv
polecenia, alemove
.Ostatnia uwaga: wyjątkowa i duża różnica w stosunku do odpowiedzi podstawowej to druga linia skryptu „
git filter-branch...
”Utwórz nowe repozytorium
Połącz nowe repozytorium z Githubem lub gdziekolwiek
Oczyszczanie, w razie potrzeby
Uwaga : pozostawia to wszystkie historyczne odniesienia w repozytorium. Zobacz załącznik w oryginalnej odpowiedzi, jeśli naprawdę obawiasz się, że podałeś hasło lub chcesz zmniejszyć rozmiar pliku w
.git
folderze.źródło
sub1
andsub2
foldery nie istnieją z pierwotnej wersji, musiałem zmodyfikować mój--tree-filter
skrypt w następujący sposób:"mkdir <name-of-folder>; if [ -d sub1 ]; then mv <sub1> <name-of-folder>/; fi"
. W drugimfilter-branch
poleceniu zastąpiłem <sub1> <sub2>, pominąłem tworzenie <nazwa-folderu> i dodałem-f
po,filter-branch
aby zastąpić ostrzeżenie o istniejącej kopii zapasowej.Pierwotne pytanie chce, aby pliki XYZ / ABC / (*) stały się plikami ABC / ABC / (*). Po zaimplementowaniu zaakceptowanej odpowiedzi na mój własny kod zauważyłem, że faktycznie zmienia on pliki XYZ / ABC / (*) na pliki ABC / (*). Strona man gałęzi filter mówi nawet:
Innymi słowy, promuje folder najwyższego poziomu „w górę” o jeden poziom. To ważne rozróżnienie, ponieważ na przykład w mojej historii zmieniłem nazwę folderu najwyższego poziomu. Promując foldery „wyżej” o jeden poziom, git traci ciągłość przy zatwierdzeniu, w którym zmieniłem nazwę.
Moja odpowiedź na to pytanie polega zatem na utworzeniu 2 kopii repozytorium i ręcznym usunięciu folderów, które chcesz w nich przechowywać. Strona podręcznika wspiera mnie następującymi informacjami:
źródło
targetdir
została w pewnym momencie zmieniona igit filter-branch
po prostu nazwała go dniem, usuwając wszystkie zatwierdzenia dokonane przed zmianą nazwy! Szokujące, biorąc pod uwagę, jak biegły Git śledzi takie rzeczy, a nawet migruje poszczególne fragmenty treści!git rm
wymaga wielu argumentów, więc nie ma powodu, aby uruchamiać go dla każdego pliku / folderu:BYEBYE="dir/subdir2 dir2 file1 dir/file2"; git filter-branch -f --index-filter "git rm -q -r -f --cached --ignore-unmatch $BYEBYE" --prune-empty -- --all
Aby dodać do odpowiedzi Pawła , odkryłem, że aby ostatecznie odzyskać miejsce, muszę pchnąć HEAD do czystego repozytorium, a to zmniejsza rozmiar katalogu .git / objects / pack.
to znaczy
Po przycięciu gc wykonaj również:
To możesz zrobić
i rozmiar ABC / .git jest zmniejszony
W rzeczywistości niektóre czasochłonne kroki (np. Git gc) nie są potrzebne w przypadku repozytorium wypychania do czyszczenia, tj .:
źródło
Właściwy sposób jest teraz następujący:
git filter-branch --prune-empty --subdirectory-filter FOLDER_NAME [first_branch] [another_branch]
GitHub ma teraz nawet mały artykuł na temat takich przypadków.
Ale pamiętaj, aby najpierw sklonować oryginalne repozytorium do osobnego katalogu (ponieważ spowoduje to usunięcie wszystkich plików i innych katalogów i prawdopodobnie będziesz musiał z nimi pracować).
Twój algorytm powinien więc:
git filter-branch
tylko pozostawionych plików w pewnym podkatalogu, pchnij do nowego pilotaźródło
Wydaje się, że większość (wszystkich?) Odpowiedzi tutaj opiera się na jakiejś formie
git filter-branch --subdirectory-filter
i podobnej. Może to działać „przez większość czasu”, jednak w niektórych przypadkach, na przykład w przypadku zmiany nazwy folderu, np .:Jeśli wykonasz normalny styl filtru git, aby wyodrębnić plik „move_me_renamed”, utracisz historię zmian plików, która nastąpiła od tyłu, gdy początkowo był to katalog move_this_dir ( zob. ).
Wygląda więc na to, że jedynym sposobem, aby naprawdę zachować całą historię zmian (jeśli tak jest w twoim przypadku), jest w istocie skopiowanie repozytorium (utworzenie nowego repozytorium, ustawienie tego jako źródła), a następnie usunięcie wszystkich pozostałych i zmień nazwę podkatalogu na nadrzędny w następujący sposób:
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
Jest to zgodne z dokumentem github „Dzielenie podfolderu na nowe repozytorium” kroki 6-11, aby wypchnąć moduł do nowego repozytorium.
Nie pozwoli ci to zaoszczędzić miejsca w folderze .git, ale zachowa całą historię zmian tych plików, nawet przy różnych nazwach. I może to nie być tego warte, jeśli nie ma „zbyt wielu” utraconych historii itp. Ale przynajmniej masz gwarancję, że nie stracisz starszych zobowiązań!
źródło
Polecam przewodnik GitHub dotyczący podziału podfolderów na nowe repozytorium . Kroki są podobne do odpowiedzi Paula , ale dla mnie instrukcje były łatwiejsze do zrozumienia.
Zmodyfikowałem instrukcje, aby dotyczyły lokalnego repozytorium, a nie jednego hostowanego w GitHub.
źródło
If you create a new clone of the repository, you won't lose any of your Git history or changes when you split a folder into a separate repository.
Jednak zgodnie z komentarzami do wszystkich odpowiedzi tutaj zarówno skrypt, jakfilter-branch
isubtree
skrypt powodują utratę historii wszędzie tam, gdzie zmienia się nazwa podkatalogu. Czy można coś zrobić, aby rozwiązać ten problem?Podczas
git filter-branch
korzystania z nowszej wersjigit
(2.22+
może?), Mówi o użyciu tego nowego narzędzia git-filter-repo . To narzędzie z pewnością uprościło mi sprawy.Filtrowanie z repozytorium filtrów
Polecenia do utworzenia
XYZ
repozytorium z pierwotnego pytania:założenia: * zdalne repozytorium XYZ było nowe i puste przed wypchnięciem
Filtrowanie i przenoszenie
W moim przypadku chciałem również przenieść kilka katalogów, aby uzyskać bardziej spójną strukturę. Początkowo uruchomiłem to proste
filter-repo
poleceniegit mv dir-to-rename
, ale potem odkryłem, że mogę uzyskać nieco „lepszą” historię przy użyciu tej--path-rename
opcji. Zamiast zobaczyć ostatnio zmodyfikowane5 hours ago
przeniesione pliki w nowym repozytorium, teraz widzęlast year
(w interfejsie GitHub), który pasuje do zmodyfikowanych czasów w oryginalnym repozytorium.Zamiast...
Ostatecznie pobiegłem ...
Uwagi:git filter-repo --subdirectory-filter dir-matching-new-repo-name
). To polecenie poprawnie przekonwertowało ten podkatalog na katalog główny skopiowanego lokalnego repozytorium, ale zaowocowało to także historią tylko trzech zatwierdzeń, które zajęły utworzenie podkatalogu. (Nie zdawałem sobie sprawy, że--path
można to określić wiele razy; tym samym eliminuje potrzebę tworzenia podkatalogu w repozytorium źródłowym). Ponieważ do czasu, gdy zauważyłem, że ktoś zaangażował się w repozytorium źródłowe, zauważyłem, że nie udało mi się przenieść historię, której użyłemgit reset commit-before-subdir-move --hard
poclone
poleceniu i dodałem--force
dofilter-repo
polecenia, aby działało na nieco zmodyfikowanym klonie lokalnym.git
, ale ostatecznie sklonowałem git-filter-repo i dowiązałem go symbolicznie do$(git --exec-path)
:źródło
filter-repo
narzędzia (które przedstawiłem w zeszłym miesiącu w stackoverflow.com/a/58251653/6309 )git-filter-repo
zdecydowanie powinien być preferowanym podejściem w tym momencie. Jest o wiele, dużo szybszy i bezpieczniejszy niżgit-filter-branch
i chroni przed wieloma problemami, na które można natknąć się podczas przepisywania historii gitów. Mam nadzieję, że ta odpowiedź przyciąga więcej uwagi, ponieważ jest to jedna z nichgit-filter-repo
.Miałem dokładnie ten problem, ale wszystkie standardowe rozwiązania oparte na gałęzi filter git były bardzo wolne. Jeśli masz małe repozytorium, to może nie być problem, to było dla mnie. Napisałem inny program do filtrowania git oparty na libgit2, który jako pierwszy krok tworzy gałęzie dla każdego filtrowania podstawowego repozytorium, a następnie wypycha je do czyszczenia repozytoriów jako następny krok. W moim repozytorium (500 Mb 100 000 zatwierdzeń) standardowe metody git filter-branch trwały kilka dni. Mój program zajmuje kilka minut, aby wykonać to samo filtrowanie.
Ma wspaniałą nazwę git_filter i mieszka tutaj:
https://github.com/slobobaby/git_filter
na GitHub.
Mam nadzieję, że komuś się przyda.
źródło
Użyj tego polecenia filtru, aby usunąć podkatalog, zachowując jednocześnie tagi i gałęzie:
źródło
Oto, co warto, oto jak używać GitHub na komputerze z systemem Windows. Załóżmy, że masz sklonowane repozytorium w miejscu zamieszkania
C:\dir1
. Struktura katalogów wygląda następująco:C:\dir1\dir2\dir3
.dir3
Katalog jest jeden Chcę być nowy oddzielny repo.Github:
MyTeam/mynewrepo
Podpowiedź Bash:
$ cd c:/Dir1
$ git filter-branch --prune-empty --subdirectory-filter dir2/dir3 HEAD
Zwrócono:
Ref 'refs/heads/master' was rewritten
(fyi: dir2 / dir3 rozróżnia małe i duże litery).$ git remote add some_name [email protected]:MyTeam/mynewrepo.git
git remote add origin etc
. nie działał, zwrócił „remote origin already exists
”$ git push --progress some_name master
źródło
Jak wspomniałem powyżej , musiałem użyć rozwiązania odwrotnego (usuwając wszystkie zatwierdzenia nie dotykające mojego
dir/subdir/targetdir
), które wydawało się działać całkiem dobrze, usuwając około 95% zatwierdzeń (zgodnie z życzeniem). Pozostają jednak dwa małe problemy.Po pierwsze ,
filter-branch
wykonał świetną robotę usuwając zatwierdzenia, które wprowadzają lub modyfikują kod, ale najwyraźniej zatwierdzenia scalania znajdują się poniżej jego stacji w Gitiverse.Jest to kwestia kosmetyczna, z którą prawdopodobnie mógłbym żyć (mówi ... powoli wycofując się z odwróconymi oczami) .
PO DRUGI, kilka pozostałych zmian jest prawie WSZYSTKIE zduplikowanych! Wydaje mi się, że uzyskałem drugą, zbędną oś czasu, która obejmuje prawie całą historię projektu. Interesującą rzeczą (którą widać na poniższym obrazku) jest to, że moje trzy lokalne oddziały nie znajdują się na tej samej osi czasu (z pewnością dlatego istnieje i nie są po prostu śmieciami).
Jedyne, co mogę sobie wyobrazić, to to, że jednym z usuniętych zatwierdzeń był być może pojedynczy zatwierdzenie scalania, które
filter-branch
faktycznie usunęło , i które stworzyło równoległą oś czasu, ponieważ każdy nie połączony nić wziął własną kopię zatwierdzeń. ( wzrusza ramionami Gdzie są moje TARDiS?) Jestem prawie pewien, że mogę rozwiązać ten problem, chociaż naprawdę chciałbym zrozumieć, jak to się stało.W przypadku szalonego mergefest-O-RAMA prawdopodobnie zostawię go w spokoju, ponieważ tak mocno zakorzenił się w mojej historii popełnień - grozi mi za każdym razem, gdy się zbliżam - nie wydaje się, aby faktycznie powodował wszelkie nie-kosmetyczne problemy i ponieważ jest dość ładna w Tower.app.
źródło
Łatwiejsza droga
git splits
. Stworzyłem go jako rozszerzenie git, oparte na rozwiązaniu Jkeating .Podziel katalogi na oddział lokalny
#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
Utwórz gdzieś puste repozytorium. Załóżmy, że utworzyliśmy puste repozytorium o nazwie
xyz
GitHub, które ma ścieżkę:[email protected]:simpliwp/xyz.git
Przejdź do nowego repozytorium.
#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
Sklonuj nowo utworzone zdalne repozytorium do nowego katalogu lokalnego
#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
źródło
git splits
)Może być potrzebne coś takiego jak „git reflog expire --expire = now - all” przed odśmiecaniem, aby faktycznie wyczyścić pliki. git filter-branch po prostu usuwa odniesienia w historii, ale nie usuwa wpisów z rejestru, które przechowują dane. Oczywiście najpierw przetestuj.
Moje użycie dysku dramatycznie spadło, chociaż moje początkowe warunki były nieco inne. Być może --subdirectory-filter neguje tę potrzebę, ale wątpię w to.
źródło
Sprawdź projekt git_split na https://github.com/vangorra/git_split
Zamień katalogi git we własne repozytoria w ich własnej lokalizacji. Brak poddrzewa zabawnego biznesu. Ten skrypt zajmie istniejący katalog w twoim repozytorium git i zamieni ten katalog w niezależne repozytorium. Po drodze skopiuje całą historię zmian dla podanego katalogu.
źródło
Umieść to w swoim gitconfig:
źródło
Jestem pewien, że poddrzewo git jest w porządku i wspaniałe, ale moje podkatalogi kodu zarządzanego przez git, które chciałem przenieść, były w całości zaćmione. Więc jeśli używasz egit, jest to boleśnie łatwe. Weź projekt, który chcesz przenieść, i połącz go -> odłącz, a następnie zespół -> udostępnij go w nowej lokalizacji. Domyślnie spróbuje użyć starej lokalizacji repozytorium, ale możesz odznaczyć istniejącą opcję użycia i wybrać nowe miejsce, aby ją przenieść. Cały grad egit.
źródło
Możesz łatwo wypróbować https://help.github.com/enterprise/2.15/user/articles/splitting-a-subfolder-out-into-a-new-repository/
To zadziałało dla mnie. Problemy, które napotkałem w powyższych krokach, to:
W tym poleceniu jest mistrzem
git filter-branch --prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAME
BRANCH-NAME
jeśli ostatni krok nie powiedzie się podczas zatwierdzania z powodu problemu z ochroną, wykonaj - https://docs.gitlab.com/ee/user/project/protected_branches.html
źródło
Znalazłem dość proste rozwiązanie. Pomysł polega na skopiowaniu repozytorium, a następnie usunięciu niepotrzebnej części. Tak to działa:
1) Sklonuj repozytorium, które chcesz podzielić
2) Przejdź do folderu git
2) Usuń niepotrzebne foldery i zatwierdź je
3) Usuń niepotrzebne foldery z historii za pomocą BFG
4) Sprawdź, czy historia nie zawiera właśnie usuniętych plików / folderów
5) Teraz masz czyste repozytorium bez ABC, więc po prostu weź je do nowego źródła
Otóż to. Możesz powtórzyć kroki, aby uzyskać inne repozytorium,
po prostu usuń XY1, XY2 i zmień nazwę XYZ -> ABC w kroku 3
źródło