git cherry-pick은“… 38c74d는 병합되었지만 -m 옵션은 제공되지 않았습니다”라고 말합니다.


518

마스터 브랜치에서 약간의 변경을했으며 그 업스트림을 가져오고 싶습니다. 그러나 다음 커밋을 선택하면 fd9f578에 붙어있어 git이 말합니다.

$ git cherry-pick fd9f578
fatal: Commit fd9f57850f6b94b7906e5bbe51a0d75bf638c74d is a merge but no -m option was given.

git가 나에게 말하려고하는 것은 무엇이며 체리 피킹은 여기에서 사용하는 것이 옳은 것입니까? 마스터 브랜치에는 업스트림 브랜치에서 수정 된 파일에 대한 변경 사항이 포함되므로 병합 충돌이 발생하지만 곧바로 정리하기에는 나쁘지 않습니다. 어디에서 어떤 변경이 필요한지 알고 있습니다.

이것들은 내가 업스트림으로 가져오고 싶은 커밋입니다.

e7d4cff added some comments...
23e6d2a moved static strings...
44cc65a incorporated test ...
40b83d5 whoops delete whitspace...
24f8a50 implemented global.c...
43651c3 cleaned up ...
068b2fe cleaned up version.c ...
fd9f578 Merge branch 'master' of ssh://extgit/git/sessions_common
4172caa cleaned up comments in sessions.c ...

답변:


606

체리 픽이 작동하는 방식은 변경 세트가 나타내는 차이 (해당 지점의 작업 트리와 부모의 작업 트리의 차이)를 가져와 현재 분기에 적용하는 것입니다.

따라서 커밋에 둘 이상의 부모가있는 경우 둘 이상의 차이를 나타냅니다. 어느 하나를 적용해야합니까?

당신은 체리 선택을 시도하고 fd9f578있는데, 이것은 두 부모와의 합병이었습니다. 따라서 -m옵션 을 사용하여 cherry-pick 명령에 diff를 계산할 명령을 지정해야합니다 . 예를 들어 git cherry-pick -m 1 fd9f578부모 1을 기본으로 사용합니다.

특정 상황에 대해 확실히 말할 수는 없지만 git merge대신 대신 사용 하는 git cherry-pick것이 좋습니다. 병합 커밋을 선택하면 해당 커밋 으로 지정하지 않은 부모의 모든 변경 사항이 축소 됩니다 . 당신은 그들의 모든 역사를 잃어 버리고 그들의 모든 차이점을 함께 흠집을냅니다. 당신의 전화.-m


3
@wufoo 당신도 아마 배워야 할 것입니다 git rebase-그것은 병합과 같지만 두 개의 가지를 통합하는 대신 한 가지를 이식하여 다른 꼭대기에 앉아 있습니다.
Borealid

91
부모 번호는 어떻게 알 수 있습니까?
Anentropic

66
@Anentropic 1은 "첫 번째 부모"이고 2는 "두 번째 부모"입니다. 순서는 커밋에 나열되는 순서입니다 (보기 등 git show).
Borealid

2
@lkraav 당신은 또한 git reset --hard HEAD@{1}당신의 실종 된 커밋을 되 찾으려고 방금 할 수있었습니다 . git reset역사상 "뒤로"이동하는 것으로 제한되지 않습니다. git checkout -b mybranch HEAD@{1}작동합니다.
Borealid

4
경고 : git merge의도하지 않은 결과가 발생할 수 있습니다. 이 명령은 부모 브랜치에 존재하는 다른 모든 (구) 커밋을 추가합니다. 일반적으로 사람들은 다른 커밋을 원하지 않기 때문에 체리 픽을 선택합니다. 원하는 변경 사항 만 구현하고 있는지 다시 확인하십시오!
Kay V

52

-m 부모 번호를 의미합니다.

자식 문서에서 :

일반적으로 병합의 어느 쪽이 메인 라인으로 간주되어야하는지 모르기 때문에 병합을 체리 픽픽으로 선택할 수 없습니다. 이 옵션은 메인 라인의 부모 번호 (1부터 시작)를 지정하고 체리 픽이 지정된 부모에 대한 변경을 재생할 수 있도록합니다.

예를 들어 커밋 트리가 다음과 같은 경우

- A - D - E - F -   master
   \     /
    B - C           branch one

그런 다음 git cherry-pick E직면 한 문제가 발생합니다.

git cherry-pick E -m 1을 사용 D-E하는 git cherry-pick E -m 2것을 의미하고을 사용 하는 것을 의미 B-C-E합니다.


32

@Borealid의 대답은 정확하지만 지점의 정확한 병합 기록을 보존하는 데 신경 쓰지 않고 선형 버전을 체리 선택하려고한다고 가정하십시오. 쉽고 안전한 방법은 다음과 같습니다.

시작 상태 : 브랜치 X에 있고 커밋을 체리 픽 선택하려고합니다 Y..Z.

  1. git checkout -b tempZ Z
  2. git rebase Y
  3. git checkout -b newX X
  4. git cherry-pick Y..tempZ
  5. (선택 과목) git branch -D tempZ

