Git/저장소병합 페이지의 소스 보기
마지막으로 [b]
-- Loading page list... --
내용출력
로그인[l]
Diary
[f]
최근변경내역
[r]
페이지목록[i]
횡설수설[2]
게시판[3]
링크
수정할 수 없습니다: Git/저장소병합 는 읽기 전용 페이지입니다.
= git 저장소 두 개를 병합 =
== # 상황 == 저장소 A와 B가 있다. {{{ A - / /fileA B - / /fileB }}} A 저장소를 B에 합치면서, 기존 커밋 로그 등도 다 가져오고 싶다. (커밋 로그 같은 거 가져올 필요가 없다면... 그냥 fileA를 복사하면 된다) == # 디렉토리 이동이 필요없는 경우 == {{{ B - / /fileA /fileB }}} 이렇게 만들 경우는 쉽다. {{{#!vim sh $ cd B # A저장소의 master브랜치를 fetch로 가져온다 (branch_A는 임의로 지은 이름) $ git fetch ../A/ master:branch_A # B저장소의 master브랜치에서 그것을 병합한다 $ git merge branch_A }}} 뭐 그나마 기분이 나쁜 거라면, 시작 커밋이 서로 다른 두 히스토리를 합쳤으니까 한 커밋에서 시작하는 게 아니라 두 커밋에서 시작해서 나중에 합쳐진 형태의 그래프가 된다. 원한다면 한쪽 히스토리와 다른 히스토리를 연결할 수도 있다. [[Git]]의 "두 저장소를 잇기"와 "CVS에서 Git로 이전하기" 참조. == # 한쪽 저장소를 서브디렉토리에 두고 싶은 경우 == {{{ B - / /A/fileA /fileB }}} 이렇게 하려니, 은근히 복잡하다. 사실 이게 맞는지 제대로 정리가 안 되었는데, 반나절 동안 직접 해보면서 발견한 내용만 적어본다. 아래 내용들은 거의 다 [http://stackoverflow.com/questions/1683531/how-to-import-existing-git-repository-into-another merge - How to import existing GIT repository into another? - Stack Overflow] 질문글에 달린 답변들이 출처이다. === # fetch로 가져오고 mv로 옮기고 merge === * [http://stackoverflow.com/a/1684694 관련 답변] {{{#!vim sh # 여기서는 remote 저장소 추가를 했는데, 안 하고 그냥 위와 같이 fetch해도 될 것이다 [B (master)]$ git remote add repoA ../A/ [B (master)]$ git fetch repoA From ../A * [new branch] master -> repoA/master # 임시 브랜치를 만들고 [B (master)]$ git checkout -b TEMP repoA/master Branch TEMP set up to track remote branch master from repoA. Switched to a new branch 'TEMP' # fileA를 A 서브디렉토리로 옮기고 커밋 [B (TEMP)]$ mkdir A [B (TEMP)]$ git mv fileA A/fileA [B (TEMP)]$ git commit -m "move fileA to A/" [TEMP d13a3ce] move fileA to A/ 1 files changed, 0 insertions(+), 0 deletions(-) rename fileA => A/fileA (100%) # master 브랜치에서 병합 [B (TEMP)]$ git checkout master Switched to branch 'master' [B (master)]$ git merge TEMP Merge made by the 'recursive' strategy. A/fileA | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) create mode 100644 A/fileA # 뒷정리 [B (master)]$ git remote rm repoA [B (master)]$ git branch -d TEMP Deleted branch TEMP (was d13a3ce). }}} 이렇게 하면 git log를 했을 때 두 저장소의 로그도 잘 보인다. 그리고 A디렉토리로 옮기는 것을 나타내는 커밋 로그도 있어서 직관적이다. 문제는 뭐냐 하면, '''A 서브디렉토리 아래 있는 파일들의 개별 로그를 보는 게 귀찮다''' {{{#!vim sh # 이렇게 하면 A로 옮긴 이력만 나온다 $ git log -- A/fileA commit d13a3ce29b1ffccc5ce1cda062883c750ddac390 Author: Geunyoung Park
Date: Thu Feb 11 00:42:59 2016 +0900 move fileA to A/ # --follow를 붙여주어 rename에 관한 이력도 추적하게 해야 한다 $ git log --follow A/fileA d13a3ce move fileA to A/ b010c01 A2 abcad74 init A }}} 그런데 --follow 옵션을 붙일 때는 대상 파일을 하나밖에 지정할 수 없다. (보통은 파일 하나만 보면 충분하겠지만) === # subtree merge === * [http://stackoverflow.com/a/8396318 관련 답변] {{{#!vim sh # 역시 원격 저장소를 추가하고 fetch [B (master)]$ git remote add repoA ../A/ [B (master)]$ git fetch repoA warning: no common commits remote: Counting objects: 6, done. remote: Compressing objects: 100% (2/2), done. remote: Total 6 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (6/6), done. From ../A * [new branch] master -> repoA/master # 서브트리 병합인데, 이 단락들의 동작 원리는 나도 잘 모르겠다 [B (master)]$ git merge -s ours --no-commit repoA/master Automatic merge went well; stopped before committing as requested [B (master|MERGING)]$ git read-tree --prefix=A/ -u repoA/master [B (master|MERGING)]$ git commit -m "imported A as a subtree." [master 8d9a587] imported A as a subtree. }}} 첫번째 방법과 비교하면, A 서브디렉토리로 이동하는 커밋이 따로 없다. 그리고 아마도 이게 중요한 장점일 것 같은데, '''A저장소가 갱신되면 그것을 받아와서 반영할 수 있다'''. {{{#!vim sh # 원래의 A저장소가 갱신된 후에 B저장소 쪽에서 [B (master)]$ git pull -s subtree repoA master remote: Counting objects: 5, done. remote: Total 3 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. From ../A * branch master -> FETCH_HEAD Merge made by the 'subtree' strategy. A/fileA | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) }}} 그러니까, 별개의 프로젝트로 관리되고 있는 저장소를 통채로 가져와서 내 프로젝트의 일부로 사용하면서, 원 프로젝트쪽에서 새로 변경된 사항이 생기면 그것을 바로 가져와서 반영할 수 있는 것이다. 아마 최근 버전의 git은 subtree 병합에 대한 명령어가 따로 있는 것 같았다. [[/서브프로젝트]] 문서도 참고하자. 그런데 여기서 첫 번째와 똑같은 단점이 나온다. fileA의 변경이력만 추려내려면 귀찮다. 게다가 더 헷갈린다. {{{#!vim sh # 이렇게 하면 역시 B에 병합하는 커밋만 나옴 $ git log -- A/fileA commit 8d9a5873987f558808ec4f1ec732cedccbb5e866 Merge: 42275bc b010c01 Author: Geunyoung Park
Date: Thu Feb 11 01:01:50 2016 +0900 imported A as a subtree. # 게다가 이렇게 하면, 이젠 아무것도 안 나옴 $ git log --follow -- A/fileA # --follow는 여전히 붙인 채로 # 우리가 prefix로 지정한 A/ 부분은 빼고 원래 파일명만 써줘야 한다 $ git log --follow -- fileA d48c21d A3 b010c01 A2 abcad74 init A }}} === # format-patch와 am - 패치 파일을 만들고, 그것을 다시 읽음 === * [http://stackoverflow.com/a/4142653 관련 답변] {{{#!vim sh # 먼저 A디렉토리에서 # 패치 파일을 저장할 임의의 디렉토리를 만들고 [A (master)]$ mkdir ~/temp/patch_A # 거기에 패치 파일을 생성 (prefix로 내가 원하는 서브디렉토리 이름 A를 적어준 것에 유의) [A (master)]$ git format-patch --root HEAD --no-stat -o ~/temp/patch_A --src-prefix=a/A/ --dst-prefix=b/A/ /home/gypark/temp/patch_A/0001-init-A.patch # 이런 파일들이 생긴다 /home/gypark/temp/patch_A/0002-A2.patch # 이제 B디렉토리로 이동 [A (master)]$ cd ../B # 저 패치 파일을 읽어서 적용 [B (master)]$ git am ~/temp/patch_A/* Applying: init A Applying: A2 # 로그를 확인해보면 이렇게 이어져 있다. [B (master)]$ git log --graph * commit c28efee9c66f7c98423f0fb3f207cd1c4e913f3d | A2 | * commit 820ca0d824a0183c294ba431d1fc103c80c975c6 | init A | * commit 42275bcb55ccc26c77c045b66a2c7f4fef9758fc | B2 | * commit 1128d425ca9716dd696ea586d9d58baa12a76e6b init B }}} git format-patch는, 원래 이메일로 보낼 패치 내용을 생성해주는 기능인가본데, 이걸 생성하고 다시 읽음으로써 B저장소에 새롭게 A저장소와 동일한 커밋들을 만들어낸다. 장점은, 보다시피 히스토리가 하나의 라인으로 이어진다. (이게 오히려 맘에 안 들 수도 있겠다) 그리고 무엇보다도, 내가 제일 짜증나던 "A의 개별 파일 로그보기"가 딱 원하는 대로 된다. {{{#!vim sh # 익숙하고 직관적이다 $ git log -- A/fileA c28efee A2 820ca0d init A }}} 그런데 저 링크에 가서 해당 답변글에 달린 코멘트를 보면, 잘 안 되어 에러가 나거나 하는 경우도 있는 듯. 내 경우에도 패치 파일 생성 과정에서 개행 문자 처리라든가 해서 경고가 주루룩 뜨기도 하고 그랬음. 그리고 * [http://blog.neutrino.es/2012/git-copy-a-file-or-directory-from-another-repository-preserving-history/ Git: Copy a file or directory from another repository preserving the history | synaptic fault] 이 글에서는 한쪽 저장소에서 자신이 원하는 파일들만, 변경 이력까지 유지하면서 가져오는 얘기를 하고 있음. 비슷하게 format-patch와 am 명령을 쓴다. == # 기타 & comments == 더 편하게 할 수 있는 방법(특히 git 버전업에 따라서) 아시면 제보 받습니다. :-)
---- [[컴퓨터분류]]
Git/저장소병합
페이지로 돌아가기 |
다른 수정본 보기