Jak zaimportować istniejące repozytorium Git do innego?
Mam repozytorium Git w folderze XXX , i mam drugie repozytorium Git o nazwie YYY .
Chcę zaimportować repozytorium XXX do repozytorium YYY jako podkatalog o nazwie ZZZ i dodać 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ę uciekać się do używania podmodułów?
15 answers
Prawdopodobnie najprostszym sposobem byłoby wyciągnięcie XXX rzeczy do gałęzi w YYY , a następnie scalenie go w master:
W YYY :
git remote add other /path/to/XXX
git fetch other
git checkout -b ZZZ other/master
mkdir ZZZ
git mv stuff ZZZ/stuff # repeat as necessary for each file/dir
git commit -m "Moved stuff to ZZZ"
git checkout master
git merge ZZZ --allow-unrelated-histories # should add ZZZ/ to master
git commit
git remote rm other
git branch -d ZZZ # to get rid of the extra branch before pushing
git push # if you have a remote, that is
[1]} właśnie próbowałem tego z kilku moich repo i to działa. W przeciwieństwie do Jörg ' s answer to nie pozwoli ci nadal korzystać z innego repo, ale i tak nie sądzę, że sprecyzowałeś to.
Uwaga: Ponieważ to zostało pierwotnie napisane w 2009 roku, git dodał połączenie podrzędne wymienione w odpowiedzi poniżej. Metodę tę pewnie bym dzisiaj zastosował, choć oczywiście metoda ta nadal działa.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-02 05:36:13
Jeśli chcesz zachować dokładną historię zatwierdzeń drugiego repozytorium, a tym samym zachować możliwość łatwego łączenia zmian w przyszłości, oto metoda, którą chcesz. Powoduje to niezmodyfikowaną historię zaimportowanego poddrzewa do repo oraz jeden commit scalający, aby przenieść scalone repozytorium do podkatalogu.
git remote add XXX_remote <path-or-url-to-XXX-repo>
git fetch XXX_remote
git merge -s ours --no-commit --allow-unrelated-histories XXX_remote/master
git read-tree --prefix=ZZZ/ -u XXX_remote/master
git commit -m "Imported XXX as a subtree."
Możesz śledzić zmiany w źródle tak:
git pull -s subtree XXX_remote master
Git sam wymyśla, gdzie są korzenie, zanim zrobi Scal, więc nie musisz określać przedrostka przy kolejnych połączeniach.
Minusem jest to, że w Scalonej historii pliki są niefixowane (Nie w podkatalogu). W rezultacie git log ZZZ/a
pokaże Ci wszystkie zmiany (jeśli występują) z wyjątkiem tych w historii Scalonej. Można zrobić:
git log --follow -- a
Ale to nie pokaże zmian innych niż w połączonej historii.
Innymi słowy, jeśli nie zmienisz plików ZZZ
w repozytorium XXX
, musisz podać --follow
i niezrealizowana ścieżka. Jeśli zmienisz je w obu repozytoriach, masz 2 polecenia, z których żadna nie pokazuje wszystkich zmian.
Wersje Git przed 2.9: nie musisz przekazywać opcji --allow-unrelated-histories
do git merge
.
Metoda w drugiej odpowiedzi, która używa read-tree
i pomija krok merge -s ours
, nie różni się skutecznie od kopiowania plików z cp i zatwierdzania wyniku.
Oryginalne źródło pochodzi z github 's" subtree Merge " help article. Oraz kolejny przydatny link .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-30 15:31:23
git-subtree
jest skryptem zaprojektowanym do tego właśnie przypadku łączenia wielu repozytoriów w jeden, zachowując historię (i / lub dzieląc historię podzbiorów, choć wydaje się to nieistotne dla tego pytania). Jest dystrybuowany jako część drzewa git od wydania 1.7.11.
Aby scalić repozytorium <repo>
w revision <rev>
jako podkatalog <prefix>
, użyj git subtree add
w następujący sposób:
git subtree add -P <prefix> <repo> <rev>
Git-subtree implementuje strategię scalania subtree w bardziej przyjazny dla użytkownika sposób.
W Twoim przypadku, wewnątrz repozytorium YYY, można uruchomić:
git subtree add -P ZZZ /path/to/XXX.git master
Minusem jest to, że w Scalonej historii pliki są niefixowane (Nie w podkatalogu). W rezultacie git log ZZZ/a
pokaże Ci wszystkie zmiany (jeśli występują) z wyjątkiem tych w historii Scalonej. Można zrobić:
git log --follow -- a
Ale to nie pokaże zmian innych niż w połączonej historii.
Innymi słowy, jeśli nie zmienisz ZZZ
plików w repozytorium XXX
, następnie należy podać --follow
i ścieżkę bez zmian. Jeśli zmienisz je w obu repozytoriach, masz 2 polecenia, z których żadna nie pokazuje wszystkich zmian.
Więcej na ten temat tutaj .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-30 15:36:40
W samym repozytorium Git jest znana taka instancja, która jest znana w społeczności Git jako " The coolest merge ever " (po temacie Linusa Torvaldsa używanym w e-mailu do listy mailingowej Git, która opisuje to połączenie). W tym przypadku, gitk
Git GUI, który teraz jest częścią Git proper, w rzeczywistości był oddzielnym projektem. Linusowi udało się połączyć to repozytorium z repozytorium Git w sposób, który
- pojawia się w Git repozytorium tak, jakby zawsze było rozwijane jako część Git,
- cała historia jest nienaruszona i
- nadal może być rozwijany niezależnie w swoim starym repozytorium, przy czym zmiany są po prostu
git pull
ed.
E-mail zawiera kroki potrzebne do odtworzenia, ale nie jest to dla osób o słabym sercu: po pierwsze, Linus napisał Git, więc prawdopodobnie wie o nim trochę więcej niż ty Czy ja, a po drugie, to było prawie 5 lat temu i Git poprawił się znacznie od tego czasu, więc może teraz jest znacznie łatwiej.
W szczególności, wydaje mi się, że obecnie używa się submodule gitk, w tym konkretnym przypadku.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55
Prostym sposobem na to jest użycie git format-patch.
Załóżmy, że mamy 2 repozytoria Gita fooi bar.
Foo zawiera:
- foo.txt
- .git
Bar zawiera:
- bar.txt
- .git
I chcemy skończyć z foo zawierającym pasek historia i te pliki:
- foo.txt
- .git
- foobar / bar.txt
Tak to zrobić:
1. create a temporary directory eg PATH_YOU_WANT/patch-bar
2. go in bar directory
3. git format-patch --root HEAD --no-stat -o PATH_YOU_WANT/patch-bar --src-prefix=a/foobar/ --dst-prefix=b/foobar/
4. go in foo directory
5. git am PATH_YOU_WANT/patch-bar/*
I jeśli chcemy przepisać wszystkie commity wiadomości z paska możemy to zrobić np. na Linuksie:
git filter-branch --msg-filter 'sed "1s/^/\[bar\] /"' COMMIT_SHA1_OF_THE_PARENT_OF_THE_FIRST_BAR_COMMIT..HEAD
Spowoduje dodanie "[bar] " na początku każdej wiadomości commit.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-10 09:58:26
Ta funkcja sklonuje zdalne repo do lokalnego katalogu repo, po połączeniu wszystkie zmiany zostaną zapisane, git log
pokaże oryginalne zmiany i właściwe ścieżki:
function git-add-repo
{
repo="$1"
dir="$(echo "$2" | sed 's/\/$//')"
path="$(pwd)"
tmp="$(mktemp -d)"
remote="$(echo "$tmp" | sed 's/\///g'| sed 's/\./_/g')"
git clone "$repo" "$tmp"
cd "$tmp"
git filter-branch --index-filter '
git ls-files -s |
sed "s,\t,&'"$dir"'/," |
GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
' HEAD
cd "$path"
git remote add -f "$remote" "file://$tmp/.git"
git pull "$remote/master"
git merge --allow-unrelated-histories -m "Merge repo $repo into master" --edit "$remote/master"
git remote remove "$remote"
rm -rf "$tmp"
}
Jak używać:
cd current/package
git-add-repo https://github.com/example/example dir/to/save
Jeśli dokonasz drobnych zmian, możesz nawet przenieść pliki / dirs scalonych repo do różnych ścieżek, na przykład:
repo="https://github.com/example/example"
path="$(pwd)"
tmp="$(mktemp -d)"
remote="$(echo "$tmp" | sed 's/\///g' | sed 's/\./_/g')"
git clone "$repo" "$tmp"
cd "$tmp"
GIT_ADD_STORED=""
function git-mv-store
{
from="$(echo "$1" | sed 's/\./\\./')"
to="$(echo "$2" | sed 's/\./\\./')"
GIT_ADD_STORED+='s,\t'"$from"',\t'"$to"',;'
}
# NOTICE! This paths used for example! Use yours instead!
git-mv-store 'public/index.php' 'public/admin.php'
git-mv-store 'public/data' 'public/x/_data'
git-mv-store 'public/.htaccess' '.htaccess'
git-mv-store 'core/config' 'config/config'
git-mv-store 'core/defines.php' 'defines/defines.php'
git-mv-store 'README.md' 'doc/README.md'
git-mv-store '.gitignore' 'unneeded/.gitignore'
git filter-branch --index-filter '
git ls-files -s |
sed "'"$GIT_ADD_STORED"'" |
GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
' HEAD
GIT_ADD_STORED=""
cd "$path"
git remote add -f "$remote" "file://$tmp/.git"
git pull "$remote/master"
git merge --allow-unrelated-histories -m "Merge repo $repo into master" --edit "$remote/master"
git remote remove "$remote"
rm -rf "$tmp"
Ogłoszenia
Paths zastępuje via sed
, więc upewnij się, że została przeniesiona w odpowiednie ścieżki po scaleniu.
Parametr --allow-unrelated-histories
istnieje tylko od git >= 2.9.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-11 12:17:26
Bazując na tym artykule , użycie subtree działa dla mnie i tylko odpowiednia historia została przeniesiona. Zamieszczanie tutaj w przypadku, gdyby ktoś potrzebował tych kroków (upewnij się, że zastąpisz symbole zastępcze wartościami mającymi zastosowanie do ciebie):
W repozytorium źródłowym podziel podfolder na nową gałąź
git subtree split --prefix=<source-path-to-merge> -b subtree-split-result
W destination repo merge w rozdzielonej gałęzi wynikowej
git remote add merge-source-repo <path-to-your-source-repository>
git fetch merge-source-repo
git merge -s ours --no-commit merge-source-repo/subtree-split-result
git read-tree --prefix=<destination-path-to-merge-into> -u merge-source-repo/subtree-split-result
Zweryfikuj zmiany i zatwierdź
git status
git commit
Nie zapomnij
Clean up poprzez usunięcie gałęzi subtree-split-result
git branch -D subtree-split-result
Usuń dodany pilot, aby pobrać dane ze źródłowego repo
git remote rm merge-source-repo
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-29 17:16:22
Użyję nazw a
(zamiast XXX
i ZZZ
) i b
(zamiast YYY
), ponieważ to sprawia, że opis jest nieco łatwiejszy do odczytania.
Powiedz, że chcesz połączyć repozytorium a
W b
(zakładam, że znajdują się obok siebie):
cd a
git filter-repo --to-subdirectory-filter a
cd ..
cd b
git remote add a ../a
git fetch a
git merge --allow-unrelated-histories a/master
git remote remove a
Do tego potrzebujeszgit-filter-repo
installed (filter-branch
is ).
Przykład połączenia dwóch dużych repozytoriów, umieszczając jeden z nich w podkatalogu: https://gist.github.com/x-yuri/9890ab1079cf4357d6f269d073fd9731
Więcej na ten temat tutaj .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-30 14:47:15
Dodanie kolejnej odpowiedzi, ponieważ myślę, że jest to nieco prostsze. Pobranie repo_dest jest wykonywane do repo_to_import, a następnie push --set-upstream URL: repo_dest master jest wykonywane.
Ta metoda zadziałała dla mnie importując kilka mniejszych repo do większego.
Jak zaimportować: repo1_to_import do repo_dest
# checkout your repo1_to_import if you don't have it already
git clone url:repo1_to_import repo1_to_import
cd repo1_to_import
# now. pull all of repo_dest
git pull url:repo_dest
ls
git status # shows Your branch is ahead of 'origin/master' by xx commits.
# now push to repo_dest
git push --set-upstream url:repo_dest master
# repeat for other repositories you want to import
Zmień nazwę lub Przenieś pliki i dirs do żądanej pozycji w oryginalnym repo przed zaimportowaniem. np.
cd repo1_to_import
mkdir topDir
git add topDir
git mv this that and the other topDir/
git commit -m"move things into topDir in preparation for exporting into new repo"
# now do the pull and push to import
Metoda opisana pod poniższym linkiem zainspirowało to odpowiedź. Podobało mi się, ponieważ wydawało się to bardziej proste. Ale uważaj! Są smoki! https://help.github.com/articles/importing-an-external-git-repository git push --mirror url:repo_dest
wypycha lokalną historię i stan repo do remote (url: repo_dest). Ale usuwa starą historię i stan pilota. Zabawa trwa! :- E
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-20 09:50:47
W moim przypadku chciałem zaimportować tylko niektóre pliki z innego repozytorium (XXX). Subtree było dla mnie zbyt skomplikowane, a inne rozwiązania nie działały. Tak zrobiłem:
ALL_COMMITS=$(git log --reverse --pretty=format:%H -- ZZZ | tr '\n' ' ')
Daje to oddzieloną spacjami listę wszystkich zmian, które mają wpływ na pliki, które chciałem zaimportować (ZZZ) w odwrotnej kolejności (być może będziesz musiał dodać --follow, aby przechwycić zmiany nazw). Następnie weszłam do repozytorium docelowego (YYY), dodałam drugie repozytorium (XXX) jako zdalne, pobrałam z niego i wreszcie:
git cherry-pick $ALL_COMMITS
Który dodaje wszystkie commity do Twojej gałęzi, będziesz miał wszystkie pliki z ich historią i możesz z nimi robić co chcesz, tak jakby zawsze były w tym repozytorium.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-27 09:22:14
Zobacz podstawowy przykład W Ten artykuł i rozważ takie mapowanie w repozytoriach:
-
A
YYY
, -
B
XXX
Po całej aktywności opisanej w tym rozdziale (po połączeniu) Usuń gałąź B-master
:
$ git branch -d B-master
Następnie wciśnij zmiany.
U mnie działa.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-18 16:59:27
Byłem w sytuacji, w której szukałem -s theirs
ale oczywiście ta strategia nie istnieje. Moja historia była taka, że rozwidlałem projekt na Githubie, a teraz z jakiegoś powodu mój lokalny master
nie mógł zostać połączony z upstream/master
, chociaż nie wprowadziłem żadnych lokalnych zmian w tej gałęzi. (Naprawdę Nie wiem , co się tam stało-myślę, że upstream zrobił jakieś brudne pchnięcia za kulisami, może?)
Skończyło się to
# as per https://help.github.com/articles/syncing-a-fork/
git fetch upstream
git checkout master
git merge upstream/master
....
# Lots of conflicts, ended up just abandonging this approach
git reset --hard # Ditch failed merge
git checkout upstream/master
# Now in detached state
git branch -d master # !
git checkout -b master # create new master from upstream/master
Więc teraz moje master
jest znowu zsynchronizowane z upstream/master
(i możesz powtórzyć powyższe dla każdej innej gałęzi, którą również chcesz zsynchronizować w podobny sposób).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-05 11:16:00
Mogę zaproponować inne rozwiązanie (alternatywa dla Git-submodules) dla Twojego problemu - gil (Git links) tool
Pozwala opisywać i zarządzać złożonymi zależnościami od repozytoriów git.
Zapewnia również rozwiązanie problemu zależności rekurencyjnych podmodułów git.
Weź pod uwagę następujące zależności projektu: przykładowy wykres zależności repozytorium git
Następnie można zdefiniować .gitlinks
Plik z repozytoriami opis relacji:
# Projects
CppBenchmark CppBenchmark https://github.com/chronoxor/CppBenchmark.git master
CppCommon CppCommon https://github.com/chronoxor/CppCommon.git master
CppLogging CppLogging https://github.com/chronoxor/CppLogging.git master
# Modules
Catch2 modules/Catch2 https://github.com/catchorg/Catch2.git master
cpp-optparse modules/cpp-optparse https://github.com/weisslj/cpp-optparse.git master
fmt modules/fmt https://github.com/fmtlib/fmt.git master
HdrHistogram modules/HdrHistogram https://github.com/HdrHistogram/HdrHistogram_c.git master
zlib modules/zlib https://github.com/madler/zlib.git master
# Scripts
build scripts/build https://github.com/chronoxor/CppBuildScripts.git master
cmake scripts/cmake https://github.com/chronoxor/CppCMakeScripts.git master
Każda linia opisuje git link w następującym formacie:
- unikalna nazwa repozytorium
- względna ścieżka repozytorium (zaczynająca się od ścieżki .plik gitlinks)
- repozytorium Git, które zostanie użyte w Komendzie git clone Oddział repozytorium do kasy
- Pusta linia lub linia zaczynająca się od # nie są przetwarzane (traktowane jako komentarz).
W końcu musisz zaktualizować swoją próbkę root repozytorium:
# Clone and link all git links dependencies from .gitlinks file
gil clone
gil link
# The same result with a single command
gil update
W rezultacie sklonujesz wszystkie wymagane projekty i połączysz je ze sobą w odpowiedni sposób.
Jeśli Chcesz zatwierdzić wszystkie zmiany w jakimś repozytorium ze wszystkimi zmianami w powiązanych repozytoriach potomnych, możesz to zrobić za pomocą jednego polecenia:
gil commit -a -m "Some big update"
Polecenia Pull, push działają w podobny sposób:
gil pull
gil push
Narzędzie Gil (Git links) obsługuje następujące polecenia:
usage: gil command arguments
Supported commands:
help - show this help
context - command will show the current git link context of the current directory
clone - clone all repositories that are missed in the current context
link - link all repositories that are missed in the current context
update - clone and link in a single operation
pull - pull all repositories in the current directory
push - push all repositories in the current directory
commit - commit all repositories in the current directory
Więcej o Git recursive submodules dependency problem .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-30 19:28:14
Nie znam łatwego sposobu na to. Możesz to zrobić:
- Użyj git filter-branch, aby dodać super-katalog ZZZ do repozytorium XXX
- Przenieś nową gałąź do repozytorium YYY Połącz popchniętą gałąź z pniem YYY.
Mogę edytować ze szczegółami, jeśli brzmi to atrakcyjnie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-05 21:06:03
Myślę, że możesz to zrobić używając 'git mv' i 'git pull'.
Jestem uczciwym git noobem - więc uważaj na swoje główne repozytorium - ale właśnie próbowałem tego w temp dir i wydaje się działać.
Po pierwsze-Zmień nazwę struktury XXX, aby pasowała do tego, jak chcesz, aby wyglądała, gdy jest w yyy:
cd XXX
mkdir tmp
git mv ZZZ tmp/ZZZ
git mv tmp ZZZ
Teraz XXX wygląda tak:
XXX
|- ZZZ
|- ZZZ
Teraz użyj 'git pull', aby pobrać zmiany w poprzek:
cd ../YYY
git pull ../XXX
Teraz YYY wygląda tak:
YYY
|- ZZZ
|- ZZZ
|- (other folders that already were in YYY)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-05 21:05:09