이 작업은를 tempZ기반으로 분기를 작성 Z하지만 Y이후 선형화 된 히스토리를 사용하여 X호출 된 사본으로 체리 선택합니다 newX. (돌연변이보다는 새로운 브랜치에서이 작업을 수행하는 것이 더 안전합니다 X.) 물론 4 단계에서 일반적인 방법으로 해결해야 할 충돌이있을 수 있습니다 (그러면 cherry-pick매우 유사하게 작동합니다 rebase). 마지막으로 임시 tempZ분기를 삭제합니다 .

2 단계에 "현재 분기 tempZ가 최신 상태입니다" Y..Z라는 메시지가 표시되면 이미 선형 인 것이므로 해당 메시지를 무시하고 3 단계부터 계속하십시오.

그런 다음 newX원하는대로했는지 검토 하고 확인하십시오.

(참고 :이 간단한 동일하지 않습니다 git rebase X분기 Z가 사이의 관계에 어떤 식 으로든 영향을받지 않기 때문에, X그리고 Y, 공통 조상 사이의 커밋이있을 수 있습니다 Y당신이 원하는하지 않았다.)


1
git rebase Y말한다Current branch tempZ is up to date
Basilevs

나는 그것이 Y..Z이미 선형 임을 의미한다고 생각합니다 . 따라서이 메시지를 무시하고 3 단계와 4 단계를 진행할 수 있습니다.
Daira Hopwood

1
흥미로운 아이디어, 나는 무슨 일이 있었는지 완전히 이해하기 위해 종이에 그림을 그려야했다
Chris

2
훌륭한. 전체 범위에 대한 git cherry-pick은 -m 옵션이 누락되었거나 제공되었다고 불평했습니다. 당신의 해결책은 황금이었습니다. (한 가지 제안 : 이후 tempZ 분기 삭제)
Otheus

1
이것은 놀랍습니다! 나는 체리 픽으로 어려움을 겪고 있었고 이것 만이 의미가있었습니다. 내가 고른 편지와 약간의 문제 (일부 지점 및 커밋 대문자이고 일부 가지 소문자)했다
pcarvalho

19

단순화하십시오. 커밋을 체리 픽. 병합을 선택하지 마십시오.

다음은 가능한 접근 방식의 장점 / 위험을 이상적으로 설명하는 허용 된 답변을 다시 작성한 것입니다.

당신은 두 부모와의 합병 인 fd9f578을 체리 선택하려고합니다.

병합을 선택하는 대신 가장 간단한 방법은 병합의 각 분기에서 실제로 원하는 커밋을 선택하는 것입니다.

이미 병합 했으므로 원하는 커밋이 모두 목록에있을 수 있습니다. 체리를 직접 고르면 병합 커밋을 망칠 필요가 없습니다.

설명

체리 픽이 작동하는 방식은 변경 세트가 나타내는 차이 (해당 지점의 작업 트리와 상위 트리의 작업 트리 간의 차이)를 변경하고 현재 지점에 변경 세트를 적용하는 것입니다.

커밋에 병합이있는 것처럼 커밋이 둘 이상인 경우 해당 커밋은 둘 이상의 차이를 나타냅니다. 차이가 적용되어야하는 불확실성으로 인해 오류가 발생합니다.

대안

병합을 포함하고 관련 커밋을 선택하는 것이 필요하다고 판단되면 두 가지 옵션이 있습니다.

  1. (더 복잡하고 모호하며 또한 기록을 버림) 적용 할 부모를 지정할 수 있습니다.

    • -m옵션을 사용하십시오 . 예를 들어, git cherry-pick -m 1 fd9f578병합에 나열된 첫 번째 상위를 기본으로 사용합니다.

    • 또한 병합 커밋을 선택하면 지정하지 않은 부모의 변경 사항 이 모두 축소 됩니다.-m 것을에 하나의 커밋을 . 당신은 그들의 모든 역사를 잃어 버리고 그들의 모든 차이점을 함께 흠집을냅니다. 당신의 전화.

  2. git merge대신에 사용할 수 있습니다 (단순하고 친숙하며 기록 유지) git cherry-pick.

    • 에서와 마찬가지로 git merge병합하는 브랜치에 존재하는 모든 커밋을 적용하고 git log에 개별적으로 나열하려고 시도합니다.

2

하나의 커밋을 고르는데 좋은 @Daira Hopwood 방법의 단순화. 임시 지점이 필요하지 않습니다.

저자의 경우 :

  • Z는 커밋을 원합니다 (fd9f578)
  • Y는 그 전에 커밋
  • X 현재 작업 지점

그런 다음 수행하십시오.

git checkout Z   # move HEAD to wanted commit
git reset Y      # have Z as changes in working tree
git stash        # save Z in stash
git checkout X   # return to working branch
git stash pop    # apply Z to current branch
git commit -a    # do commit

2
물론 원래 커밋과 관련된 메타 데이터가 손실됩니다. 그것이 더 간단한 지 여부는 의견의 문제라고 생각합니다. 메타 데이터를 잃고 전체 코드 변경 사항 만 유지 하려고 할 때 가끔 사용합니다 . Y가 Z의 직계 부모가 아닌 경우에도 작동합니다 (이 경우 변경 사항이 취소됨).
Daira Hopwood
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.