힘내 : 특정 커밋에 리베이스하는 방법?


154

다른 지점의 HEAD가 아닌 특정 커밋에 리베이스하고 싶습니다.

A --- B --- C          master
 \
  \-- D                topic

A --- B --- C          master
       \
        \-- D          topic

대신에

A --- B --- C          master
             \
              \-- D    topic

어떻게하면 되나요?


4
당신은 git checkout B실행하기 전에 시도 했습니까 git rebase?
Peter-Paul van Gemerden

아뇨, 도움이 되나요? rebase명령 참조 만 중요하다고 생각합니다.
Ondra Žižka

답변:


98

원하는 커밋에 임시 브랜치를 만들어 --onto 매개 변수를 사용하지 않고 간단한 형식으로 rebase를 사용할 수 있습니다.

git branch temp master^
git checkout topic
git rebase temp
git branch -d temp

5
나는이 RISC와 같은 접근법을 더 좋아합니다 :) 시도합니다. 감사.
Ondra Žižka

10
약간 다른 시나리오 에서 왜 작동하지 않는지 궁금합니다 . 내가 원하는 그룹이 스킵 pep8을 하고 기반으로 마스터 . git rebase temp( 그룹에 있을 때 ) "현재 지점 그룹이 최신입니다."
Alois Mahdal 2016 년

4
이 솔루션은 주제가 이미 마스터를 기반으로 한 시나리오에서는 작동하지 않지만 상위 항목을 마스터로 리베이스하려는 경우에 적용됩니다. 이 경우 git rebase --onto <target> <from> <to><from> 커밋을 지정할 수 있도록 사용해야합니다 .
mirzmaster

브랜치가 기반으로하는 동일한 커밋에 리베이스하려는 경우 가장 쉬운 옵션입니다.
Ash

1
나는 일하는 것처럼 보이지만 GitLab은 다른 것을 말합니다. 커밋이 10 개, 커밋이 5 회이면 커밋이 8 개, 커밋이 2 회 커밋 된 후 5 개가 커집니다. 그러나 이것 대신에 그것은 5에 더 많은 커밋을 추가합니다.
ROMANIA_engineer

67

직접 접근 할 수도 있습니다.

git checkout topic
git rebase <commitB>

6
나에게 이것은 실제로 의도 한 것을하지 않습니다. 지금까지 내가 말할 수있는, 그것은 "마지막 공통 조상"의에 리베이스하려고 topic하고 commitB.
Dan Lenski

2
works.Quoting REBASE 어떻게하지 @DanLenski, 워드 프로세서 , It works by going to the common ancestor of the two branches (the one you’re on and the one you’re rebasing onto), getting the diff introduced by each commit of the branch you’re on, saving those diffs to temporary files, resetting the current branch to the same commit as the branch you are rebasing onto, and finally applying each change in turn. 내가 지금 다시 시도하고 잘 작동하는 것 같았다.
r0hitsharma

1
매우 쉽고 작동합니다! 이제 commitB_from_master-> topicCommit1-> topicCommit2가 있습니다.
Martin Konicek

그것은 나를 위해 작동하지 않았다. 이 전에 GitLab은 "n commits 앞서"고 말했습니다. 그리고 이제 "m commits ahead"라고 m > n합니다.
ROMANIA_engineer

48

"onto"옵션을 사용하십시오 :

git rebase --onto master^ D^ D

2
D그리고 D^마지막과 다음 - 투 - 마지막으로 "항목"의 커밋의 해시 것입니까?
Ondra Žižka

39
구문은 다음과 같습니다 git rebase --onto <new-parent> <old-parent>. 자식 부모 포인터를 다른 부모로 설정을 참조하십시오 . 귀하의 경우 <new-parent>는 B이고 <old-parent>는 A입니다.
jsz

7
나는 항상 3 가지 논증을 사용한다 : 데스티 네이션, 커밋의 시작과 끝.
Adam Dymitruk

14
이것은 나를 위해 일했다 :git rebase --onto <commit-ID> master

4
@ jsz의 의견은 시몬 남쪽의 의견에 반하는, 그것은 다른 방법으로 주위있어, 올 git rebase --onto master <commit-ID-of-old-parent>영업 이익을 위해 git rebase --onto B A.
gaborous

19

