기존 Git 저장소를 다른 저장소로 가져오는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/1683531

  •  18-09-2019
  •  | 
  •  

문제

라는 폴더에 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 링크를 설명합니다.

  1. 저장소의 고유 이름
  2. 저장소의 상대 경로(.gitlinks 파일의 경로에서 시작됨)
  3. git clone 명령 저장소에 사용될 git 저장소
  4. 빈 줄이나 #으로 시작하는 줄은 구문 분석되지 않습니다(주석으로 처리).

마지막으로 루트 샘플 저장소를 업데이트해야 합니다.

# 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 재귀 하위 모듈 종속성 문제.

나는 그렇게하는 쉬운 방법을 모른다. 당신은 이것을 할 수 있습니다 :

  1. GIT 필터 브랜치를 사용하여 XXX 저장소에 ZZZ 슈퍼 디렉토리를 추가하십시오.
  2. 새 지점을 YYY 저장소로 밀어 넣으십시오
  3. 푸시 된 가지를 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)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top