2009-11-12 4 views
49

대화 형 rebase 중에 두 개의 병합 커밋을 함께 스쿼시하는 간단한 솔루션을 원했습니다. 실제 사이의 범하지와git rebase interactive : squash merge together together

입니다
X --- Y --------- M1 -------- M2 (my-feature) 
/    /  /
/    /  /
a --- b --- c --- d --- e --- f (stable) 

, 나는 두 번 최근에 합병 된 my-feature 지점을 가지고 :

내 저장소는 것 같습니다. 난 그냥 난 그냥 (아직 그 커밋을 게시하지 않은 경우) 마지막 두 병합 하나에 커밋 함께 스쿼시하려면, 그것은 자신의 출판 분기이기 때문에 my-feature 지점을 리베이스하고 싶지 않은

X --- Y ---- M (my-feature) 
/  /
/  /
a --- ... -- f (stable) 

나는 시도 :

git rebase -p -i M1^ 

하지만 내가 가지고 : 나는 마침내 무슨 짓을

Refusing to squash a merge: M2 

은 다음과 같습니다

,536,
git checkout my-feature 
git reset --soft HEAD^ # remove the last commit (M2) but keep the changes in the index 
git commit -m toto  # redo the commit M2, this time it is not a merge commit 
git rebase -p -i M1^ # do the rebase and squash the last commit 
git diff M2 HEAD  # test the commits are the same 

이제 새로운 병합 커밋은 더 이상 병합 커밋으로 간주되지 않습니다 (첫 번째 부모 만 유지함). 따라서 :

git reset --soft HEAD^    # get ready to modify the commit 
git stash       # put away the index 
git merge -s ours --no-commit stable # regenerate merge information (the second parent) 
git stash apply      # get the index back with the real merge in it 
git commit -a      # commit your merge 
git diff M2 HEAD      # test that you have the same commit again 

커밋이 많으면 복잡해질 수 있습니다. 더 좋은 해결책이 있습니까? 감사합니다. .

밀드레드

+0

음을 커밋 그들이 최선을 다하고 할 수있는 인덱스에 변경 사항을 적용합니다 두 번째 병합을 할 때 항상'--squash'를 사용하여 커밋을 생성하지 않고'git commit --amend'를 사용하여 이전 병합을 수정할 수 있습니다. – Mildred

+0

이 작업을 수행 할 수 없으며 병합에서 병합 한 분기의 새 버전을 저장하지 않습니다. – Mildred

답변

8

마지막 두 병합 커밋 게시하지 않은 경우, 당신은 리셋 간단한 병합 할 수 있습니다.

git reset --hard Y 
git merge stable 
+2

예, 병합이 어려웠으므로 가능한 한 적은 변경 사항을 병합합니다. 나는 이미 해결 한 갈등을 해결하고 싶지 않습니다. – Mildred

+9

충돌을 다시 해결하고 싶지 않으면 git-rerere를 사용해야합니다 ("사용"은 "켜기"를 의미합니다. 사용 가능). –

47

이 항목은 오래된 항목이지만 비슷한 정보를 찾는 동안 방금 훑어 보았습니다.

Subtree octopus merge에 설명 된 것과 유사한 트릭은 이러한 유형의 문제에 대한 정말 좋은 솔루션입니다 :

git checkout my-feature 
git reset --soft Y 
git rev-parse f > .git/MERGE_HEAD 
git commit 
내-기능의 끝 부분에 존재하는 인덱스를 가지고, 그것을 사용합니다

두 번째 부모로 'f'를 사용하여 Y의 새로운 커밋을 만듭니다. 결과는 M1을 한 번도 사용하지 않았지만 M2를 수행하는 것과 똑같습니다.

+0

이 종류의 병합은 하위 트리 또는 문어 병합과 아무 관련이 없습니다. 링크 한 블로그는 하위 트리 병합과 낙지 병합을 하나의 병합 커밋으로 결합하는 기술을 사용합니다. 왜냐하면 자식은 한 번에 두 병합을 직접 수행 할 수 없기 때문입니다. – sleske

+0

이 단점은 git이 적절한 커밋 메시지를 생성 할 수 없다는 것입니다. 이전 병합 커밋의 메시지를 복사했습니다. 그렇지 않으면 좋고, 쉬운 해결책. –

+0

너무 많은 upvote! 우리는 방금 합병을 매우 어렵게 만들었고 동료 접근 방식은 한 번에 하나씩 자신의 나무에서 각 커밋을 합병하는 것이 었습니다. 그리고 나서 우리는이 해결책을 찾았습니다. 자신 만의 커밋 메시지를 작성해야하는 것은 부끄러운 일입니다. – Sam

0

언급 된 방법 중 가장 최근 버전의 git 버전을 사용하고 있습니다. 제 경우에는 다음과 같은 트릭이있었습니다 :

git reset --soft Y 
git reset --hard $(git commit-tree $(git write-tree) -p HEAD -p stable < commit_msg) 

먼저 커밋 메시지를 commit_msg 파일에 작성해야합니다.

5

나는이 주제로 한 병합 커밋을 스쿼시하고자했다. 그래서 제 대답은 원래의 질문에 유용하지 않습니다. 내가 원하는 무엇

   X 
       \ 
       \ 
a --- b --- c --- M1 (subtree merge) 

는 B의 상단에 하나의 커밋으로 M1 병합, 스쿼시 모든 리베이스하는 것이 었습니다.

a --- b --- S (include the changes from c, X and M1) 

나는 다른 조합의 모든 종류를 시도했지만이 일 것입니다 :

git checkout -b rebase b (checkout a working branch at point b) 
git merge --squash M1 

이것은 당신이 때, 자식이

+1

이 경우'git diff b> diff.patch','git checkout b','cat diff.patch | patch -p1' 그리고 나서'git commit'을 실행합니다. * 병합 *에 해상도가 포함 된 경우이 방법이 작동합니다. 원래의 질문은 다릅니다. 그러나 나는 당신이 여기 나와 같은 것을 찾기 위해 온 것 같아요. 'git log' 명령으로 체크인 메시지를 얻을 수 있습니다. –

+0

마스터에서 상황을 확인하려면 추가 단계가 필요합니다.'git checkout master && git reset --hard b && git rebase rebase'. 이것은 나 자신을 생각 나게하는 것입니다. "rebase"보다는 다른 이름을 선택할 수 있습니다 :) – eis

관련 문제