Chciałbym scalić zdalne repozytorium git w moim działającym repozytorium git jako jego podkatalog. Chciałbym, aby powstałe repozytorium zawierało połączoną historię dwóch repozytoriów, a także, aby każdy plik scalonego repozytorium zachował swoją historię tak, jak w zdalnym repozytorium. Próbowałem użyć strategii poddrzewa, jak wspomniano w Jak używać strategii scalania poddrzewa , ale po wykonaniu tej procedury, chociaż wynikowe repozytorium rzeczywiście zawiera scaloną historię dwóch repozytoriów, pojedyncze pliki pochodzące ze zdalnego nie zachowały swojej historii (`git log 'na którymkolwiek z nich pokazuje po prostu komunikat" Scalona gałąź ... ").
Nie chcę też używać modułów podrzędnych, ponieważ nie chcę, aby dwa połączone repozytoria git były już oddzielne.
Czy możliwe jest połączenie zdalnego repozytorium git w innym jako podkatalog z pojedynczymi plikami pochodzącymi ze zdalnego repozytorium, zachowując ich historię?
Bardzo dziękuję za pomoc.
EDYCJA: Obecnie wypróbowuję rozwiązanie, które używa git filter-branch do przepisania historii scalonego repozytorium. Wygląda na to, że działa, ale muszę to jeszcze przetestować. Wrócę do raportu z moich ustaleń.
EDYCJA 2: W nadziei, że wyjaśnię siebie, podaję dokładne polecenia, których użyłem w strategii poddrzewa git, co powoduje widoczną utratę historii plików zdalnego repozytorium. Niech A będzie repozytorium git, w którym obecnie pracuję, a B repozytorium git, które chciałbym włączyć do A jako jego podkatalog. Wykonał następujące czynności:
git remote add -f B <url-of-B>
git merge -s ours --no-commit B/master
git read-tree --prefix=subdir/Iwant/to/put/B/in/ -u B/master
git commit -m "Merge B as subdirectory in subdir/Iwant/to/put/B/in."
Po tych poleceniach i przejściu do katalogu subdir / Iwant / to / put / B / in, widzę wszystkie pliki B, ale git log
na każdym z nich wyświetla się tylko komunikat zatwierdzenia „Scal B jako podkatalog w podkatalogu / Iwant / to / put /Kosz." Historia ich plików, jaka jest w B, zostaje utracona.
To, co wydaje się działać (ponieważ jestem początkującym w git, mogę się mylić) jest następujące:
git remote add -f B <url-of-B>
git checkout -b B_branch B/master # make a local branch following B's master
git filter-branch --index-filter \
'git ls-files -s | sed "s-\t\"*-&subdir/Iwant/to/put/B/in/-" |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD
git checkout master
git merge B_branch
Powyższe polecenie dla filter-branch pochodzi z git help filter-branch
, w którym zmieniłem tylko ścieżkę subdir.
gitk
mówi o historii? W przeszłości z powodzeniem korzystałem z funkcji scalania poddrzewa git. Być może możesz ujawnić swoje dokładne polecenia? Nie jestem pewien, czy git-filter-branch to właściwe podejście. Mogę polecić wypróbowanie git-fast-export i git-fast-import, aby zsyntetyzować nową historię.gitk
pokazuje dwa repozytoria połączone na swoich końcówkach i niepowiązane w ich początkowych zatwierdzeniach. (Czy pomogłoby, gdybym opublikował zrzuty ekranu widoku historii gitk? Czy mogę?) Niestety, poszczególne pliki zdalnego repozytorium nie zachowały swojej historii, jeśli to zrobiłem w terminalugit log <file-from-remote-repo>
. Patrzę nagit-fast-export
igit-fast-import
; Jestem nowy w git. Zmienię moje pytanie, aby dokładnie pokazać, jakich poleceń użyłem w poddrzewie git. Bardzo dziękuję za odpowiedź.Odpowiedzi:
Po uzyskaniu pełniejszego wyjaśnienia tego, co się dzieje, myślę, że to rozumiem, aw każdym razie na dole mam obejście. W szczególności uważam, że to, co się dzieje, polega na tym, że wykrywanie zmiany nazwy jest oszukiwane przez scalanie poddrzewa z --prefix. Oto mój przypadek testowy:
Tworzymy katalogi git aib z kilkoma zatwierdzeniami w każdym. Dokonujemy scalenia poddrzewa, a następnie wykonujemy ostateczne zatwierdzenie w nowym poddrzewie.
Bieg
gitk
(w z / a) pokazuje, że historia się pojawia, możemy ją zobaczyć. Bieggit log
pokazuje, że historia się pojawia. Jednak spojrzenie na konkretny plik ma problem:git log bdir/B
Cóż, jest sztuczka, którą możemy zagrać. Możemy przyjrzeć się historii przed zmianą nazwy konkretnego pliku za pomocą --follow.
git log --follow -- B
. Jest to dobre, ale nie świetne, ponieważ nie łączy historii przed scaleniem z po scaleniu.Próbowałem grać z -M i -C, ale nie byłem w stanie zmusić go do śledzenia jednego konkretnego pliku.
Wydaje mi się, że rozwiązaniem jest poinformowanie gita o zmianie nazwy, która będzie miała miejsce w ramach scalania poddrzewa. Niestety drzewo git-read-tree jest dość wybredne, jeśli chodzi o scalanie poddrzewów, więc musimy przejść przez katalog tymczasowy, ale może to zniknąć przed zatwierdzeniem. Następnie możemy zobaczyć pełną historię.
Najpierw utwórz repozytorium „A” i wykonaj kilka zatwierdzeń:
Po drugie, utwórz repozytorium „B” i wykonaj kilka zatwierdzeń:
I sztuczka, aby to zadziałało : zmusić Gita do rozpoznania zmiany nazwy, tworząc podkatalog i przenosząc do niego zawartość.
Wróć do repozytorium „A” i pobierz i scal zawartość „B”:
Aby pokazać, że są teraz połączone:
Aby udowodnić, że pełna historia jest zachowana w połączonym łańcuchu:
Po wykonaniu tej czynności uzyskujemy historię, ale problem polega na tym, że jeśli faktycznie przechowujesz stare repozytorium „b” i od czasu do czasu łączysz się z nim (powiedzmy, że jest to w rzeczywistości oddzielnie obsługiwane repozytorium strony trzeciej), masz kłopoty, ponieważ ta strona trzecia nie dokonał zmiany nazwy. Musisz spróbować scalić nowe zmiany ze swoją wersją b ze zmianą nazwy i obawiam się, że to nie pójdzie gładko. Ale jeśli b odchodzi, wygrywasz.
źródło
git log --stat
). Nie zauważyłem też--follow
zmiany w dokumentacji git log; wydaje się bardzo przydatne przy zmianie nazw. Bardzo dziękuję za tak szczegółową i pouczającą odpowiedź!git
tego programufatal: refusing to merge unrelated histories
należy się uruchomićgit merge -s ours --allow-unrelated-histories --no-commit B/master
.git-subtree
jest skryptem zaprojektowanym do dokładnie tego przypadku użycia, polegającego na scalaniu wielu repozytoriów w jedno przy jednoczesnym zachowaniu historii (i / lub dzieleniu historii poddrzew, chociaż wydaje się to nie mieć związku z tym pytaniem). Jest dystrybuowany jako część drzewa git od wersji 1.7.11 .Aby scalić repozytorium
<repo>
w rewizji<rev>
jako podkatalog<prefix>
, użyjgit subtree add
w następujący sposób:git-subtree implementuje strategię scalania poddrzewa w bardziej przyjazny dla użytkownika sposób.
Minusem jest to, że w historii połączonego pliki są prefiksu (nie w podkatalogu). Powiedzmy, że scalasz repozytorium
a
zb
. W rezultaciegit log a/f1
pokażą Ci wszystkie zmiany (jeśli istnieją) 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 zmieniasz
a
plików w repozytoriumb
, musisz to określić--follow
ścieżkę bez prefiksu. Jeśli zmienisz je w obu repozytoriach, masz 2 polecenia, z których żadne nie pokazuje wszystkich zmian.Więcej na ten temat tutaj .
źródło
<prefix>
. Np. W celu scalenia podkatalogu, który został kiedyś ręcznie przeniesiony do własnego repozytorium i chcesz go ponownie scalić.Chciałbym
git log -- file
działają bez--follow
.Krok 1 : Przepisz historię w repozytorium źródłowym, aby wyglądało na to, że wszystkie pliki zawsze istniały poniżej podkatalogu.
Utwórz tymczasową gałąź dla przepisanej historii.
Następnie użyj
git filter-branch
zgodnie z opisem w Jak mogę przepisać historię, aby wszystkie pliki, z wyjątkiem tych, które zostały już przeniesione, znajdowały się w podkatalogu? :Krok 2 : Przełącz się do repozytorium docelowego. Dodaj repozytorium źródłowe jako zdalne w repozytorium docelowym i pobierz jego zawartość.
Krok 3 : Użyj,
merge --onto
aby dodać zatwierdzenia przepisanego repozytorium źródłowego na górze repozytorium docelowego.Możesz sprawdzić dziennik, aby zobaczyć, że naprawdę dostałeś to, czego chciałeś.
Krok 4 : Po rebase jesteś w stanie „odłączonej głowy”. Możesz przewinąć mastera do nowej głowy.
Krok 5 : Na koniec trochę porządkowania: Usuń tymczasowego pilota.
źródło
git rebase
wygląda na to, że nie zezwala razem na określone opcje: "błąd: nie można łączyć opcji interaktywnych (--interactive, --exec, --rebase-scales, --preserve-scales, --keep-empty, --root + - -onto) z opcjami am (--committer-date-is-author-date) "--committer-date-is-author-date
. Sprawdzanie niezgodnych opcji zostało ostatnio dodane w git v2.19.0 ( github.com/git/git/commit/ ... ). Z opisu wynika, że i tak--committer-date-is-author-date
zostało po cichu zignorowane.filter-branch
polecenia, użyjgit filter-repo --to-subdirectory-filter <dir>
, jest to znacznie szybsze i łatwiejsze.Jeśli naprawdę chcesz zszyć rzeczy razem, spójrz na przeszczepianie. Powinieneś także używać
git rebase --preserve-merges --onto
. Istnieje również możliwość zachowania daty autora dla informacji o autorach.źródło
git filter-branch
i wydaje się, że działa, ale może twój jest lepszy. Wypróbuję to.Uważam, że następujące rozwiązanie jest dla mnie wykonalne. Najpierw przechodzę do projektu B, tworzę nową gałąź, w której już wszystkie pliki zostaną przeniesione do nowego podkatalogu. Następnie pcham tę nową gałąź do początku. Następnie idę do projektu A, dodaję i pobieram pilota B, potem wyewidencjonuję przeniesioną gałąź, wracam do mastera i scalam:
Jeśli przejdę do podkatalogu
subdir
, mogę użyćgit log --follow
i nadal mam historię.Nie jestem ekspertem od git, więc nie mogę komentować, czy jest to szczególnie dobre rozwiązanie, czy ma zastrzeżenia, ale na razie wydaje się wszystko w porządku.
źródło
Czy próbowałeś dodać dodatkowe repozytorium jako moduł podrzędny git? Nie połączy historii z repozytorium zawierającym, w rzeczywistości będzie to niezależne repozytorium.
Wspominam o tym, bo tego nie zrobiłeś.
źródło
Powiedzmy, że chcesz scalić repozytorium
a
zb
(zakładam, że znajdują się obok siebie):Do tego trzeba
git-filter-repo
zainstalować (filter-branch
jest zniechęcony ).Przykład połączenia 2 dużych repozytoriów, umieszczając jedno z nich w podkatalogu: https://gist.github.com/x-yuri/9890ab1079cf4357d6f269d073fd9731
Więcej na ten temat tutaj .
źródło
Podobnie jak odpowiedź hfs, której chciałem
git log -- file
działają bez--follow
.Jednak wybrałem nowocześniejszy
filter-repo
(zakładając, żenew
repozytorium istnieje i jest sprawdzone):możesz potrzebować naprawić konflikty (ręcznie) lub zmienić polecenie rebase, aby zawierało,
--merge -s recursive -X theirs
jeśli chcesz spróbować rozwiązać problem za pomocątheirs
wersji:kończysz na odłączonym HEAD, więc stwórz nową gałąź i połącz ją z główną uwagą, że nowoczesne repozytoria nie powinny używać gałęzi „master”, ale „main”
sprzątać
źródło