Utwórz repozytorium podmodułów z folderu i zachowaj jego historię zatwierdzeń git

111

Mam aplikację internetową, która eksploruje inne aplikacje internetowe w określony sposób. Zawiera kilka demonstracji internetowych w demosfolderze, a jedno z nich powinno mieć teraz swoje własne repozytorium. Chciałbym utworzyć osobne repozytorium dla tej aplikacji demonstracyjnej i nadać mu rozszerzeniepodpakiet podmoduł z głównego repozytorium bez utraty historii zmian.

Czy można zachować historię zatwierdzeń z plików w folderze repozytorium i utworzyć z niego repozytorium i zamiast tego używać go jako modułu podrzędnego ?

GabLeRoux
źródło
Szukałem, jak przenieść katalog 1 z repozytorium Git A do repozytorium Git B. +1 w celu uzyskania łącza do artykułu.
Chetabahana
1
Duplikować? stackoverflow.com/questions/12514197/…
naught101
Tak, to jest rzeczywiście bardzo podobne, rozwiązania trochę się różnią, dzięki za udostępnienie tego
GabLeRoux

Odpowiedzi:

191

Szczegółowe rozwiązanie

Zobacz notatkę na końcu tej odpowiedzi (ostatni akapit), aby uzyskać szybką alternatywę dla podmodułów git przy użyciu npm;)

W poniższej odpowiedzi dowiesz się, jak wyodrębnić folder z repozytorium i utworzyć z niego repozytorium git, a następnie dołączyć go jako moduł podrzędny zamiast folderu.

Zainspirowany artykułem Gerga Bayera Przenoszenie plików z jednego repozytorium Git do innego, zachowywanie historii

Na początku mamy coś takiego:

<git repository A>
    someFolders
    someFiles
    someLib <-- we want this to be a new repo and a git submodule!
        some files

W kroki mieszkowy, odniosę się to someLibjak <directory 1>.

Na koniec będziemy mieli coś takiego:

<git repository A>
    someFolders
    someFiles
    @submodule --> <git repository B>

<git repository B>
    someFolders
    someFiles

Utwórz nowe repozytorium git z folderu w innym repozytorium

Krok 1

Uzyskaj nową kopię repozytorium do podziału.

git clone <git repository A url>
cd <git repository A directory>

Krok 2

Bieżący folder będzie nowym repozytorium, więc usuń bieżący pilot.

git remote rm origin

Krok 3

Wyodrębnij historię żądanego folderu i zatwierdź go

git filter-branch --subdirectory-filter <directory 1> -- --all

Powinieneś teraz mieć repozytorium git z plikami z directory 1katalogu głównego repozytorium z całą powiązaną historią zatwierdzania.

Krok 4

Stwórz swoje repozytorium online i prześlij swoje nowe repozytorium!

git remote add origin <git repository B url>
git push

Być może będziesz musiał ustawić upstreamgałąź do pierwszego wypchnięcia

git push --set-upstream origin master

Czyste <git repository A>(opcjonalnie, patrz komentarze)

Chcemy usunąć ślady (pliki i historię zatwierdzeń) <git repository B>z, <git repository A>więc historia dla tego folderu jest tylko raz.

Jest to oparte na usuwaniu poufnych danych z github.

Przejdź do nowego folderu i

git clone <git repository A url>
cd <git repository A directory>
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch <directory 1> -r' --prune-empty --tag-name-filter cat -- --all

Zastąp <directory 1>folderem, który chcesz usunąć. -rzrobi to rekurencyjnie w określonym katalogu :). Teraz push origin/masterz--force

git push origin master --force

Scena bossa (patrz uwaga poniżej)

Utwórz moduł podrzędny z <git repository B>do<git repository A>

git submodule add <git repository B url>
git submodule update
git commit

Sprawdź, czy wszystko działa zgodnie z oczekiwaniami i push

git push origin master

Uwaga

