기존 Git 저장소를 다른 저장소로 가져오는 방법은 무엇입니까?
문제
라는 폴더에 Git 저장소가 있습니다. 트리플 엑스, 그리고 두 번째 Git 저장소가 있습니다. YYY.
나는 트리플 엑스 저장소에 YYY 이름이 하위 디렉터리인 저장소 쿨쿨 모두 추가하고 트리플 엑스님의 변경 내역을 다음으로 변경: YYY.
이전 폴더 구조:
XXX
|- .git
|- (project files)
YYY
|- .git
|- (project files)
다음 이후의 폴더 구조:
YYY
|- .git <-- This now contains the change history from XXX
|- ZZZ <-- This was originally XXX
|- (project files)
|- (project files)
이것이 가능합니까, 아니면 하위 모듈을 사용해야 합니까?
해결책
아마도 가장 간단한 방법은 트리플 엑스 지점에 물건을 넣다 YYY 그런 다음 마스터에 병합합니다.
~ 안에 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
나는 실제로 몇 개의 저장소로 이것을 시도했고 작동합니다.같지 않은 Jörg의 답변 다른 저장소를 계속 사용할 수는 없지만 어쨌든 그렇게 지정하지는 않은 것 같습니다.
메모:이것은 원래 2009년에 작성되었으므로 git은 아래 답변에 언급된 하위 트리 병합을 추가했습니다.물론 이 방법이 여전히 작동하기는 하지만 나는 아마도 오늘 그 방법을 사용할 것입니다.
다른 팁
두 번째 저장소의 정확한 커밋 기록을 유지하려면 향후 업스트림 변경을 쉽게 병합 할 수있는 능력을 유지하려면 여기에 원하는 방법이 있습니다. 하위 트리의 수정되지 않은 이력이 리포지토리로 가져 오려고 합병 된 저장소를 하위 디렉토리로 이동시키기위한 하나의 병합 커밋입니다.
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."
SO와 같은 업스트림 변경을 추적 할 수 있습니다.
git pull -s subtree XXX_remote master
git은 병합을하기 전에 뿌리가있는 곳에 자체적으로 파악하므로 후속 병합에 접두사를 지정할 필요가 없습니다.
2.9 이전의 git 버전: 당신은 통과 할 필요가 없습니다 --allow-unrelated-histories
옵션 git merge
.
사용하는 다른 답변의 방법 read-tree
그리고 건너 뜁니다 merge -s ours
단계는 CP로 파일을 복사하고 결과를 커밋하는 것과 효과적으로 다르지 않습니다.
원래 소스에서 왔습니다 Github의 "Subtree Merge"도움말 기사.
git-subtree
역사를 보존하는 동안 여러 리포지토리를 하나로 병합하는이 사용 사례를 위해 설계된 스크립트입니다 (이 질문과 관련이없는 것 같습니다). 그것은 git 트리의 일부로 배포됩니다 릴리스 1.7.11 이후.
저장소를 병합합니다 <repo>
개정시 <rev>
하위 디렉토리로 <prefix>
, 사용 git subtree add
다음과 같이 :
git subtree add -P <prefix> <repo> <rev>
git-subtree는 하위 트리는 전략을 병합합니다 보다 사용자 친화적 인 방식으로.
귀하의 경우, 내부 리포지토리 YYY의 경우 다음을 실행합니다.
git subtree add -P ZZZ /path/to/XXX.git master
Git 커뮤니티에서 공동으로 알려진 Git 저장소 자체에는 잘 알려진 인스턴스가 있습니다.가장 멋진 합병"(제목 라인 후 Linus Torvalds는이 병합을 설명하는 GIT 메일 링거의 이메일에 사용되었습니다).이 경우, gitk
현재 Git Propect의 일부인 Git Gui는 실제로 별도의 프로젝트였습니다. Linus는 그 저장소를 GIT 저장소로 병합했습니다.
- git 리포지토리에서 항상 GIT의 일부로 개발 된 것처럼 보입니다.
- 모든 역사는 그대로 유지됩니다
- 기존 저장소에서 독립적으로 개발 될 수 있으며 변경 사항은 단순히
git pull
에드.
이메일에는 재현하는 데 필요한 단계가 포함되어 있지만 희미한 마음을위한 것은 아닙니다. 첫째, Linus 썼다 git, 그래서 그는 아마도 당신이나 나보다 그것에 대해 조금 더 알고있을 것입니다. 둘째, 이것은 거의 5 년 전이었고 Git은 개선되었습니다. 상당히 그 이후로 아마 훨씬 쉬울 것입니다.
특히, 나는 요즘 특정 경우에 Gitk 하위 모듈을 사용할 것이라고 생각합니다.
그렇게하는 간단한 방법은 git 형식 패치를 사용하는 것입니다.
2 개의 git 리포지토리가 있다고 가정합니다 foo 그리고 술집.
foo 포함
- foo.txt
- .git
술집 포함
- bar.txt
- .git
그리고 우리는 끝내고 싶습니다 foo 포함 술집 역사 와이 파일 :
- foo.txt
- .git
- foobar/bar.txt
그래서 그렇게하려면 :
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/*
그리고 우리가 바에서 모든 메시지 커밋을 다시 작성하려면, 우리는 Linux에서 할 수 있습니다.
git filter-branch --msg-filter 'sed "1s/^/\[bar\] /"' COMMIT_SHA1_OF_THE_PARENT_OF_THE_FIRST_BAR_COMMIT..HEAD
각 커밋 메시지의 시작 부분에 [Bar]가 추가됩니다.
기반을 둔 이 기사에서, 하위 트리를 사용하는 것은 나에게 효과가 있었고 해당 기록 만 이전되었습니다. 누구나 단계가 필요한 경우 여기에 게시합니다 (자리 표시자를 귀하에게 적용 가능한 값으로 바꾸십시오) :
소스 저장소에서 Subfolder Subfolder에서 새 지점으로 분할
git subtree split --prefix=<source-path-to-merge> -b subtree-split-result
Split Result Branch의 대상 레포지기 병합
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
변경 사항을 확인하고 커밋하십시오
git status
git commit
잊지 마세요
삭제하여 정리하십시오 subtree-split-result
나뭇가지
git branch -D subtree-split-result
소스 리포에서 데이터를 가져 오기 위해 추가 한 리모컨을 제거하십시오.
git remote rm merge-source-repo
이 기능은 원격 repo를 로컬 리포 디르로 복제합니다. 모든 커밋을 병합 한 후에는 저장됩니다. git log
원래 커밋과 적절한 경로를 보여줍니다.
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"
}
사용하는 방법:
cd current/package
git-add-repo https://github.com/example/example dir/to/save
약간의 변경을 수행하면 병합 된 repo의 파일/더스를 다른 경로로 이동할 수도 있습니다.
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"
통지
경로는 sed
, 합병 후 적절한 경로로 이동했는지 확인하십시오.
그만큼 --allow-unrelated-histories
매개 변수는 git> = 2.9 이후에만 존재합니다.
이것이 조금 더 간단하다고 생각하는 다른 대답을 추가합니다. repo_dest의 풀은 repo_to_import로 수행 된 다음 푸시-세트 업스트림 URL : repo_dest 마스터가 완료됩니다.
이 방법은 몇 가지 작은 저장소를 더 큰 저장소로 가져 오는 데 도움이되었습니다.
가져 오는 방법 : repo1_to_import to 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
가져 오기 전에 원래 리포에서 파일을 이름을 바꾸거나 옮기고 원래 리포지토리로 이동하십시오. 예를 들어
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
다음 링크에 설명 된 방법은이 답변에 영감을주었습니다. 더 단순 해 보였기 때문에 나는 그것을 좋아했다. 그러나 조심하십시오! 용이 있습니다! https://help.github.com/articles/importing-an-external-git-repository git push --mirror url:repo_dest
로컬 리포 기록과 상태를 원격으로 푸시합니다 (URL : repo_dest). 그러나 그것은 원격의 오래된 역사와 상태를 삭제합니다. 재미가 계속됩니다! :-이자형
제 경우에는 다른 리포지토리 (xxx)에서 일부 파일 만 가져오고 싶었습니다. 하위 트리는 나에게 너무 복잡했고 다른 솔루션은 작동하지 않았습니다. 이것이 내가 한 일입니다.
ALL_COMMITS=$(git log --reverse --pretty=format:%H -- ZZZ | tr '\n' ' ')
이를 통해 ZZZ (ZZZ)에 리버스 순서로 가져 오려는 파일에 영향을 미치는 모든 커밋 목록을 제공합니다 (RENAME를 캡처하려면 팔로우해야 할 수도 있음). 그런 다음 Target Repository (YYY)로 들어가서 다른 저장소 (XXX)를 원격으로 추가하고 마지막으로 가져 와서 다음과 같습니다.
git cherry-pick $ALL_COMMITS
모든 커밋을 지점에 추가하면 모든 파일을 기록한 모든 파일을 가지고 있으며 항상이 저장소에있는 것처럼 원하는 모든 것을 할 수 있습니다.
나는 내가 찾고 있던 상황에 있었다 -s theirs
그러나 물론이 전략은 존재하지 않습니다. 내 역사는 내가 github에 대한 프로젝트를 포장했다는 것이었고, 이제 어떤 이유로 내 현지인 master
병합 될 수 없습니다 upstream/master
나는이 지점을 지역적으로 바꾸지 않았지만. (정말로 무슨 일이 있었는지 모르겠습니다. 상류가 무대 뒤에서 더러운 푸시를했을 것 같아요?)
내가 한 일은
# 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
그래서 이제 내 master
다시 동기화됩니다 upstream/master
(그리고 비슷하게 동기화하려는 다른 분기에 대해서는 위의 것을 반복 할 수 있습니다).
보다 기본 예 안에 이 기사 리포지토리에 대한 이러한 매핑을 고려하십시오.
A
<->YYY
,B
<->XXX
이 장에서 설명한 모든 활동 (병합 후)을 제거한 후 분기를 제거하십시오. B-master
:
$ git branch -d B-master
그런 다음 변경 사항을 누릅니다.
그것은 나를 위해 작동합니다.
다른 솔루션을 제안할 수 있습니다(대체 자식 하위 모듈) 귀하의 문제에 대해 - Gil(git 링크) 도구
복잡한 git 저장소 종속성을 설명하고 관리할 수 있습니다.
또한 이에 대한 솔루션을 제공합니다. git 재귀 하위 모듈 종속성 문제.
다음과 같은 프로젝트 종속성이 있다고 가정하세요.샘플 Git 저장소 종속성 그래프
그런 다음 정의할 수 있습니다. .gitlinks
저장소 관계 설명이 포함된 파일:
# 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
각 줄은 다음 형식으로 git 링크를 설명합니다.
- 저장소의 고유 이름
- 저장소의 상대 경로(.gitlinks 파일의 경로에서 시작됨)
- git clone 명령 저장소에 사용될 git 저장소
- 빈 줄이나 #으로 시작하는 줄은 구문 분석되지 않습니다(주석으로 처리).
마지막으로 루트 샘플 저장소를 업데이트해야 합니다.
# Clone and link all git links dependencies from .gitlinks file
gil clone
gil link
# The same result with a single command
gil update
결과적으로 필요한 모든 프로젝트를 복제하고 적절한 방식으로 서로 연결하게 됩니다.
하위 링크 저장소의 모든 변경 사항과 함께 일부 저장소의 모든 변경 사항을 커밋하려면 단일 명령으로 수행할 수 있습니다.
gil commit -a -m "Some big update"
당기기, 밀어넣기 명령은 비슷한 방식으로 작동합니다.
gil pull
gil push
Gil(git link) 도구는 다음 명령을 지원합니다.
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
자세히 알아보기 git 재귀 하위 모듈 종속성 문제.
나는 그렇게하는 쉬운 방법을 모른다. 당신은 이것을 할 수 있습니다 :
- GIT 필터 브랜치를 사용하여 XXX 저장소에 ZZZ 슈퍼 디렉토리를 추가하십시오.
- 새 지점을 YYY 저장소로 밀어 넣으십시오
- 푸시 된 가지를 YYY의 트렁크와 병합하십시오.
매력적으로 들리면 세부 사항으로 편집 할 수 있습니다.
'git mv'와 'git pull'을 사용하여 이것을 할 수 있다고 생각합니다.
나는 공정한 git noob입니다. 그래서 당신의 주요 저장소에주의하십시오 - 그러나 나는 이것을 온도로 시도했는데 작동하는 것 같습니다.
첫 번째 - xxx의 구조 이름을 yyy 내에있을 때 원하는 방법과 일치하도록 :
cd XXX
mkdir tmp
git mv ZZZ tmp/ZZZ
git mv tmp ZZZ
이제 XXX는 다음과 같습니다.
XXX
|- ZZZ
|- ZZZ
이제 'git pull'을 사용하여 변경 사항을 가져옵니다.
cd ../YYY
git pull ../XXX
이제 YYY는 다음과 같습니다.
YYY
|- ZZZ
|- ZZZ
|- (other folders that already were in YYY)