힘내 체리 선택 대 리베이스


119

최근에 Git 작업을 시작했습니다.

오버가는 망할 놈의 책 온라인 난은 "힘내 Rebase 현재"섹션에서 다음과 발견 :

rebase 명령을 사용하면 한 분기에서 커밋 된 모든 변경 사항을 가져 와서 다른 분기에서 재생할 수 있습니다.

(에서 인용 : http://git-scm.com/book/en/Git-Branching-Rebasing )

나는 이것이 git cherry-pick 의 정확한 정의라고 생각했습니다 (현재 체크 아웃 된 브랜치에 커밋 또는 커밋 객체 세트를 다시 적용하십시오).

둘의 차이점은 무엇입니까?

답변:


165

시간이지나면서 git cherry-pick여러 커밋을 적용 할 수있게 되었기 때문에 그 차이는 실제로 다소 논쟁의 여지가 있었지만 이것은 수렴 진화라고 할 수 있습니다 ;-)

진정한 차이점은 두 도구를 모두 만들려는 원래 의도에 있습니다.

  • git rebase의 임무는 일부 업스트림 브랜치의 버전 X에 대해 생성 된 개발자가 비공개 저장소에있는 일련의 변경 사항을 동일한 브랜치의 버전 Y (Y> X)로 포워드하는 것입니다. 이는 해당 일련의 커밋 의 기반 을 효과적으로 변경 하므로 "리베이스"됩니다.

    (또한 개발자가 임의의 커밋에 일련의 커밋을 이식 할 수 있지만 이는 덜 분명한 용도입니다.)

  • git cherry-pick한 개발 라인에서 다른 라인으로 흥미로운 커밋을 가져 오는 것입니다. 고전적인 예는 불안정한 개발 브랜치에서 만들어진 보안 픽스를 안정된 (유지 보수) 브랜치로 백 포트하는 merge것입니다.이 경우 원치 않는 변경 사항이 많이 발생하므로 의미가 없습니다.

    처음 등장한 이후 git cherry-pick로 한 번에 여러 커밋을 하나씩 선택할 수있었습니다.

따라서이 두 명령의 가장 두드러진 차이점은 작업중인 브랜치를 처리하는 방법입니다. git cherry-pick일반적으로 다른 곳 에서 커밋 가져와 현재 브랜치 위에 적용하여 커밋을 기록하고 git rebase현재 브랜치 를 가져와 다시 작성합니다. 일련의 자체 팁이 어떤 식 으로든 커밋됩니다. 예, 이것은 무엇을 git rebase할 수 있는지에 대한 매우 멍청한 설명 이지만, 일반적인 아이디어를 포함시키려는 의도적 인 것입니다.

git rebase논의중인 사용 예를 추가로 설명하는 업데이트 .

이 상황에서
리베이스 이전의 리포지토리 상태
은 다음과 같이 말합니다.

그러나 또 다른 방법이 있습니다. C3에 도입 된 변경 사항의 패치를 가져와 C4 위에 다시 적용 할 수 있습니다. Git에서는이를 리베이스라고합니다. rebase 명령을 사용하면 한 분기에서 커밋 된 모든 변경 사항을 다른 분기에 적용 할 수 있습니다.

이 예에서는 다음을 실행합니다.

$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command

여기서 "잡지"는이 예에서 "실험"분기 (리베이스의 주제)가 원래 "마스터"분기에서 분리되었으므로 C0에서 C2까지 커밋 을 공유 한다는 것입니다. 사실상 "experiment"는 " master "까지 C2와 커밋 C3를 포함합니다. (이는 가능한 가장 간단한 경우입니다. 물론 "실험"에는 원래 기반 위에 수십 개의 커밋이 포함될 수 있습니다.)