위의 jsz의 의견은 많은 고통을 덜어주었습니다. 따라서 다른 커밋 위에 커밋을 리베이스 / 이동시키는 데 사용했던 단계별 레시피가 있습니다.

  1. 리베이스 (이동) 할 분기의 이전 분기점을 찾으십시오.이를 이전 상위라고합니다. 위의 예에서 A는
  2. 분기를 이동하려는 커밋을 새 부모라고 부릅니다. Exampe에서 그것은 B입니다
  3. 지점 (이동 지점)에 있어야합니다.
  4. 리베이스를 적용하십시오 : git rebase --onto <new parent> <old parent>

위의 예에서 다음과 같이 간단합니다.

   git checkout topic
   git rebase --onto B A

6
이것이 정답이어야합니다. 내가 사용하는 것을 제외하고 는 더 자세한 설명은 대답git rebase --onto B master참조하십시오 .
잭 모리스

그것은 나에게 잘 작동하지 않았다. 나는 2 개의 연속 커밋 (현재 분기에있는 마스터의 마지막 커밋과 현재 분기에없는 마스터의 첫 번째 커밋)을 선택했습니다. 나는 100 뒤에 -10 전방으로 시작했고 99 뒤에 -10 전방에있는 대신 105 뒤에 -13 전방에 있습니다.
ROMANIA_engineer

작동하지 않는 다니 유감입니다. 당신의 가지가 꽤 많이 갈라진 것처럼 들립니다.이 많은 차이점으로 가지를 리베이스하기 전에 먼저 스쿼시하는 것이 좋습니다.
Nestor Milyaev

11

주제 솔루션

게시 된 질문에 대답하기위한 올바른 명령은 다음 중 하나 일 수 있습니다 (분기 topic가 이미 체크 아웃 되었다고 가정 ).

git rebase --onto B master
git rebase --onto master~1 master
git rebase --onto B A
git rebase --onto B C
git rebase --onto B

topic체크 아웃되지 않은 경우 다음 topic과 같이 명령에 마지막 명령을 추가 하면됩니다 (마지막 명령 제외).

git rebase --onto B master topic

또는 먼저 다음을 사용하여 지점을 확인하십시오.

git checkout topic

모든 커밋 문자열을 대상 커밋으로 리베이스

우리가 필요로하는 명령의 기본 형태는 다음과 같습니다.

git rebase --onto <Target> [<Upstream> [<Branch>]]

<Branch>선택적이며 나머지 명령을 실행하기 전에 지정된 분기를 체크 아웃하기 만하면됩니다. 리베이스하려는 지점을 이미 체크 아웃 한 경우 필요하지 않습니다. 사용자가 지정한해야합니다 <Upstream>지정하기 위해 <Branch>또는 자식이 당신이 지정하는 생각합니다 <Upstream>.

<Target>커밋 문자열을 첨부 할 커밋입니다. 지점 이름을 제공 할 때는 해당 지점의 헤드 커밋을 지정하기 만하면됩니다. <Target>이동되는 커밋 문자열에 포함되지 않는 커밋이 될 수 있습니다. 예를 들면 다음과 같습니다.

A --- B --- C --- D         master
      \
       \-- X --- Y --- Z    feature

전체 기능 지점을 이동하려면, 당신은 선택할 수 없습니다 X, Y, Z, 또는 feature는 AS <Target>그 이후 모든 이동하는 그룹 내부 커밋이다.

<Upstream>두 가지를 의미 할 수 있기 때문에 특별합니다. 체크 아웃 된 브랜치의 조상 인 커밋이면 컷 포인트 역할을합니다. 내가 제공 한 예에서,이없는 어떤 것 C, D또는를 master. <Upstream>체크 아웃 된 지점의 헤드가 이동 될 때까지의 모든 커밋

그러나 <Upstream>조상이 아닌 경우 git은 체크 아웃 된 분기가있는 공통 조상을 찾을 때까지 지정된 커밋에서 체인을 백업합니다 (찾을 수 없으면 중단). 우리의 경우,에서 <Upstream>B, C, D, 또는 master것입니다 커밋의 모든 결과 B절단 지점의 역할. <Upstream>자체는 선택적인 명령이며, 지정하지 않으면 git은 입력 한 것과 동일한 체크 아웃 된 브랜치의 부모를 찾습니다 master.

