Mam repozytorium Git w folderze o nazwie XXX i mam drugie repozytorium Git o nazwie YYY .
Chcę zaimportować repozytorium XXX do repozytorium YYY jako podkatalog o nazwie ZZZ i dodać całą historię zmian XXX do YYY .
Struktura folderów przed:
├── XXX
│ ├── .git
│ └── (project files)
└── YYY
├── .git
└── (project files)
Struktura folderów po:
YYY
├── .git <-- This now contains the change history from XXX
├── ZZZ <-- This was originally XXX
│ └── (project files)
└── (project files)
Czy można to zrobić, czy muszę skorzystać z podmodułów?
Odpowiedzi:
Prawdopodobnie najprostszym sposobem byłoby wciągnięcie elementów XXX do gałęzi w YYY, a następnie scalenie ich w master:
W RRRR :
Właśnie próbowałem tego z kilkoma moimi repozytoriami i działa. W przeciwieństwie do odpowiedzi Jörga nie pozwoli ci to na dalsze korzystanie z drugiego repozytorium, ale nie sądzę, że i tak to określiłeś.
Uwaga: Ponieważ pierwotnie napisano to w 2009 roku, git dodał scalenie poddrzewa wymienione w odpowiedzi poniżej. Prawdopodobnie skorzystałbym z tej metody dzisiaj, chociaż oczywiście ta metoda nadal działa.
źródło
git mv $(ls|grep -v <your foldername>) <your foldername>/
Spowoduje to skopiowanie wszystkich plików i folderów do nowego folderuJeśli chcesz zachować dokładną historię zatwierdzeń drugiego repozytorium, a tym samym zachować możliwość łatwego scalenia wcześniejszych zmian w przyszłości, oto metoda, którą chcesz. Powoduje to niezmodyfikowaną historię importowania poddrzewa do repozytorium oraz jedno zatwierdzenie scalania, aby przenieść scalone repozytorium do podkatalogu.
Możesz śledzić zmiany upstream w następujący sposób:
Git sam określa, gdzie znajdują się pierwiastki przed scaleniem, więc nie musisz określać prefiksu przy kolejnych scaleniach.
Minusem jest to, że w historii połączonego pliki są prefiksu (nie w podkatalogu). W rezultacie
git log ZZZ/a
pokażą Ci wszystkie zmiany (jeśli wystąpią) oprócz tych w połączonej historii. Możesz to zrobić:ale to nie pokaże zmian innych niż w połączonej historii.
Innymi słowy, jeśli nie zmienisz
ZZZ
plików w repozytoriumXXX
, musisz to określić--follow
i nieokreśloną ścieżkę. Jeśli zmienisz je w obu repozytoriach, będziesz mieć 2 polecenia, z których żadne nie pokazuje wszystkich zmian.Wersje Git wcześniejsze niż 2.9 : Nie musisz przekazywać
--allow-unrelated-histories
opcji dogit merge
.Metoda w drugiej odpowiedzi, która używa
read-tree
i pomijamerge -s ours
krok, nie różni się niczym od skopiowania plików za pomocą cp i zatwierdzenia wyniku.Oryginalne źródło pochodzi z artykułu pomocy github „Subtree Merge” . I kolejny przydatny link .
źródło
git log
z plików, które ściągnąłem, po prostu zobaczę zatwierdzenie pojedynczego scalenia i nic z jego poprzedniego życia w drugim repo? Git 1.8.0git log -- myfile
git log -- rack/myfile
--allow-unrelated-histories
podczas scalania.git-subtree
jest skryptem zaprojektowanym do tego właśnie przypadku użycia łączenia wielu repozytoriów w jedno, przy jednoczesnym zachowaniu historii (i / lub dzieleniu historii poddrzewa, choć wydaje się to nie mieć znaczenia dla tego pytania). Jest dystrybuowany jako część drzewa git od wydania 1.7.11 .Aby scalić repozytorium
<repo>
przy rewizji<rev>
jako podkatalog<prefix>
, użyjgit subtree add
następującego polecenia:git-subtree implementuje strategię scalania poddrzewa w bardziej przyjazny dla użytkownika sposób.
W twoim przypadku w repozytorium YYY uruchomisz:
Minusem jest to, że w historii połączonego pliki są prefiksu (nie w podkatalogu). W rezultacie
git log ZZZ/a
pokażą Ci wszystkie zmiany (jeśli wystąpią) oprócz tych w połączonej historii. Możesz to zrobić:ale to nie pokaże zmian innych niż w połączonej historii.
Innymi słowy, jeśli nie zmienisz
ZZZ
plików w repozytoriumXXX
, musisz podać--follow
i nieokreśloną ścieżkę. Jeśli zmienisz je w obu repozytoriach, będziesz mieć 2 polecenia, z których żadne nie pokazuje wszystkich zmian.Więcej na ten temat tutaj .
źródło
git subtree add -P name-of-desired-prefix ~/location/of/git/repo-without-.git branch-name
Istnieje dobrze znany przykład tego w samym repozytorium Git, który jest zbiorowo znany w społeczności Git jako „ najfajniejsze połączenie kiedykolwiek ” (po temacie, którego Linus Torvalds użył w e-mailu do listy mailingowej Git, który opisuje to łączyć). W tym przypadku
gitk
GUI Git, który jest teraz częścią Git właściwego, faktycznie był osobnym projektem. Linusowi udało się połączyć to repozytorium z repozytorium Git w ten sposóbgit pull
edytowane.Wiadomość e-mail zawiera kroki niezbędne do odtworzenia, ale nie jest to dla osób o słabym sercu: po pierwsze, Linus napisał Git, więc prawdopodobnie wie o tym więcej niż ty lub ja, a po drugie, to było prawie 5 lat temu i git poprawiła się znacznie od tego czasu, więc może to jest teraz znacznie łatwiejsze.
W szczególności wydaje mi się, że w tym konkretnym przypadku należy użyć podmoduła gitk.
źródło
git-subtree
narzędzie strony trzeciej , które może ci w tym pomóc: github.com/apenwarr/git-subtreesubtree
Strategia seryjnej, szczególnie w połączeniu zgit-subtree
narzędziem jest ładny, może nawet lepsza alternatywa submodułów.Najprostszym sposobem na to jest użycie łatki formatu git.
Załóżmy, że mamy 2 repozytoria git foo i bar .
foo zawiera:
pasek zawiera:
i chcemy skończyć z foo zawierającym historię paska i te pliki:
Aby to zrobić:
A jeśli chcemy przepisać wszystkie zatwierdzenia wiadomości z paska, możemy to zrobić, np. W systemie Linux:
Spowoduje to dodanie „[bar]” na początku każdej wiadomości zatwierdzenia.
źródło
git am
prawdopodobnie się nie powiedzie.[ ]
z wiadomości zatwierdzenia. Dlatego powinieneś użyć innego markera niż[bar]
Ta funkcja sklonuje zdalne repo do lokalnego repozytorium, po scaleniu wszystkie commity zostaną zapisane,
git log
pokaże oryginalne commity i odpowiednie ścieżki:Jak używać:
Jeśli wprowadzisz małe zmiany, możesz nawet przenieść pliki / katalogi scalonego repozytorium na różne ścieżki, na przykład:
Powiadomienia
Ścieżki zamieniają się przez
sed
, więc upewnij się, że po scaleniu poruszały się we właściwych ścieżkach.Ten
--allow-unrelated-histories
parametr istnieje tylko od git> = 2,9.źródło
gnu-sed
abygit-add-repo
funkcja działała. Jeszcze raz dziękuję Andrey!Na podstawie tego artykułu działało dla mnie poddrzewo i przeniesiono tylko odpowiednią historię. Publikuj tutaj, na wypadek gdyby ktoś potrzebował tych kroków (pamiętaj o zastąpieniu symboli zastępczych wartościami, które dotyczą Ciebie):
w twoim źródłowym repozytorium podziel podfolder na nowy oddział
git subtree split --prefix=<source-path-to-merge> -b subtree-split-result
w docelowym scaleniu repozytorium w gałęzi podzielonego wyniku
sprawdź zmiany i zatwierdź
Nie zapomnij
Oczyść, usuwając
subtree-split-result
gałąźgit branch -D subtree-split-result
Usuń dodany pilot, aby pobrać dane z repozytorium źródłowego
git remote rm merge-source-repo
źródło
Dodanie kolejnej odpowiedzi, ponieważ myślę, że jest to nieco prostsze. Wyciąganie repo_dest odbywa się w repo_to_import, a następnie wykonywany jest push --set-upstream url: repo_dest master.
Ta metoda zadziałała, importując kilka mniejszych repozytoriów do większych.
Jak importować: repo1_to_import do repo_dest
Przed importem zmień nazwę lub przenieś pliki i katalogi w wybrane miejsce w oryginalnym repozytorium. na przykład
Metoda opisana pod poniższym linkiem zainspirowała tę odpowiedź. Podobało mi się, ponieważ wydawało się to prostsze. Ale strzeż się! Będą smoki! https://help.github.com/articles/importing-an-external-git-repository
git push --mirror url:repo_dest
wypycha lokalną historię repozytorium i stan do zdalnego (url: repo_dest). ALE to usuwa starą historię i stan pilota. Następuje zabawa! :-MIźródło
W moim przypadku chciałem zaimportować tylko niektóre pliki z innego repozytorium (XXX). Poddrzewo było dla mnie zbyt skomplikowane, a inne rozwiązania nie działały. Oto co zrobiłem:
To daje rozdzieloną spacjami listę wszystkich zatwierdzeń, które wpływają na pliki, które chciałem zaimportować (ZZZ) w odwrotnej kolejności (być może trzeba dodać --follow, aby przechwycić także nazwy). Następnie poszedłem do docelowego repozytorium (RRRR), dodałem inne repozytorium (XXX) jako zdalne, wykonałem z niego pobieranie i wreszcie:
który dodaje wszystkie zatwierdzenia do twojego oddziału, będziesz mieć wszystkie pliki z ich historią i możesz robić z nimi, co chcesz, tak jakby zawsze były w tym repozytorium.
źródło
Zobacz Podstawowy przykład w tym artykule i rozważ takie mapowanie na repozytoria:
A
<->YYY
,B
<->XXX
Po wszystkich czynnościach opisanych w tym rozdziale (po scaleniu) usuń gałąź
B-master
:Następnie wciśnij zmiany.
Mi to pasuje.
źródło
Byłem w sytuacji, w której szukałem,
-s theirs
ale oczywiście ta strategia nie istnieje. Moja historia była taka, że rozwidliłem projekt na GitHub, a teraz z jakiegoś powodu mój lokalnymaster
nie mógł zostać połączony zupstream/master
chociaż nie wprowadziłem żadnych lokalnych zmian w tym oddziale. (Naprawdę nie wiem, co się tam wydarzyło - myślę, że pod prąd zrobił jakieś brudne pchnięcia za kulisami, może?)Skończyło się na tym, że to zrobiłem
Więc teraz mój
master
jest ponownie zsynchronizowany zupstream/master
(i możesz powtórzyć powyższe dla każdego innego oddziału, którego również chcesz zsynchronizować podobnie).źródło
git reset --hard upstream/master
w twoim lokalnymmaster
oddziale wykona zadanie. W ten sposób nie tracisz konfiguracji lokalnego oddziału - takie jak domyślny upstream.Mogę zaproponować inne rozwiązanie (alternatywa dla git-submodules ) dla twojego problemu - narzędzie gil (git links)
Pozwala opisywać i zarządzać złożonymi zależnościami repozytoriów git.
Zapewnia również rozwiązanie problemu zależności rekurencyjnych podmodułów git .
Rozważ, że masz następujące zależności projektu: przykładowy wykres zależności repozytorium git
Następnie możesz zdefiniować
.gitlinks
plik z opisem relacji z repozytoriami:Każda linia opisuje link do git w następującym formacie:
Wreszcie musisz zaktualizować swoje główne repozytorium przykładowe:
W rezultacie sklonujesz wszystkie wymagane projekty i połączysz je ze sobą w odpowiedni sposób.
Jeśli chcesz zatwierdzić wszystkie zmiany w niektórych repozytoriach ze wszystkimi zmianami w podrzędnych repozytoriach połączonych, możesz to zrobić za pomocą jednego polecenia:
Polecenia pull, push działają w podobny sposób:
Narzędzie Gil (git links) obsługuje następujące polecenia:
Więcej informacji na temat problemu zależności rekurencyjnych submodułów git .
źródło
Pozwól, że użyję nazw
a
(zamiastXXX
iZZZ
) ib
(zamiastYYY
), ponieważ dzięki temu opis jest nieco łatwiejszy do odczytania.Powiedzmy, że chcesz scalić repozytorium
a
dob
(jestem zakładając się znajdują obok siebie):Do tego trzeba
git-filter-repo
zainstalować (filter-branch
jest odradzane ).Przykład połączenia 2 dużych repozytoriów i umieszczenia jednego z nich w podkatalogu: https://gist.github.com/x-yuri/9890ab1079cf4357d6f269d073fd9731
Więcej na ten temat tutaj .
źródło
Nie wiem, jak to łatwo zrobić. Mógłbyś to zrobić:
Mogę edytować ze szczegółami, jeśli brzmi to atrakcyjnie.
źródło
Myślę, że możesz to zrobić za pomocą „git mv” i „git pull”.
Jestem uczciwym git noobem - więc uważaj na swoje główne repozytorium - ale właśnie wypróbowałem to w tymczasowym katalogu i wydaje się, że działa.
Po pierwsze - zmień nazwę struktury XXX, aby dopasować ją tak, jak ma wyglądać, gdy jest w YYY:
Teraz XXX wygląda następująco:
Teraz użyj „git pull”, aby pobrać zmiany między:
Teraz RRRR wygląda następująco:
źródło