이제 git rebase"실험"을 "마스터" 의 현재 팁 으로 리베이스하라는 지시를 받고 다음과 git rebase같이 진행됩니다.

  1. git merge-base"실험"과 "마스터"모두에서 공유 한 마지막 커밋이 무엇인지 확인하기 위해 실행 됩니다 (즉, 전환 지점이 무엇인지). 이것은 C2입니다.
  2. 전환 지점 이후에 만들어진 모든 커밋을 저장합니다. 장난감 예제에서는 C3입니다.
  3. HEAD (작업이 실행되기 시작하기 전에 "실험"의 팁 커밋을 가리킴)를 되 감아 "마스터"의 팁을 가리 키도록합니다. 우리는 그것을 리베이스하고 있습니다.
  4. 저장된 각 커밋 git apply을 순서대로 적용하려고 시도합니다 . 우리의 장난감 예제에서는 단지 하나의 커밋, C3입니다. 애플리케이션이 커밋 C3 '을 생성한다고 가정 해 보겠습니다.
  5. 모든 것이 순조롭게 진행되면 마지막으로 저장된 커밋 (이 경우 C3 ')을 적용한 결과 커밋을 가리 키도록 "실험"참조가 업데이트됩니다.

이제 질문으로 돌아갑니다. 보시다시피, 여기서는 기술적 git rebase 으로 실제로 "실험"에서 "마스터"의 팁으로 일련의 커밋을 이식하므로 프로세스에 실제로 "다른 분기"가 있음을 정당하게 알 수 있습니다. 그러나 요점은 "experiment"의 팁 커밋이 "experiment"의 새로운 팁 커밋이되었고 그 기반이 변경되었다는 것입니다.
병합 후 상태

다시 말하지만, 기술적으로 git rebase여기에 "마스터"의 특정 커밋이 포함되어 있음을 알 수 있으며 이는 절대적으로 정확합니다.


2
감사. 나는 아직도 당신이 여기서 의미하는 바를 완전히 이해하지 못했습니다. 이 책에서는 rebase가 다른 브랜치에서 일련의 팁 커밋을 적용하고 "동일 브랜치"에서 온 것이라고 말하는 예제가 있습니다. 아니면 작동 방식에 대한 몇 가지 사례가 있습니까?
lysergic 산성

1
내 대답을 업데이트하여 문제를 설명하려고했습니다.
kostix

98

cherry-pick을 사용하면 원래 커밋 / 분기가 주변에 고정되고 새 커밋이 생성됩니다. rebase를 사용하면 전체 분기가 재생 된 커밋을 가리키는 분기와 함께 이동됩니다.

다음으로 시작했다고 가정 해 보겠습니다.

      A---B---C topic
     /
D---E---F---G master

리베이스 :

$ git rebase master topic

당신은 얻을 :

              A'--B'--C' topic
             /
D---E---F---G master

체리 픽 :

$ git checkout master -b topic_new
$ git cherry-pick A^..C

당신은 얻을 :

      A---B---C topic
     /
D---E---F---G master
             \
              A'--B'--C' topic_new

git에 대한 자세한 내용은이 책에 대부분 있습니다 (http://git-scm.com/book).


3
잘 대답했습니다. 또한 A와 B 커밋 만 체리 픽하고 싶지만 C는 그대로두고 브랜치를 유지하고 동료가 확인해야 할 변경 사항 만 체리 픽 선택하는 것이 일반적입니다. Git은 사람들과 함께 작업하도록 만들어 졌기 때문에 혼자 작업 할 때 어떤 이점이없는 경우 더 큰 그룹에서 작업 할 때 더 일반적으로 사용됩니다.
Pablo Jomer 2012

대신에 하나 이상의 커밋을 제외하고 대화 형 리베이스가 수행 되었다면 마지막에 어떤 분기를 갖게 될까요? 을 기반으로 만 topic리베이스 된 master경우 남은 커밋이 포함되어 있지 않으므로 어떤 분기에 속할까요?
Anthony

당신이 경우 : 그냥 한 가지 더 내가 추가 할 git checkout topic다음 git reset --hard C'체리 따기 후, 당신은 리베이스 이후로 매우 동일한 결과를 가지고있다. 공통 조상이 돌아 왔기 때문에 리베이스보다 체리 피킹을 사용하여 많은 병합 충돌에서 나 자신을 구했습니다.
sorrymissjackson

@anthony - stackoverflow.com/questions/11835948/... : 지금까지 나는 그들이 손실됩니다 이해. 나는 더는 아니지만 git-guru 그러나이 rebase/가 cherry-pick모든 세부 사항에 git내가 문제의 이해를하였습니다.
thoni56

1
그래프는 기능적으로 동일하기 때문에 좋은 것보다 해를 끼칩니다. 유일한 차이점은에 의해 생성 된 브랜치로 git checkout -b,와 관련이 없습니다 git cherry-pick. 당신이 말하고자하는 것을 설명하는 더 좋은 방법은“당신 git rebasetopic지점에서 달려가 그것을 통과한다 master; 당신 git cherry-pickmaster지점 에서 실행 하고 그것을 전달합니다 (커밋에서) topic.”
Rory O'Kane

14

체리 피킹은 개별 커밋에 대해 작동합니다 .

리베이스를 할 때 히스토리의 모든 커밋 을 거기에없는 브랜치의 HEAD에 적용 합니다 .


감사. 이것들이 덮개 아래에서 동일하게 작동하는지 알고 있습니까? (중간 출력을 "패치"파일 등에 저장).
lysergic-acid-

Afaik 예. 모든 패치를 하나씩 적용합니다. 이것이 계속하기 전에 리베이스 중간에 병합 충돌을 해결해야하는 이유입니다.
iltempo

6
@iltempo, 이전 버전의 Git에서만 개별 커밋에 대해 작동했습니다. 현재 당신은 같은 것을 할 수 있고 git cherry-pick foo~3..foo"foo"에서 하나씩 고른 트리 상단 커밋을 얻을 수 있습니다 .
kostix

1
git-rebase는 코드베이스 iirc에서 체리 피킹이 수행하는 것과 동일한 API를 사용합니다
대안

나는 그들이 실제로 커버 아래에서 똑같이 작동한다고 생각하지 않습니다. 나는 수천 개의 커밋을 리베이스하려고 시도했으며 git이 거대한 사서함 파일을 만든 다음 실행한다고 생각 git am합니다. 체리 선택은 커밋별로 커밋을 적용하는 반면 (가능하면 각 패치에 대해 단일 메시지 사서함을 생성하여). 내 리베이스는 생성하는 사서함 파일의 드라이브 공간이 부족했기 때문에 실패했지만 동일한 수정 범위의 체리 선택이 성공했습니다 (더 빨리 실행되는 것 같습니다).
onlynone

11

짧은 대답 :

  • git cherry-pick은 더 "낮은 수준"입니다.
  • 따라서 git rebase를 에뮬레이션 할 수 있습니다.

위에 주어진 답변은 훌륭합니다. 나는 그들의 상호 관계를 보여주기 위해 예제를 제공하고 싶었습니다.

"git rebase"를이 일련의 동작으로 대체하는 것은 권장되지 않습니다. 이것은 단지 "개념 증명"일 뿐이며, 이것이 어떻게 작동하는지 이해하는 데 도움이되기를 바랍니다.

다음 장난감 저장소가 제공됩니다.

$ git log --graph --decorate --all --oneline
* 558be99 (test_branch_1) Test commit #7
* 21883bb Test commit #6
| * 7254931 (HEAD -> master) Test commit #5
| * 79fd6cb Test commit #4
| * 48c9b78 Test commit #3
| * da8a50f Test commit #2
|/
* f2fa606 Test commit #1

master에서 test_branch_1에 포함하고 싶은 매우 중요한 변경 사항 (커밋 # 2에서 # 5)이 있다고 가정 해 보겠습니다. 보통 우리는 브랜치로 전환하고 "git rebase master"를 수행합니다. 그러나 우리는 "git cherry-pick"만 장착 된 척하면서 다음을 수행합니다.

$ git checkout 7254931                # Switch to master (7254931 <-- master <-- HEAD)
$ git cherry-pick 21883bb^..558be99   # Apply a range of commits (first commit is included, hence "^")    

이 모든 작업 후 커밋 그래프는 다음과 같습니다.

* dd0d3b4 (HEAD) Test commit #7
* 8ccc132 Test commit #6
* 7254931 (master) Test commit #5
* 79fd6cb Test commit #4
* 48c9b78 Test commit #3
* da8a50f Test commit #2
| * 558be99 (test_branch_1) Test commit #7
| * 21883bb Test commit #6
|/
* f2fa606 Test commit #1

보시다시피 커밋 # 6 및 # 7은 7254931 (마스터의 팁 커밋)에 대해 적용되었습니다. HEAD가 이동되어 기본적으로 리베이스 브랜치의 팁인 커밋을 가리 킵니다. 이제 우리가해야 할 일은 이전 분기 포인터를 삭제하고 새 포인터를 만드는 것입니다.

$ git branch -D test_branch_1
$ git checkout -b test_branch_1 dd0d3b4

test_branch_1 은 이제 최신 마스터 위치에서 루팅됩니다. 끝난!


그러나 rebase는 git cherry-pick도 시뮬레이션 할 수 있습니까?
Number945

cherry-pick다양한 커밋을 적용 할 수 있기 때문에 그렇다고 생각합니다. 이 방법이 약간 이상하지만 .NET의 기능 브랜치에서 모든 커밋을 선택하는 것을 방해하는 것은 없습니다 master. 그런 다음 기능 브랜치를 삭제하고 master. , 및 git rebase의 시퀀스로 생각할 수 있습니다 . git cherry-pick feature_branchgit branch -d feature_branchgit branch feature_branch master
raiks

7

두 가지 모두 한 분기의 커밋을 다른 분기 위에 다시 작성하는 명령입니다. 차이점은 "yours"(현재 체크 아웃 된 항목 HEAD) 또는 "theirs"(명령에 대한 인수로 전달 된 분기) 분기가 무엇인지에 있습니다. 이 재 작성 의 기초 .

git rebase소요 시작 커밋 하고 다시 재생 하여 이후에 들어오는 커밋을 그들의 (시작 커밋).

git cherry-pick소요 커밋의 설정을 하고 재생합니다 이후에 들어오는 커밋을 당신 (당신의 HEAD).

즉, 두 명령은 핵심 동작 (다양한 성능 특성, 호출 규칙 및 향상 옵션 무시)에서 대칭 적입니다 . 분기를 확인 bar하고 실행 git rebase foo하면 bar분기를 확인 foo하고 실행 하는 것과 동일한 기록으로 분기 를 git cherry-pick ..bar설정합니다. foo로 (에서 변경 한 foo다음에서 변경 bar).

이름 지정 측면에서 두 명령의 차이점은 각 명령이 현재 분기에 대해 수행하는 작업을 설명한다는 점에서 기억할 수 있습니다 rebase. 다른 헤드는 변경 사항 의 새 기반 이되는 반면 cherry-pick다른 분기에서 변경 사항을 선택 하여 맨 위에 배치합니다. 당신HEAD (선디 위에 체리처럼).


1
나는 당신의 대답을 제외하고는 어떤 대답도 이해할 수 없었습니다! 간결하고 불필요한 표현 없이도 완벽하게 이해할 수 있습니다.
neoxic

4

둘 다 매우 비슷한 일을합니다. 주요 개념적 차이점은 다음과 같습니다.

  • rebase현재 분기 에서 다른 분기 로 커밋을 이동 합니다.

  • cherry-pick다른 분기 에서 현재 분기 로 커밋을 복사 합니다.

@Kenny Ho의 답변 과 유사한 다이어그램 사용 :

이 초기 상태가 주어지면 :

A---B---C---D master
     \
      E---F---G topic

... topic현재 master브랜치 위에 재생 된 브랜치 에서 커밋을 가져 오길 원한다고 가정하면 두 가지 옵션이 있습니다.

  1. rebase 사용 : 먼저 topic를 수행 git checkout topic한 다음을 실행하여 분기를 이동하고 다음을 git rebase master생성합니다.

    A---B---C---D master
                 \
                  E'---F'---G' topic
    

    결과 : 현재 브랜치 topic가로 리베이스 (이동)되었습니다 master. 그동안 분기, 업데이트 된 지점이 자리에 남아 있었다.
    topicmaster

  2. cherry-pick 사용 : 먼저 master를 수행 git checkout master한 다음 실행하여 분기를 복사합니다 git cherry-pick topic~3..topic(또는 동등하게 git cherry-pick B..G).

    A---B---C---D---E'---F'---G' master
         \
          E---F---G topic
    

    결과 : 커밋에서 topic복사master. 그동안 분기, 업데이트 된 지점이 자리에 남아 있었다.
    mastertopic


물론 여기 에서는 범위 표기법을 사용하여 일련의 커밋을 선택하도록 cherry-pick에게 명시 적으로 지시해야했습니다 . 에서와 같이 단순히 분기 이름을 전달했다면 분기 끝에있는 커밋 만 선택했을 것입니다. foo..bargit cherry-pick topic

A---B---C---D---G' master
     \
      E---F---G topic
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.