programing

여러 Git 저장소 결합

muds 2023. 6. 25. 20:38
반응형

여러 Git 저장소 결합

예를 들어, 제가 다음과 같은 설정을 가지고 있다고 가정해 보겠습니다.

phd/code/
phd/figures/
phd/thesis/

역사적인 이유로 이들은 모두 고유한 깃 저장소를 가지고 있습니다.하지만 저는 그것들을 하나의 것으로 결합하여 일을 조금 단순화하고 싶습니다.예를 들어, 지금 당장은 두 가지 변경 사항을 적용하고 다음과 같은 작업을 수행해야 할 수 있습니다.

cd phd/code
git commit 
cd ../figures
git commit

공연을 하는 것만으로도 (지금) 좋을 것 같습니다.

cd phd
git commit

서브모듈을 사용하거나 하위 저장소에서 꺼내는 방법이 몇 가지 있는 것 같습니다. 하지만 제가 찾고 있는 것보다 조금 더 복잡합니다.적어도, 난 행복할 것입니다.

cd phd
git init
git add [[everything that's already in my other repositories]]

하지만 그건 한 줄기 선이 아닌 것 같아요.?에 뭐가 있습니까?git그게 나를 도와줄 수 있습니까?

제가 제시한 해결책은 다음과 같습니다.

  1. 먼저 pdh 디렉토리의 전체 백업을 수행합니다.나는 당신의 수년간의 노고에 대한 책임을 지고 싶지 않습니다! ;-)

     $ cp -r phd phd-backup
    
  2. 내이동의 합니다.phd/codephd/code/code기록을 수정하여 항상 있었던 것처럼 보이게 합니다(git's filter-filter 명령 사용).

     $ cd phd/code
     $ git filter-branch --index-filter \
         'git ls-files -s | sed "s#\t#&code/#" |
          GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
          git update-index --index-info &&
          mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD
    
  3. 의내도동일다니합의 입니다.phd/figures그리고.phd/thesis 바꾸기 (그냥교체))code와 함께figures그리고.thesis).

이제 디렉터리 구조는 다음과 같습니다.

    phd
      |_code
      |    |_.git
      |    |_code
      |         |_(your code...)
      |_figures
      |    |_.git
      |    |_figures
      |         |_(your figures...)
      |_thesis
           |_.git
           |_thesis
                |_(your thesis...)
  1. 그런 다음 루트 디렉터리에 git 저장소를 만들고 모든 항목을 해당 디렉터리로 가져온 다음 이전 리포지토리를 제거합니다.

     $ cd phd
     $ git init
    
     $ git pull code
     $ rm -rf code/code
     $ rm -rf code/.git
    
     $ git pull figures --allow-unrelated-histories
     $ rm -rf figures/figures
     $ rm -rf figures/.git
    
     $ git pull thesis --allow-unrelated-histories
     $ rm -rf thesis/thesis
     $ rm -rf thesis/.git
    

마지막으로, 이제 원하는 것을 얻을 수 있습니다.

    phd
      |_.git
      |_code
      |    |_(your code...)
      |_figures
      |    |_(your figures...)
      |_thesis
           |_(your thesis...)

이 절차의 한 가지 좋은 점은 버전이 아닌 파일과 디렉터리를 그대로 유지한다는 것입니다.


하지만 한 마디 경고: 만약 당신이code디렉터리에 이미 다음이 있습니다.code잘못될 수 .figures그리고.thesis 파일의 을 변경하십시오.그런 경우 다음 전체 절차를 수행하기 전에 해당 디렉토리 또는 파일의 이름을 변경하십시오.

$ cd phd/code
$ git mv code code-repository-migration
$ git commit -m "preparing the code directory for migration"

절차가 완료되면 다음 마지막 단계를 추가합니다.

$ cd phd
$ git mv code/code-repository-migration code/code
$ git commit -m "final step for code directory migration"

만약에 론만, 에약물.code이 아닌, 하디렉파버아닙전다니이이일또위는리터▁use▁sub다아니를 사용하세요. 그냥 사용하십시오.mvgit mv그리고 그것에 대해 잊어버립니다.git commits의

git-stitch-repo 의 출력을 처리합니다.git-fast-export --all --date-order git에 합니다.git-fast-import모든 원본 리포지토리의 기록을 존중하는 새 커밋 트리에 모든 커밋이 포함된 새 리포지토리를 만듭니다.

예를 들어, (이전 답변과 유사하지만 더 간단한 명령을 사용하여) 각각의 오래된 저장소에서 콘텐츠를 적절하게 명명된 하위 저장소로 이동시키는 커밋을 만들 수 있습니다.

$ cd phd/code
$ mkdir code
# This won't work literally, because * would also match the new code/ subdir, but you understand what I mean:
$ git mv * code/
$ git commit -m "preparing the code directory for migration"

