Jak mogę przenieść pojedynczy katalog z repozytorium git do nowego repozytorium, zachowując jednocześnie historię?

110

Odziedziczyłem repozytorium git zawierające wiele projektów w oddzielnych katalogach. Chciałbym podzielić repozytorium na nowe indywidualne repozytoria, po jednym dla każdego projektu, a następnie aby repozytorium główne zawierało projekty jako moduły podrzędne. Chciałbym to wszystko zrobić, jeśli to możliwe, zachowując historię wersji poszczególnych projektów.

Mógłbym sklonować repozytorium dla każdego projektu i za każdym razem usunąć wszystkie inne projekty, ale czy istnieje lepszy sposób na uniknięcie sklonowanej historii w każdym nowym repozytorium projektów?

haftowane
źródło
2
Dodano tag git-submodules, ponieważ jest to bardzo przydatne do konwersji części repozytorium do modułu podrzędnego.
idbrii
Możliwy duplikat poddrzewa eksportu w Git z historią
użytkownik

Odpowiedzi:

99

Możesz użyć git filter-branchdo przepisania historii projektu. Z dokumentacji:

Aby przepisać repozytorium tak, aby wyglądało tak, jakby foodir / był jego korzeniem projektu i odrzucić całą pozostałą historię:

git filter-branch --subdirectory-filter foodir -- --all

Zrób kilka kopii repozytorium, zrób to dla każdego podkatalogu, który chcesz podzielić, a powinieneś skończyć z tym, czego szukasz.

Brian Campbell
źródło
1
A co jeśli chciałbym wykluczyć foodira i usunąć całą jego historię?
saeedgnu
1
Uwaga: jeśli chcesz mieć kilka katalogów, musisz określić --subdirectory-filterwiele razy. EG git filter-branch --subdirectory-filter foodir --subdirectory-filter bardiritp. --subdirectoryNie będzie zajmować wielu katalogów, ale można je określić wielokrotnie.
EnabrenTane
3
@Adam Jeśli chcesz zachować historię foodirw oryginalnym projekcie, nie przepisując jej historii, po prostu git rm -r foodirpowinno wystarczyć (to również usunie kopię z twojego drzewa roboczego; jeśli tego nie chcesz, użyj --cached). Jeśli chcesz całkowicie usunąć to z historii (odpowiadając również na pytanie @ilius), potrzebujesz czegoś takiegogit filter-branch --index-filter 'git rm -r --cached --ignore-unmatched foodir' -- --all
Brian Campbell
2
@ilius Przepraszam, że przegapiłem Twoje pytanie wcześniej, zobacz moją odpowiedź na powyższe pytanie, jak usunąć katalog i jego historię.
Brian Campbell
2
@ilius Tak, to też działa. W przypadku dużego projektu --index-filterrozwiązanie jest szybsze niż w przypadku --tree-filter, ponieważ nie musi on faktycznie pobierać plików, może po prostu bezpośrednio manipulować indeksem. --tree-filterMoże być trochę łatwiej jednak używać, jak można użyć zwykłych operacji filsystem zamiast pracy z operacji manipulacyjnych indeksu.
Brian Campbell
4

Aby wyeksportować folder jako nowe repozytorium, potrzebujesz:

  1. Aby sklonować repozytorium, w którym znajduje się folder, który chcesz wyeksportować.
  2. Aby utworzyć puste repozytorium u dostawcy usług hostingowych jako GitHub, aby przechowywać wyeksportowany folder.
  3. Otwórz sklonowany folder repozytorium i uruchom to polecenie:

    git subtree push --prefix=YourFolderNameToExport https://github.com/YourUserName/YourNewCleanRepoName master
    
użytkownik
źródło
1
git subtreenie jest dostępny jako pakiet Cygwin. Jeśli tego potrzebujesz: stackoverflow.com/a/27116828/2484903
Jack Miller
2

Celem git jest to, że historia jest zawarta w każdym zatwierdzeniu przez haszowanie zatwierdzenia rodzica. Możesz "odtworzyć" zatwierdzenia (tak właśnie działa importer svn) do nowego repozytorium i zachowując tylko każdy podprojekt. To jednak zniszczyłoby znaczenie skrótów zatwierdzania. Jeśli nie masz z tym problemu, niech tak będzie.

W przeszłości po prostu go sklonowałem i ruszyłem dalej. To sprawia, że ​​rzeczy są większe, ale miejsce na dysku jest tanie; mój czas jest drogi.

Nie znam też żadnych narzędzi do rozdzielania katalogu. Przypuszczam, że mógłbyś zalogować się git-log do katalogu, aby znaleźć wszystkie zmiany w nim, a następnie odtworzyć zatwierdzenia za pomocą czegoś takiego jak git-fast-export?

Colin Burnett
źródło
Głosowałem za tym, ponieważ nie zasługiwałem na to, aby być negatywnym - na pewno nie zastosowałbym tego podejścia, ale widzę, że próbował
Alvin