Po wykonaniu tego wszystkiego zdałem sobie sprawę, że w moim przypadku bardziej odpowiednie jest użycie npm do zarządzania własnymi zależnościami. Możemy określić adresy URL i wersje git, zobacz adresy URL pakietu Package.json jako zależności .

Jeśli zrobisz to w ten sposób, repozytorium chcesz używać jako wymóg musi być moduł npm więc musi zawierać package.jsonplik lub dostaniesz ten błąd: Error: ENOENT, open 'tmp.tgz-unpack/package.json'.

tldr (rozwiązanie alternatywne)

Może być łatwiejsze korzystanie z npm i zarządzanie zależnościami za pomocą adresów URL git :

  • Przenieś folder do nowego repozytorium
  • uruchomić npm initw obu repozytoriach
  • uruchom npm install --save git://github.com/user/project.git#commit-ishtam, gdzie chcesz zainstalować zależności
GabLeRoux
źródło
39
Należy unikać kroku „Wyczyść <git repository A>”. W ten sposób nie możesz w pełni przywrócić / pobrać starszych wersji / zatwierdzeń z historii. Powinieneś po prostu zdjąć folder i dodać podmoduł. Więc upewnij się, że masz w pełni działającą kopię podczas sprawdzania starszych zatwierdzeń.
Cybot,
Nie powinieneś zrobić cd someLibprzed krokiem 2? Mówisz „Bieżący folder będzie nowym repozytorium”, ale tak naprawdę nie będzie; nowe repozytorium (moduł podrzędny) znajduje się w tym folderze.
Jago
1
potwierdzenie: tak, działa dla więcej niż jednego podmodułu. Bardzo dziękuję za szczegółową odpowiedź. Nie musiał też używać npm.
Breno Inojosa
2
Dodałbym informację o tym, refs/original/...który jest tworzony w kroku 3.
Emile Bergeron
6
GitHub opublikował artykuł o tym, jak wyodrębnić folder do nowego repozytorium: help.github.com/articles/…
jrobichaud
9

Rozwiązanie @GabLeRoux zgniata gałęzie i związane z nimi zatwierdzenia.

Prosty sposób na sklonowanie i zachowanie tych wszystkich dodatkowych gałęzi i zatwierdzeń:

1 - Upewnij się, że masz ten alias git

git config --global alias.clone-branches '! git branch -a | sed -n "/\/HEAD /d; /\/master$/d; /remotes/p;" | xargs -L1 git checkout -t'

2 - Sklonuj pilota, ściągnij wszystkie gałęzie, zmień pilota, przefiltruj katalog, wciśnij

git clone [email protected]:user/existing-repo.git new-repo
cd new-repo
git clone-branches
git remote rm origin
git remote add origin [email protected]:user/new-repo.git
git remote -v
git filter-branch --subdirectory-filter my_directory/ -- --all
git push --all
git push --tags
oodavid
źródło
3

Rozwiązanie GabLeRoux działa dobrze, chyba że używasz git lfsi masz duże pliki w katalogu, który chcesz odłączyć. W takim przypadku po kroku 3 wszystkie duże pliki pozostaną plikami wskaźników zamiast prawdziwymi plikami. Myślę, że jest to prawdopodobnie spowodowane usunięciem .gitattributespliku w procesie gałęzi filtru.

Zdając sobie z tego sprawę, stwierdzam, że działa dla mnie następujące rozwiązanie:

cp .gitattributes .git/info/attributes

Kopiowanie, .gitattributesktóre git lfs używa do śledzenia dużych plików do .git/katalogu, aby uniknąć ich usunięcia.

Kiedy filter-branch jest gotowy, nie zapomnij wstawić z powrotem, .gitattributesjeśli nadal chcesz używać git lfs dla nowego repozytorium:

mv .git/info/attributes .gitattributes
git add .gitattributes
git commit -m 'added back .gitattributes'
ls.
źródło