그런 다음 다음 다음과 같이 smth를 수행하여 세 개의 개별 저장소를 하나의 새 저장소로 병합합니다.

$ cd ../..
$ mkdir phd.all
$ cd phd.all
$ git init
$ git pull ../phd/code
...

그러면 기록은 저장되지만 단일 레포로 계속 진행됩니다.

하위 트리 병합 전략을 시도할 수 있습니다.그러면 repo B를 repo A로 병합할 수 있습니다.보다 유리한 점git-filter-branch리포 A(SHA1 합계 깨기)의 이력을 다시 작성할 필요가 없는 것입니까?

git-filter-branch 솔루션은 잘 작동하지만 git repo가 SVN 가져오기에서 가져온 경우 다음과 같은 메시지와 함께 실패할 수 있습니다.

Rewrite 422a38a0e9d2c61098b98e6c56213ac83b7bacc2 (1/42)mv: cannot stat `/home/.../wikis/nodows/.git-rewrite/t/../index.new': No such file or directory

이 경우 필터 분기에서 초기 수정본을 제외해야 합니다. 즉, 다음을 변경합니다.HEAD의 끝에[SHA of 2nd revision]..HEAD참조:

http://www.git.code-experiments.com/blog/2010/03/merging-git-repositories.html

아리스토텔레스 파갈치스의 대답의 git-stitch-repo는 단순하고 선형적인 역사를 가진 저장소에서만 작동합니다.

MiniQuark의 답변은 모든 리포지토리에 대해 작동하지만 태그 및 분기를 처리하지 않습니다.

저는 MiniQuark가 설명하는 것과 같은 방식으로 작동하는 프로그램을 만들었지만, 하나의 병합 커밋(N개의 부모와 함께)을 사용하고 이러한 병합 커밋을 가리키는 모든 태그와 분기를 다시 만듭니다.

git-merge-repos 저장소의 사용 예를 참조하십시오.

@MiniQuark 솔루션은 많은 도움이 되었지만 안타깝게도 소스 저장소에 있는 태그를 고려하지 않습니다(적어도 제 경우).@MiniQuark 답변에 대한 저의 개선점은 아래와 같습니다.

  1. 먼저 구성된 repo 및 병합된 repos를 포함하는 디렉터리를 만들고, 병합된 각 디렉터리에 대한 디렉터리를 만듭니다.

    mkdir new_dir
    mkdir new_mkdir/코드
    mkdir new_상의/상의
    mkdir new_continue/논문

  2. 각 리포지토리를 풀하고 모든 태그를 가져옵니다. (다음에 대한 지침만 표시)code하위 디렉터리)

    cd new_module/code
    잽싸게
    git pull ../../original_dll/코드 마스터
    git fetch ../../original_betch/coderefs/refs/*:refs/refs/*

  3. (MiniQuark 답변의 포인트 2에 대한 개선 사항) 내용 이동new_phd/code로.new_phd/code/code추가code_ 태그 앞에 접두사

    git filter-filter --index-filter 'gitls-files -s | sed "s-\t\"*-&code/--" | GIT_INDEX_FILE.new git update-index --index-info & mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' --태그-name 필터 's "s "s-code_code_"&" - 헤드

  4. 이렇게 하면 필터 분기를 수행하기 전보다 두 배 많은 태그가 생성됩니다.이전 태그는 repo에 남아 있고 새 태그는code_접두사가 추가되었습니다.

    tag 그깃
    mytag1
    code_mytag1

    이전 태그를 수동으로 제거:

    ls.git/refs/sys/* | grep -v "/code_" | xargs rm

    다른 하위 디렉터리에 대해 지점 2,3,4를 반복합니다.

  5. 이제 우리는 @MiniQuark anwers point 3과 같은 디렉토리 구조를 가지고 있습니다.

  6. , 한 후 MiniQuark answer를 하기 전에 miniQuark answer의 4번 포인트처럼 ..gittags:dir, fetch 태그:

    git fetch catalog refs/debug/*:refs/debug/*

    계속...

이것은 또 다른 해결책일 뿐입니다.누군가에게 도움이 되었으면 좋겠어요, 저에게 도움이 되었어요 :)

이 작업을 수행하는 도구를 만들었습니다.사용되는 방법은 유사하지만(내부적으로 --filter-branch와 같은 것을 만듭니다) 더 친숙합니다.GPL 2.0

http://github.com/geppo12/GitCombineRepo

실제로 git-stitch-repo는 주석이 달린 태그를 포함하여 분기와 태그를 지원합니다(보고한 버그가 있음을 발견하고 수정되었습니다).제가 유용하다고 생각한 것은 태그입니다.태그가 커밋에 연결되어 있고 일부 솔루션(Eric Lee의 접근 방식과 같은)이 태그를 처리하지 못하기 때문입니다.가져온 태그에서 분기를 생성하려고 하면 모든 Git Merge/Move를 실행 취소하고 통합 리포지토리가 태그의 원본 리포지토리와 거의 동일한 것처럼 다시 보냅니다.또한 병합/통합된 여러 리포지토리에서 동일한 태그를 사용하는 경우에도 문제가 있습니다.예를 들어, repo의 A 광고 B가 있고 둘 다 rel_1.0 태그가 있는 경우.repo A와 repo B를 repo AB로 병합합니다.rel_1.0 태그가 두 개의 서로 다른 커밋(A용과 B용)에 있으므로 AB에서 볼 수 있는 태그는 무엇입니까?가져온 repo A의 태그 또는 가져온 repo B의 태그 중 하나이지만 둘 다는 아닙니다.

git-stitch-repo는 rel_1.0-A 및 rel_1.0-B 태그를 만들어 이 문제를 해결하는 데 도움이 됩니다.rel_1.0 태그를 체크아웃하지 못하고 둘 다 예상할 수 있지만 적어도 둘 다 볼 수 있으며, 이론적으로 두 태그를 공통 로컬 분기로 병합한 다음 해당 병합된 분기에 rel_1.0 태그를 만들 수 있습니다(소스 코드를 변경하지 않고 병합하는 것으로 가정).각 repo의 분기처럼 로컬 분기로 병합할 수 있으므로 분기로 작업하는 것이 좋습니다.(dev-a 및 dev-b는 로컬 dev 분기에 병합된 다음 오리진으로 푸시할 수 있습니다.)

당신이 제안한 순서는

git init
git add *
git commit -a -m "import everything"

효과는 있겠지만 커밋 기록은 잃게 될 것입니다.

주 프로젝트 내에서 두 번째 프로젝트를 병합하는 방법

두 번째 프로젝트에서

git fast-export --all --date-order > /tmp/secondProjectExport

기본 프로젝트:

git checkout -b secondProject
git fast-import --force < /tmp/secondProjectExport

이 지점에서는 수행해야 하는 모든 중대한 변환을 수행하고 이를 수행합니다.

그런 다음 마스터로 돌아가 두 분기 간의 고전적 병합:

git checkout master
git merge secondProject

저도 여기에 제 해결책을 넣을게요.기본적으로 꽤 간단한 bash 스크립트 래퍼입니다.git filter-branch다른 솔루션과 마찬가지로 마스터 분기만 마이그레이션하고 태그는 마이그레이션하지 않습니다.그러나 전체 마스터 커밋 기록은 마이그레이션되고 짧은 bash 스크립트이므로 사용자가 비교적 쉽게 검토하거나 수정할 수 있습니다.

https://github.com/Oakleon/git-join-repos

이 bash 스크립트는 sed문자 문제(예: MacOS)와 누락된 파일 문제를 해결합니다.

export SUBREPO="subrepo"; # <= your subrepository name here
export TABULATOR=`printf '\t'`;
FILTER='git ls-files -s | sed "s#${TABULATOR}#&${SUBREPO}/#" |
  GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
  git update-index --index-info &&
  if [ -f "$GIT_INDEX_FILE.new" ]; then mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE; else echo "git filter skipped missing file: $GIT_INXEX_FILE.new"; fi'

git filter-branch --index-filter "$FILTER" HEAD

이것은 miniquark, marius-butuc Ryan의 게시물을 조합한 것입니다.그들에게 건배!

IntelliJ IDEA Community Edition의 Git 통합을 통해 3개의 Git 저장소를 하나로 수동으로 결합했습니다.

  1. 새 repo를 만들고, 빈 README.md 파일로 새 커밋을 마스터 분기에 추가합니다.
  2. 각각 3개의 리포지토리 이름과 해당 리포지토리의 원격 URL을 사용하여 새 리포지토리에 대한 3개의 원격을 추가합니다.Git Fetch를 실행합니다.
  3. 이 "" " " " 인새 지점을 만듭니다.temp마스터 브랜치를 기반으로 하여 마스터 브랜치를 오염시키지 않고 다시 시작할 수 있습니다.다음 항목을 확인하십시오.temp분점.
  4. 원격 분기 하나(리포지토리 하나)의 커밋만 표시하려면 선택합니다.
  5. 모든 커밋을 선택하고 마우스 오른쪽 버튼을 클릭하여 Cerry-Pick합니다.
  6. 이 리포지토리에 대한 디렉터리 구조를 만든 다음 파일을 리포지토리로 이동하고 커밋합니다.
  7. 다른 2개의 원격 분기(리포지토리)에 대해 4~6단계를 반복합니다.
  8. 것이 OK일 때, 든것이정때일, 의모변병합다니합사의 합니다.temp본분지로 분기하다

그런 다음 마스터 분기에 대한 오리진 원격 URL을 추가하고 푸시합니다.

언급URL : https://stackoverflow.com/questions/277029/combining-multiple-git-repositories

반응형