[git] 하위 디렉토리에 git 저장소 병합

내 작업 git 저장소의 원격 git 저장소를 하위 디렉토리로 병합하고 싶습니다. 결과 저장소에 두 저장소의 병합 된 기록이 포함되고 병합 된 저장소의 각 파일이 원격 저장소에있는 것처럼 기록이 유지되기를 원합니다. How to use the subtree merge strategy 에서 언급 한대로 하위 트리 전략을 사용해 보았지만 해당 절차를 수행 한 후 결과 저장소에는 실제로 두 저장소의 병합 된 기록이 포함되어 있지만 원격 저장소에서 오는 개별 파일은 해당 기록을 유지하지 않습니다. ( ‘git log’는 “Merged branch …”라는 메시지 만 표시합니다.)

또한 두 개의 결합 된 git 저장소가 더 이상 분리되는 것을 원하지 않기 때문에 하위 모듈을 사용하고 싶지 않습니다.

원격 저장소에서 가져온 개별 파일이 기록을 유지하는 하위 디렉토리로 다른 저장소의 원격 git 저장소를 병합 할 수 있습니까?

도움을 주셔서 대단히 감사합니다.

편집 : 현재 git filter-branch를 사용하여 병합 된 저장소 기록을 다시 쓰는 솔루션을 시도하고 있습니다. 작동하는 것 같지만 좀 더 테스트해야합니다. 나는 내 결과를보고하기 위해 돌아갈 것이다.

편집 2 : 원격 저장소의 파일 기록이 명백하게 손실되는 결과로 git의 하위 트리 전략과 함께 사용한 정확한 명령을 더 명확하게 제공하기를 바랍니다. A를 현재 작업중인 git repo로하고 B를 A에 하위 디렉토리로 통합하려는 git repo를 지정합니다. 다음을 수행했습니다.

git remote add -f B <url-of-B>
git merge -s ours --no-commit B/master
git read-tree --prefix=subdir/Iwant/to/put/B/in/ -u B/master
git commit -m "Merge B as subdirectory in subdir/Iwant/to/put/B/in."

이 명령을 실행 한 후 subdir / Iwant / to / put / B / in 디렉터리로 이동하면 B의 모든 파일이 표시되지만 git log그중 하나에 “Merge B as subdir in subdir / Iwant / to / put /큰 상자.” B에있는 파일 기록은 손실됩니다.

어떤 (나는 자식에 초보자이야 이후 내가 잘못 될 수있다) 작업으로 다음과 같다 :

git remote add -f B <url-of-B>
git checkout -b B_branch B/master  # make a local branch following B's master
git filter-branch --index-filter \
   'git ls-files -s | sed "s-\t\"*-&subdir/Iwant/to/put/B/in/-" |
        GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
                git update-index --index-info &&
        mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD
git checkout master
git merge B_branch

filter-branch에 대한 위의 명령은에서 가져 왔습니다 git help filter-branch. 여기서 저는 subdir 경로 만 변경했습니다.



답변

무슨 일이 일어나고 있는지에 대한 완전한 설명을 얻은 후, 나는 그것을 이해한다고 생각하며 어떤 경우에도 해결 방법이 있습니다. 특히, 나는 이름 변경 감지가 –prefix와의 하위 트리 병합에 속고 있다고 생각합니다. 내 테스트 케이스는 다음과 같습니다.

mkdir -p z/a z/b
cd z/a
git init
echo A>A
git add A
git commit -m A
echo AA>>A
git commit -a -m AA
cd ../b
git init
echo B>B
git add B
git commit -m B
echo BB>>B
git commit -a -m BB
cd ../a
git remote add -f B ../b
git merge -s ours --no-commit B/master
git read-tree --prefix=bdir -u B/master
git commit -m "subtree merge B into bdir"
cd bdir
echo BBB>>B
git commit -a -m BBB

우리는 각각 여러 커밋으로 git 디렉토리 a와 b를 만듭니다. 하위 트리 병합을 수행 한 다음 새 하위 트리에서 최종 커밋을 수행합니다.

