체리 픽 후 git merge는 어떻게 작동합니까?


190

master지점 이 있다고 상상해 봅시다 .

그런 다음 newbranch

git checkout -b newbranch

그리고 두 개의 새로운 커밋을 newbranch: commit1commit2

그런 다음 마스터로 전환하고 cherry-pick

git checkout master
git cherry-pick hash_of_commit1

를 살펴보면 gitk우리하면 해당 참조 commit1 때문에 기술적으로 두 개의 서로 다른 커밋은, 그 체리 고른 버전은 서로 다른 해시를 가지고있다.

마지막으로 우리는 다음과 같이 합병 newbranch합니다 master.

git merge newbranch

서로 다른 해시를 가진이 두 커밋은 동일한 변경 사항이 두 번 적용되어야하므로 그 중 하나가 실패해야 함을 의미하지만 문제없이 병합되었습니다.

git은 병합하는 동안 실제로 커밋 내용을 현명하게 분석하고 변경 사항을 두 번 적용해서는 안되거나 이러한 커밋이 내부적으로 연결된 것으로 표시됩니까?

답변:


131

짧은 답변

걱정하지 마십시오. 힘내가 처리합니다.

긴 대답

예를 들어 SVN 1 과 달리 Git은 커밋을 델타 형식으로 저장하지 않지만 스냅 샷 기반 2,3 입니다. SVN은 병합 된 각 커밋을 패치로 순진하게 적용하려고 시도하지만 (설명한 정확한 이유로 실패) Git은 일반적 으로이 시나리오를 처리 할 수 ​​있습니다.

병합 할 때 Git은 두 HEAD 커밋의 스냅 샷을 새로운 스냅 샷으로 결합하려고 시도합니다. 코드 또는 파일의 일부가 두 스냅 샷에서 동일하면 (즉, 커밋이 이미 체리 선택 되었기 때문에) Git은이를 만지지 않습니다.

출처

1 Subversion의 Skip-Deltas
2 Git 기초
3 Git 객체 모델


40
실제로, 병합에 대해 걱정해야 한다고 말하고 "git will handle it"은 좋은 규칙이 아닙니다.
cregox

4
실제로 병합은 경우에 따라 내용이 중복 될 수 있습니다. 힘내는 때때로 그것을 처리하지만 때로는 그렇지 않습니다.
donquixote

이것은 끔찍한 잘못입니다. 거의 모든 형태로 파일 파일을 저장했습니다. 그리고 내가 올바르게 기억하면 SVN은 스냅 샷을 저장하는 데 사용됩니다.
he_the_great

2
@he_the_great, 아뇨. SVN의 스킵 델타 스토리지 형식 (! = 스냅 샷)은 설명서 잘 설명 되어 있습니다 . 그리고 나는 정말로 condevable의 의미를 얻지 못합니다 . 나는 원어민이 아니지만 그것이 실제 단어가 아니라고 확신합니다.
helmbert

2
@he_the_great 그러나 파일에 대해 주어진 해시를 파일로 저장하더라도 전체 파일이 생성됩니다. 예, 델타를 사용하여 압축하지만 커밋의 변경에 대한 델타가 아니라 파일의 해시 사이의 델타입니다. 커밋 객체와 관련하여 전체 파일의 해시를 참조하는 트리를 참조합니다. 후드 아래에서 데이터가 압축된다는 것은 git 작동 방식에 영향을 미치지 않습니다. Git은 커밋에 관한 한 완전한 파일을 저장하고 SVN은 내가 이해하는 커밋에 대한 델타를 저장합니다.
피터 올슨

44

이러한 병합 후에는 역사에서 체리 피킹 커밋이 두 번있을 수 있습니다.

이것을 피하기위한 해결책 은 중복 (체리 피킹) 커밋이있는 브랜치에 대해 권장하는 기사 에서 인용 하기 전에 병합 전에 rebase를 사용합니다.

git cherry-pick 후 git merge : 중복 커밋 피하기

마스터 브랜치와 브랜치 b가 있다고 상상해보십시오.

   o---X   <-- master
    \
     b1---b2---b3---b4   <-- b

이제 우리는 커밋 b1과 b3을 긴급히 필요하지만 b의 나머지 커밋은 필요하지 않습니다. 우리가하는 일은 마스터 브랜치와 체리 픽 커밋 b1과 b3을 체크 아웃하는 것입니다.

$ git checkout master
$ git cherry-pick "b1's SHA"
$ git cherry-pick "b3's SHA"

결과는 다음과 같습니다.

   o---X---b1'---b3'   <-- master
    \
     b1---b2---b3---b4   <-- b

마스터에 대한 또 다른 커밋을 수행하면 다음과 같은 결과를 얻습니다.

   o---X---b1'---b3'---Y   <-- master
    \
     b1---b2---b3---b4   <-- b

이제 브랜치 b를 마스터로 병합한다면 :

$ git merge b

우리는 다음을 얻을 것입니다 :

   o---X---b1'---b3'---Y--- M  <-- master
     \                     /
      b1----b2----b3----b4   <-- b

이는 b1 및 b3에 의해 도입 된 변경 사항이 기록에 두 번 나타남을 의미합니다. 병합 대신 리베이스 할 수있는 것을 피하려면 :

$ git rebase master b

어느 것이 산출 될까요?

   o---X---b1'---b3'---Y   <-- master
                        \
                         b2'---b4'   <-- b

드디어:

$ git checkout master
$ git merge b

우리에게 주어지다:

   o---X---b1'---b3'---Y---b2'---b4'   <-- master, b

David Lemon의 의견에 의해 수정 된 수정


1
rebase에 대한 좋은 힌트! 그것은 체리가 고른 모든 커밋을 자동으로 '건너 뛸 것'입니다.
iTake

2
솔직히 말해서, 그것이 사실이 되기에는 너무 좋게 들립니다. 나는 그것을 눈으로 봐야합니다. 또한 커밋을 수정하고 마지막 타임 라인은 다음과 같습니다---Y---b2'---b4'
David Lemon

완벽하게 작동합니다. 체리 피킹 커밋을 두 번 사용하고 싶지 않은 경우 매우 유용합니다.
user2350644

1
rebase가 아름답 지 만 rebase가 아름답지만 오래된 b로 만든 포크 또는 브랜치가 동기화되지 않아 사용자가 git reset --hard 및 git와 같은 것을 사용해야 할 수도 있습니다. 푸시 -f?
JHH

1
우리는 지역의 여기 지점 리베이스 왜 @JHH 그게
ephemerr을
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.