두 개의 비 연속 커밋을 어떻게 스쿼시합니까?


183

나는 git 내의 모든 rebasing 기능에 약간 익숙하다. 내가 다음과 같은 커밋을했다고 가정 해 봅시다.

A -> B -> C -> D

이후 D에에 추가 된 새로운 코드에 따라 수정 사항이 포함되어 있으며 A이러한 커밋이 함께 속해 있음을 알고 있습니다. 어떻게 스쿼시 않는 AD함께하고 휴가 BC혼자?

답변:


258

git rebase --interactiveB보다 먼저 D를 실행 하고 재정렬 할 수 있으며 D는 A로 스쿼시 할 수 있습니다 .

Git이 편집기를 열면 다음과 같은 파일이 나타납니다. 예 : git rebase --interactive HEAD~4

pick aaaaaaa Commit A
pick bbbbbbb Commit B
pick ccccccc Commit C
pick ddddddd Commit D

# Rebase aaaaaaa..ddddddd onto 1234567 (4 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

이제 다음과 같은 파일을 변경하십시오.

pick aaaaaaa Commit A
squash ddddddd Commit D
pick bbbbbbb Commit B
pick ccccccc Commit C

그리고 git은 이제 A와 D의 변경 사항을 하나의 커밋으로 병합하고 나중에 B와 C를 넣습니다. 대신 커밋 메시지 D를 유지하지 않으려면 키워드를 squash사용하십시오 fixup. 에 대한 자세한 내용 fixupgit rebase문서를 참조 하거나 좋은 답변 이있는이 질문 을 확인하십시오 .


5
처음에 나는 그것을 "D에 A를베이스로, D를 A에 A로, 그리고 B를 DA에 리베이스한다"라고 읽었다. 텍스트 편집기에서 행을 재정렬 하여이 작업을 수행 할 수 있다는 것은 명확하지 않습니다.
Victor Sergienko 17

3
지점이 현지인 There is no tracking information for the current branch경우 재베이스 작업시 오류가 발생합니다. 이 경우 다음과 같이 작업하려는 커밋 수를 지정해야합니다 git rebase -i HEAD~4. 이 답변을 참조하십시오 .
johndodo

1
몇 년 동안 대화 형 모드 (git rebase -i)를 사용하여 방금 재정렬 될 수 있음을 깨달았습니다 . 감사합니다 🤟🏻
CalvinChe

43

참고 : 결과 를 알지 못하면 다른 리포지토리 로 푸시 된 커밋을 변경 해서는 안됩니다 .

git log --oneline -4

D commit_message_for_D
C commit_message_for_C
B commit_message_for_B
A commit_message_for_A

git rebase --interactive

pick D commit_message_for_D
pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A

타입 i(삽입 모드에서 VIM 넣기)

다음과 같이 목록을 변경하십시오 (커밋 메시지를 제거하거나 포함하지 않아도 됨). 철자를 틀리지 마십시오 squash! :

pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A
squash D

입력 Esc한 후 ZZ(VIM 저장 후 종료)

# This is a combination of 2 commits.
# The first commit's message is:

commit_message_for_D

# This is the 2nd commit message:

commit_message_for_A

유형 i

텍스트를 새 커밋 메시지의 모양으로 변경하십시오. 커밋 A및 변경 사항에 대한 설명입니다 D.

new_commit_message_for_A_and_D

입력 Esc후,ZZ

git log --oneline -4

E new_commit_message_for_A_and_D
C commit_message_for_C
B commit_message_for_B

git show E

(You should see a diff showing a combination of changes from A and D)

이제 새로운 커밋을 만들었습니다 E. 커밋 A하고 D더 이상 당신의 역사에 있지 않지만 사라지지 않았습니다. 여전히이 시점에서 복구 할 수 있으며 잠시 동안 git rebase --hard D( git rebase --hard로컬 변경 사항이 삭제됩니다! ).


3

SourceTree를 사용하는 사람들 :

커밋을 아직 푸시하지 않았는지 확인하십시오.

  1. 리포지토리> 대화식 리베이스 ...
  2. D (최신 커밋)를 A (오래된 커밋) 바로 위로 드래그
  3. 커밋 D가 강조 표시되어 있는지 확인
  4. 딸깍 하는 소리 Squash with previous

1

대화 형 리베이스는 지점에서 커밋하는 동안 20-30 개의 커밋 및 / 또는 마스터로부터의 병합 및 / 또는 충돌을 해결하는 큰 기능 분기가있을 때까지 잘 작동합니다. 심지어 역사를 통해 내 커밋을 찾는 및 교체와 pick함께 squash여기에 일을하지 않습니다. 그래서 나는 다른 방법을 찾고 있었고이 기사를 찾았다 . 별도의 지점 에서이 작업을 수행하기 위해 변경을 수행했습니다.

git checkout master
git fetch
git pull
git merge branch-name
git reset origin/master
git branch -D branch-name
git checkout -b branch-name
git add --all
#Do some commit
git push -f --set-upstream origin branch-name

이 전에 마스터 + 수정 충돌에서 2-3 개의 병합으로 약 30 개의 커밋으로 풀 요청을 받았습니다. 그리고 그 후 나는 한 번의 커밋으로 명확한 PR을 얻었습니다.

PS 는 자동 모드 에서이 단계를 수행하는 bash 스크립트 입니다.


이 기사의 첫 번째 솔루션은 링크 덕분입니다.
Hoody

-1

$ git checkout master

$ git log --oneline

D
C
B
A

$ git rebase --onto HEAD ^^^ HEAD ^

$ git log --oneline

D
A

내 생각 엔 --oneline? 그리고 그것은 당신이 떨어진 것 같은 모습 CB영업 이익이 의도 한 바가 아니다.
bstpierre

나를 위해 작동하지 않았다. HEAD와 마스터를 모두 A로 옮겼지만 D를 A ( git show A) 로 병합하지 않았 으며 D, C 및 B가 내 참조 로그에서 손실되었습니다. 했다 git rebase D다시 얻을 수 있습니다.
Nate
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.