달리기 gitk(z / a)는 히스토리가 나타나는 것을 보여줍니다. 우리는 그것을 볼 수 있습니다. 달리기 git log는 역사가 나타나는 것을 보여줍니다. 그러나 특정 파일을 보면 문제가 있습니다. git log bdir/B

음, 우리가 할 수있는 트릭이 있습니다. –follow를 사용하여 특정 파일의 이름 바꾸기 이전 기록을 볼 수 있습니다. git log --follow -- B. 이것은 좋지만 사전 병합의 기록과 병합 후의 기록을 연결하지 못하기 때문에 좋지 않습니다.

-M과 -C를 가지고 놀았지만 특정 파일을 따라갈 수 없었습니다.

그래서 해결책은 git에게 하위 트리 병합의 일부로 발생하는 이름 변경에 대해 알려주는 것입니다. 불행히도 git-read-tree는 하위 트리 병합에 대해 매우 까다롭기 때문에 임시 디렉토리를 통해 작업해야하지만 커밋하기 전에 사라질 수 있습니다. 그 후 우리는 전체 역사를 볼 수 있습니다.

먼저 “A”저장소를 만들고 몇 가지 커밋을 만듭니다.

mkdir -p z/a z/b
cd z/a
git init
echo A>A
git add A
git commit -m A
echo AA>>A
git commit -a -m AA

둘째, “B”저장소를 만들고 몇 가지 커밋을 만듭니다.

cd ../b
git init
echo B>B
git add B
git commit -m B
echo BB>>B
git commit -a -m BB

그리고이 작업을 수행하는 비결은 Git이 하위 디렉토리를 만들고 내용을 이동하여 이름을 인식하도록 강제합니다.

mkdir bdir
git mv B bdir
git commit -a -m bdir-rename

저장소 “A”로 돌아가서 “B”의 내용을 가져와 병합합니다.

cd ../a
git remote add -f B ../b
git merge -s ours --no-commit B/master
# According to Alex Brown and pjvandehaar, newer versions of git need --allow-unrelated-histories
# git merge -s ours --allow-unrelated-histories --no-commit B/master
git read-tree --prefix= -u B/master
git commit -m "subtree merge B into bdir"

이제 병합되었음을 표시하려면 :

cd bdir
echo BBB>>B
git commit -a -m BBB

전체 역사가 연결된 체인에 보존되어 있음을 증명하려면 :

git log --follow B

이 작업을 수행 한 후 기록을 얻지 만 문제는 실제로 이전 “b”저장소를 유지하고 때때로 병합하는 경우 (실제로는 별도로 유지 관리되는 타사 인 경우) 해당 타사 이후 문제가 발생한다는 것입니다. 이름을 변경하지 않았습니다. 이름을 변경하여 b 버전에 새로운 변경 사항을 병합해야하며 원활하게 진행되지 않을까 두렵습니다. 그러나 b가 사라지면 당신이 이깁니다.


답변

git-subtree는 기록을 보존하면서 여러 저장소를 하나로 병합하는이 사용 사례를 위해 설계된 스크립트입니다 (및 / 또는이 질문과 관련이없는 것처럼 보이지만 하위 트리의 기록을 분할). 릴리스 1.7.11 이후 git 트리의 일부로 배포됩니다 .

<repo>리비전 의 저장소 를 <rev>하위 디렉토리로 병합하려면 다음과 같이 <prefix>사용하십시오 git subtree add.

git subtree add -P <prefix> <repo> <rev>

git-subtree 는보다 사용자 친화적 인 방식으로 하위 트리 병합 전략 을 구현합니다 .

단점은 병합의 역사에 파일이 (가 아닌 하위 디렉토리에) 접두어가 있다는 것입니다. 저장소 ab. 결과적으로 git log a/f1병합 된 기록의 변경 사항을 제외한 모든 변경 사항 (있는 경우)이 표시됩니다. 넌 할 수있어:

git log --follow -- f1

그러나 병합 된 기록의 다른 변경 사항은 표시되지 않습니다.

즉, arepository에서의 파일을 변경하지 않으면 및 접두사가없는 경로 b를 지정해야 --follow합니다. 두 저장소 모두에서 변경하면 두 개의 명령이 있으며 어느 것도 모든 변경 사항을 표시하지 않습니다.