git은 커밋하고 이동할 커밋을 선택 <Target>했으므로 대상에 이미 적용된 커밋을 건너 뛰기 위해 커밋을 적용합니다 .

흥미로운 예와 결과

이 시작점을 사용하여 :

A --- B --- C --- D --- E         master
            \
             \-- X --- Y --- Z    feature
  • git rebase --onto D A feature
    커밋을 적용 B, C, X, Y, Z커밋하기 D및 스킵하지 않는 BC그들은 이미 적용되어 있기 때문이다.

  • git rebase --onto C X feature
    커밋 을 효과적으로 삭제하고 커밋 을 적용 Y하고 커밋합니다.ZCX


4

더 간단한 해결책은 git rebase <SHA1 of B> topic입니다. 이것은 당신의 위치에 관계없이 작동합니다 HEAD.

git rebase doc 에서이 동작을 확인할 수 있습니다

<upstream>비교할 업스트림 브랜치 기존 브랜치 이름뿐만 아니라 유효한 commit 일 수 있습니다 . 현재 분기에 대해 구성된 업스트림이 기본값입니다.


topic위의 명령에서 SHA1을 언급하면 ​​어떻게 될지 생각하고 있습니까?

git rebase <SHA1 of B> <SHA1 of topic>

이것은 또한 작동하지만 rebase는 Topic그렇게 만들어져 새로운 분기를 가리 키지 않으며 HEAD분리 된 상태가됩니다. 따라서 여기에서 이전을 수동으로 삭제 Topic하고 rebase에서 만든 새 분기에 새 분기 참조를 작성해야합니다.


3

위에서 설명한 여러 가지 솔루션을 사용했습니다.

$ git branch temp <specific sha1>
$ git rebase --onto temp master topic
$ git branch -d temp

읽고 이해하는 것이 훨씬 쉽다는 것을 알았습니다. 수용 된 솔루션으로 인해 병합 충돌이 발생합니다 (손으로 수정하기에는 너무 게으르다).

$ git rebase temp
First, rewinding head to replay your work on top of it...
Applying: <git comment>
Using index info to reconstruct a base tree...
M       pom.xml
.git/rebase-apply/patch:10: trailing whitespace.
    <some code>
.git/rebase-apply/patch:17: trailing whitespace.
        <some other code>
warning: 2 lines add whitespace errors.
Falling back to patching base and 3-way merge...
Auto-merging pom.xml
CONFLICT (content): Merge conflict in pom.xml
error: Failed to merge in the changes.
Patch failed at 0001 <git comment>
The copy of the patch that failed is found in: .git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

1
여기서도 가장 인기있는 두 가지 답변 (예 : r0hitsharma 및 Dymitruk)을 사용했을 때 여러 파일이 충돌했습니다.
Oliver

3

rebasing이 매우 기본이기 때문에 Nestor Milyaev의 답변이 확장되었습니다 . Adam Dymitruk의 답변 에서 jszSimon South의 주석을 결합 하면 지점의 커밋 에서 분기 되는지 또는 분기에서 분기되는지에 관계 없이이 명령을 수행합니다 .topicmasterAC

git checkout topic
git rebase --onto <commit-B> <pre-rebase-A-or-post-rebase-C-or-base-branch-name>

마지막 인수가 필요합니다 (그렇지 않으면 커밋하기 위해 분기를 되감습니다) B ).

예 :

# if topic branches from master commit A:
git checkout topic
git rebase --onto <commit-B> <commit-A>
# if topic branches from master commit C:
git checkout topic
git rebase --onto <commit-B> <commit-C>
# regardless of whether topic branches from master commit A or C:
git checkout topic
git rebase --onto <commit-B> master

마지막 명령은 내가 일반적으로 사용하는 명령입니다.


-2

다른 방법이 있거나 하나 이상의 커밋으로 다시 이동하려는 경우가 있습니다.

다음은 n커밋 수로 다시 이동하는 예 입니다.

git branch topic master~n

이 질문을 위해이 작업을 수행 할 수도 있습니다.

git branch topic master~1

이 명령은에서 완벽하게 작동합니다 git version 2.7.4. 다른 버전에서는 테스트하지 않았습니다.


분기에 대한 질문으로 이것을 잘못 해석 했습니까? 이것은 실제로 rebasing에 관한 질문입니다.
NetherGranite
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.