To pytanie jest oparte na podkatalogu Odłącz do osobnego repozytorium Git
Zamiast odłączać pojedynczy podkatalog, chcę odłączyć kilka. Na przykład moje bieżące drzewo katalogów wygląda następująco:
/apps
/AAA
/BBB
/CCC
/libs
/XXX
/YYY
/ZZZ
Zamiast tego chciałbym:
/apps
/AAA
/libs
/XXX
--subdirectory-filter
Argument git filter-branch
nie będzie działać, ponieważ pozbywa się wszystkiego z wyjątkiem podanym katalogu po raz pierwszy jest prowadzony. Myślałem, że użycie --index-filter
argumentu dla wszystkich niechcianych plików zadziała (choćby nużące), ale jeśli spróbuję go uruchomić więcej niż raz, otrzymuję następujący komunikat:
Cannot create a new backup.
A previous backup already exists in refs/original/
Force overwriting the backup with -f
Jakieś pomysły? TIA
źródło
--tag-name-filter cat
do swoich parametrówRęczne kroki za pomocą prostych poleceń git
Plan polega na podzieleniu poszczególnych katalogów na własne repozytoria, a następnie scaleniu ich razem. Poniższe ręczne kroki nie wykorzystywały łatwych w użyciu skryptów, ale łatwe do zrozumienia polecenia i mogą pomóc w scaleniu dodatkowych N podfolderów w inne pojedyncze repozytorium.
Podzielić
Załóżmy, że Twoje oryginalne repozytorium to: original_repo
1 - Podziel aplikacje:
2 - Podziel biblioteki
Kontynuuj, jeśli masz więcej niż 2 foldery. Teraz będziesz mieć dwa nowe i tymczasowe repozytorium git.
Pokonaj , łącząc aplikacje i biblioteki
3 - Przygotuj nowe repozytorium:
Będziesz musiał wykonać co najmniej jedno zatwierdzenie. Jeśli poniższe trzy wiersze powinny zostać pominięte, pierwsze repozytorium pojawi się natychmiast w katalogu głównym repozytorium:
Po zatwierdzeniu pliku tymczasowego
merge
polecenie w późniejszej sekcji zostanie zatrzymane zgodnie z oczekiwaniami.Biorąc pod uwagę opinie użytkowników, zamiast dodawać losowy plik, taki jak
a_file_and_make_a_commit
, możesz dodać.gitignore
, lubREADME.md
itp.4 - Najpierw scal repozytorium aplikacji:
Teraz powinieneś zobaczyć katalog aplikacji w nowym repozytorium.
git log
powinien pokazywać wszystkie istotne historyczne komunikaty o zatwierdzeniach.Uwaga: jak Chris zauważył poniżej w komentarzach, dla nowszej wersji (> = 2.9) git, musisz określić za
--allow-unrelated-histories
pomocągit merge
5 - Następnie scal repozytorium bibliotek w ten sam sposób:
Kontynuuj, jeśli masz więcej niż 2 repozytoria do scalenia.
Odniesienie: Scal podkatalog innego repozytorium z git
źródło
.gitignore
iREADME.md
pliki.git merge .. git read-tree
kroku, ponieważ rejestruje je jako nowo dodane pliki, a wszystkie moje git guis nie łączą się z ich wcześniejszymi zatwierdzeniami.Dlaczego miałbyś chcieć biegać
filter-branch
więcej niż raz? Możesz to wszystko zrobić za jednym zamachem, więc nie musisz tego wymuszać (pamiętaj, że musiszextglob
włączyć w powłoce, aby to zadziałało):Powinno to pozbyć się wszystkich zmian w niechcianych podkatalogach i zachować wszystkie twoje gałęzie i zatwierdzenia (chyba że wpływają one tylko na pliki w przyciętych podkatalogach
--prune-empty
) - nie ma problemu z powielonymi zatwierdzeniami itp.Po tej operacji niechciane katalogi zostaną wymienione jako nieśledzone przez
git status
.To
$(ls ...)
jest konieczne,extglob
jest oceniane przez twoją powłokę zamiast przez filtr indeksu, który używash
wbudowanegoeval
(gdzieextglob
nie jest dostępny). Zobacz Jak włączyć opcje powłoki w git? po dalsze szczegóły na ten temat.źródło
git
poleceniach, a zatem nie jest tak podatna na różnice w sposobiels
interpretowania znaków w różnych systemach operacyjnych, jak odkrył @Bae.Odpowiadając tutaj na moje własne pytanie ... po wielu próbach i błędach.
Udało mi się to zrobić za pomocą kombinacji
git subtree
igit-stitch-repo
. Te instrukcje są oparte na:Najpierw wyciągnąłem katalogi, które chciałem zachować, w ich oddzielnym repozytorium:
Następnie utworzyłem nowe, puste repozytorium i zaimportowałem / zszyłem do niego ostatnie dwa:
Stwarza to dwa oddziały,
master-A
amaster-B
każdy trzyma zawartość jednej ze zszytych repo. Aby je połączyć i posprzątać:Teraz nie jestem do końca pewien, jak / kiedy to się dzieje, ale po pierwszej
checkout
i drugiejpull
, kod magicznie łączy się z gałęzią master (każdy wgląd w to, co się tutaj dzieje, jest mile widziany!)Wygląda na to, że wszystko działało zgodnie z oczekiwaniami, z wyjątkiem tego, że jeśli
newRepo
przejrzę historię zmian, istnieją duplikaty, gdy zestaw zmian wpłynął na obaapps/AAA
ilibs/XXX
. Jeśli istnieje sposób na usunięcie duplikatów, byłby idealny.źródło
export PERL5LIB="$PERL5LIB:/usr/local/git/lib/perl5/site_perl/"
do mojej konfiguracji basha, aby mógł znaleźć Git.pm. Następnie zainstalowałem go z cpan.git subtree add
do wykonania tego zadania. Zobacz stackoverflow.com/a/58253979/1894803Napisałem filtr git, aby rozwiązać dokładnie ten problem. Ma fantastyczną nazwę git_filter i znajduje się na github tutaj:
https://github.com/slobobaby/git_filter
Opiera się na doskonałej bibliotece libgit2.
Musiałem podzielić duże repozytorium z wieloma zatwierdzeniami (~ 100000), a rozwiązania oparte na git filter-branch zajęły kilka dni. git_filter zajmuje minutę, aby zrobić to samo.
źródło
Użyj rozszerzenia git „git splits”
git splits
to skrypt bash będący opakowaniem,git branch-filter
który stworzyłem jako rozszerzenie git, w oparciu o rozwiązanie jkeating .Został stworzony dokładnie do tej sytuacji. W przypadku błędu spróbuj użyć
git splits -f
opcji wymuszenia usunięcia kopii zapasowej. Ponieważgit splits
działa na nowej gałęzi, nie przepisuje bieżącej gałęzi, więc kopia zapasowa jest zbędna. Zobacz plik readme, aby uzyskać więcej szczegółów i pamiętaj, aby użyć go na kopii / klonie repozytorium (na wszelki wypadek!) .git splits
.Podziel katalogi na lokalny oddział
#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
Utwórz gdzieś puste repozytorium. Zakładamy, że utworzyliśmy puste repozytorium wywołane
xyz
na 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 repozytorium zdalne 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
źródło
for
Pętla jest warta uznania, gdyż inne podobne odpowiedzi nie zawierają go. Jeśli nie masz lokalnej kopii każdej gałęzi w swoim klonie,filter-branch
nie uwzględnisz ich w ramach przepisywania, co może potencjalnie wykluczyć pliki wprowadzone w innych gałęziach, ale jeszcze nie połączone z bieżącą gałęzią. (Choć warto też robigit fetch
na wszystkich oddziałach zostały wcześniej sprawdzone w celu zapewnienia, że pozostają one aktualne.)Proste rozwiązanie: git-filter-repo
Miałem podobny problem i po przejrzeniu różnych wymienionych tutaj podejść odkryłem git-filter-repo . Jest zalecany jako alternatywa dla git-filter-branch w oficjalnej dokumentacji git tutaj .
Aby utworzyć nowe repozytorium z podzbioru katalogów w istniejącym repozytorium, możesz użyć polecenia:
Filtruj wiele plików / folderów, łącząc je:
Tak więc, aby odpowiedzieć na pierwotne pytanie , z git-filter-repo potrzebujesz tylko następującego polecenia:
źródło
Tak. Wymuś zastąpienie kopii zapasowej, używając
-f
flagi przy kolejnych wywołaniach do,filter-branch
aby zastąpić to ostrzeżenie. :) W przeciwnym razie myślę, że masz rozwiązanie (to znaczy usunąć niechciany katalog na raz za pomocąfilter-branch
).źródło
Usuń kopię zapasową obecną w katalogu .git w refs / original, jak sugeruje wiadomość. Katalog jest ukryty.
źródło