여기에서 더 자세히 알아 보십시오 .


답변

내가 원한

  1. 명시 적 병합없이 선형 히스토리 유지
  2. 이 병합 된 저장소의 파일처럼 보이게 항상 하위 디렉토리에 존재하고, 부작용 메이크로했다 git log -- file없이 작업 --follow.

1 단계 : 모든 파일이 항상 하위 디렉터리 아래에 존재하는 것처럼 보이도록 소스 저장소의 기록을 다시 작성합니다.

다시 작성된 기록에 대한 임시 분기를 만듭니다.

git checkout -b tmp_subdir

그런 다음 이미 이동 한 파일을 제외한 모든 파일이 하위 디렉터리에 있도록 기록을 다시 쓸 수git filter-branch 있는 방법에 설명 된대로 사용 합니다. :

git filter-branch --prune-empty --tree-filter '
if [ ! -e foo/bar ]; then
    mkdir -p foo/bar
    git ls-tree --name-only $GIT_COMMIT | xargs -I files mv files foo/bar
fi'

2 단계 : 대상 저장소로 전환합니다. 소스 저장소를 대상 저장소에 원격으로 추가하고 해당 컨텐츠를 가져옵니다.

git remote add sourcerepo .../path/to/sourcerepo
git fetch sourcerepo

3 단계 : merge --onto대상 리포지토리 위에 재 작성된 소스 리포지토리의 커밋을 추가하는 데 사용 합니다.

git rebase --preserve-merges --onto master --root sourcerepo/tmp_subdir

로그를 확인하여 이것이 실제로 원하는 것을 얻었는지 확인할 수 있습니다.

git log --stat

4 단계 : 리베이스 후에는 “분리 된 HEAD”상태에 있습니다. 마스터를 새 헤드로 빨리 감을 수 있습니다.

git checkout -b tmp_merged
git checkout master
git merge tmp_merged
git branch -d tmp_merged

5 단계 : 마지막으로 몇 가지 정리 : 임시 리모컨을 제거합니다.

git remote rm sourcerepo


답변

정말로 함께 꿰매고 싶다면 접목을 찾으십시오. 또한 git rebase --preserve-merges --onto. 커미터 정보의 작성자 날짜를 유지하는 옵션도 있습니다.


답변

다음 솔루션이 나에게 적합하다는 것을 알았습니다. 먼저 프로젝트 B로 이동하여 이미 모든 파일이 새 하위 디렉터리로 이동되는 새 분기를 만듭니다. 그런 다음이 새 분기를 원점으로 푸시합니다. 다음으로 프로젝트 A로 이동하여 B의 리모컨을 추가하고 가져온 다음 이동 된 분기를 체크 아웃하고 마스터로 돌아가 병합합니다.

# in local copy of project B
git checkout -b prepare_move
mkdir subdir
git mv <files_to_move> subdir/
git commit -m 'move files to subdir'
git push origin prepare_move

# in local copy of project A
git remote add -f B_origin <remote-url>
git checkout -b from_B B_origin/prepare_move
git checkout master
git merge from_B

하위 디렉토리로 이동하면 subdir사용할 수 git log --follow있으며 여전히 기록이 있습니다.

나는 자식 전문가가 아니기 때문에 이것이 특히 좋은 해결책인지 또는 경고가 있는지에 대해서는 언급 할 수 없지만 지금까지는 괜찮아 보입니다.


답변

여분의 저장소를 git 하위 모듈로 추가해 보셨습니까? 히스토리를 포함하는 저장소와 병합하지 않고 실제로 독립적 인 저장소가됩니다.

당신이하지 않았기 때문에 나는 그것을 언급합니다.


답변

저장소 a를 다음 과 같이 병합하고 싶다고 b가정 해 보겠습니다. (서로 나란히 있다고 가정합니다) :

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

이를 위해서는 git-filter-repo설치 filter-branch가 필요합니다 ( 권장되지 않음 ).

2 개의 큰 저장소를 병합하고 그중 하나를 하위 디렉토리에 넣는 예 : https://gist.github.com/x-yuri/9890ab1079cf4357d6f269d073fd9731

여기에서 더 자세히 알아 보십시오 .