이미 리베이스를 시작한 경우 두 커밋을 하나로 병합하려면 어떻게해야합니까?


1157

2 커밋을 1로 병합하려고 하므로 git ready에서“rebase로 커밋 스쿼시”를 수행했습니다 .

나는 달렸다

git rebase --interactive HEAD~2

결과 편집기에서, 나는 변경 picksquash한 다음 저장 - 종료하지만, REBASE는 오류와 함께 실패

이전 커밋없이 '스쿼시'할 수 없습니다

작업 트리가이 상태에 도달 했으므로 복구에 문제가 있습니다.

이 명령 git rebase --interactive HEAD~2은 다음과 같이 실패합니다.

대화식 리베이스가 이미 시작되었습니다

그리고 git rebase --continue실패

이전 커밋없이 '스쿼시'할 수 없습니다


22
나는 이것도 명중했다. 내 실수는 git rebase -i가 커밋을 git log의 반대 순서로 나열한다는 사실에 기인합니다. 최신 커밋이 맨 아래에 있습니다!
lmsurprenant 2019


1
nha

답변:


1732

요약

오류 메시지

이전 커밋없이 '스쿼시'할 수 없습니다

"아래로 스쿼시"하려고 시도했을 가능성이 있습니다. Git은 항상 새로운 커밋을 이전 커밋 또는 이전에 커밋 된 대화 형 rebase 할 일 목록에서 볼 때 "위쪽으로" 스쿼시합니다 . 할 일 목록의 첫 번째 줄에서 명령을 변경하면 squash첫 번째 커밋이 스쿼시되지 않기 때문에 항상이 오류가 발생합니다.

수정

먼저 시작한 곳으로 돌아갑니다.

$ git rebase --abort

당신의 역사가

$ git log --pretty=oneline
a931ac7c808e2471b22b5bd20f0cad046b1c5d0d c
b76d157d507e819d7511132bdb5a80dd421d854f b
df239176e1a2ffac927d8b496ea00d5488481db5 a

즉, a는 첫 번째 커밋이고 b, 마지막으로 c입니다. c를 커밋 한 후 b와 c를 함께 스쿼시하기로 결정합니다.

(참고 : 대부분의 플랫폼에서 기본적 git log으로 실행 하면 출력이 호출기로 출력됩니다. 호출기 less를 종료하고 명령 프롬프트로 돌아가려면 q키를 누르십시오 .)

실행 git rebase --interactive HEAD~2하면 편집기가 제공됩니다

pick b76d157 b
pick a931ac7 c

# Rebase df23917..a931ac7 onto df23917
#
# 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
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

(이 할 일 목록은의 출력과 비교할 때 반대 순서입니다 git log.)

B의 변경 pick하는 squash당신이 본 오류가 발생하지만 B에 C 스쿼시 대신하면됩니다 (새가에 커밋 이전 또는 "위로 부수")에 할 일 목록을 변경하여

pick   b76d157 b
squash a931ac7 c

편집기를 저장 중지하면 내용이 다른 편집기가 나타납니다.

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

b

# This is the 2nd commit message:

c

저장하고 종료하면 편집 된 파일의 내용이 결합 된 새 커밋의 커밋 메시지가됩니다.

$ git log --pretty=oneline
18fd73d3ce748f2a58d1b566c03dd9dafe0b6b4f b and c
df239176e1a2ffac927d8b496ea00d5488481db5 a

기록 재 작성에 대한 참고 사항

대화식 리베이스가 기록을 다시 씁니다. 이전 기록이 포함 된 리모컨을 푸시하려고하면 빨리 감기되지 않으므로 실패합니다.

리베이스하는 브랜치 가 직접 작업 하는 토픽 또는 기능 브랜치 라면 별다른 문제가 없습니다. 다른 리포지토리로 푸시하려면 --force옵션 이 필요 하거나 원격 리포지토리의 권한에 따라 먼저 이전 분기를 삭제 한 다음 리베이스 된 버전을 푸시 할 수 있습니다. 작업을 잠재적으로 파괴 할 수있는 명령의 예는이 답변의 범위를 벗어납니다.

당신이없이 다른 사람들과 작업하는 지점에 이미 게시 된 역사를 다시 쓰기 아주 같은 공동 작업자에 암호 나 기타 민감한 정보를 강제로 일을 누출로 좋은 이유와 것은 반사회적이고 다른 개발자를 성가 시게한다. 설명서의 "업스트림 리베이스에서 복구"섹션에git rebase 강조가 추가 되어 설명되어 있습니다.

다른 사람이 작업 한 브랜치를 리베이스 (또는 다른 형태의 재 작성)하는 것은 나쁜 생각입니다. 이 섹션에서는 다운 스트림 관점에서 수정을 수행하는 방법에 대해 설명합니다. 그러나 실제 수정은 처음부터 업스트림을 리베이스하지 않는 것입니다.


rebase를 사용하여 커밋을 스쿼시하면 두 개의 변경 세트를 포함하는 새로운 "결합 된"커밋이 생성되지만 해시는 다릅니다. 원래 커밋도 git에 의해 보존됩니까?
fabsenet

@fabsenet 예와 아니오. 원래 커밋은 여전히 ​​액세스 가능하지만 더 이상 모든 기록에서 도달 할 수 없습니다 (이력의 특정 사항에 따라 다름). 참조되지 않은 커밋은 결국 가비지 수집 프로세스를 통해 정리됩니다.
Greg Bacon

난 그냥 ... 장난되었다 내가 한 git log hashoftheoldcommit그것은 일,하지만 난이를보고 호기심 git log --graph이 도달 할 수없는 커밋 모두와 함께하는 것이 포함
fabsenet

이 스쿼시는 푸시 전에 커밋을 구성하는 좋은 도구이지만 커밋을 푸시하면 스쿼시 할 수 없습니까? 자식은 말합니다 : 분리 된 HEAD를 성공적으로 리베이스하고 업데이트했습니다.
Sérgio

두 번째 인스턴스의 편집기 인 git bash는 일부 프로세스에 고정 된 것처럼 보입니다. 무엇을해야합니까?

411

커밋이 여러 개인 경우 git rebase -i두 커밋을 하나로 스쿼시 하는 데 사용할 수 있습니다 .

병합하려는 커밋이 두 개이고 "가장 최근 두 개"인 경우 다음 명령을 사용하여 두 커밋을 하나로 결합 할 수 있습니다.

git reset --soft "HEAD^"
git commit --amend

6
rebase와 비교할 때 단점은 무엇입니까? 사용하기가 훨씬 간단합니다.
Guillaume86

17
임의의 순서로 참여할 수 없으며 마지막 두 커밋 에만 참여할 수 있습니다 .
dr0i

50
@ dr0i 마지막 X 커밋이고 중간 어딘가가 아닌 한 원하는만큼 커밋을 병합 할 수 있습니다 . 그냥 실행하십시오 git reset --soft HEAD~10. 여기서 10은 병합하려는 커밋 수입니다.
fregante

2
원격 원점 세트가없고 커밋이 두 개인 경우에 사용할 수 있습니다.
atedja

8
커밋 의 SHA1 ID는 어디에서 HEAD사용하여 몇 개인 지 계산하지 않으려는 경우 특정 커밋으로 재설정 할 수도 있습니다 . git reset --soft 47b5c5...47b5c5...
dguay

112

Rebase : 당신은 그것을 필요로하지 않을 것입니다 :

가장 빈번한 시나리오를위한 더 간단한 방법.

대부분의 경우에:

당신이 원하는 모든 경우 사실 그냥 단순히 하나에 몇 가지 최근의 커밋을 결합 하지만 필요하지 drop, reword다른 REBASE 작업.

당신은 간단하게 할 수 있습니다 :

git reset --soft "HEAD~n"
  • ~n부드럽게 커밋 해제하는 커밋 수를 가정합니다 (예 ~1: ~2, ...).

그런 다음 커밋 메시지를 수정하려면 다음 명령을 사용하십시오.

git commit --amend

이것은 장거리 squash와 하나와 거의 동일 pick합니다.

그리고 위의 답변이 프롬프트 된 것처럼 두 개의 커밋이 아닌 n 개의 커밋에 대해 작동합니다.


3
이것은 중간에 1 커밋을 제거하거나 코드 줄을 변경하는 것과 같이 커밋을 스쿼시하는 것 외에도 추가 정리를 수행하려는 경우에 좋습니다.
styfle

1
~n부드럽게 커밋 해제하는 커밋 수를 가정합니다 (예 ~1: ~2, ...)
Ray

1
n마지막 커밋이 아니라 n중간에 커밋 을 병합하려면 어떻게해야 합니까? 이것을 쉽게 할 수 있습니까?
chumakoff

1
그런 다음 git rebase -i일을해야합니다 squash. @chumakoff
pambda

3
그래서 가입 n하나, 처음 사용하기에 가장 최근의 커밋을 git reset --soft @~m,m = n - 1
의 Łukasz Rajchel

55

먼저 커밋 수를 확인해야합니다.

git log

두 가지 상태가 있습니다.

하나는 있다는 것입니다 이 커밋 :

예를 들면 다음과 같습니다.

commit A
commit B

(이 경우 git rebase를 사용하여 수행 할 수 없습니다) 다음을 수행해야합니다.

$ git reset --soft HEAD^1

$ git commit --amend

다른 하나는 커밋이 두 개 이상 있다는 것입니다. 커밋 C와 D를 병합하려고합니다.

예를 들면 다음과 같습니다.

commit A
commit B
commit C
commit D

(이 조건에서 git rebase를 사용할 수 있습니다)

git rebase -i B

그리고 "스쿼시"를 사용하는 것보다. 나머지 부분은 매우 쉽습니다. 여전히 모르는 경우 http://zerodie.github.io/blog/2012/01/19/git-rebase-i/ 를 읽으십시오


재설정 --soft and commit --amend는 이미 리베이스가 진행중인 경우 작동하는 유일한 방법입니다 (이 커밋에 대해 '스쿼시'대신 '편집'을 선택). +1
Jacek Lach

1
저장소에서 첫 번째와 두 개의 커밋을 병합, 정확히 내 우위 사례 :-)
Chris Huang-Leaver

1
git push -f origin master필요할 수 있습니다 추가하십시오 .
Rishabh Agrahari

33

자신의 토픽 브랜치에 있다고 가정합니다. 마지막 두 커밋을 하나로 병합하고 영웅처럼 보이려면 마지막 두 커밋을하기 직전에 커밋을 분기하십시오.

git checkout -b temp_branch HEAD^2

그런 다음이 새로운 지점에서 다른 지점을 스쿼시 커밋하십시오.

git merge branch_with_two_commits --squash

변경 사항이 적용되지만 커밋되지는 않습니다. 커밋 만하면 끝입니다.

git commit -m "my message"

이제이 새로운 토픽 브랜치를 메인 브랜치로 다시 병합 할 수 있습니다.


5
이것은 수동 리베이스가 필요하지 않기 때문에 실제로 가장 유용한 답변이었습니다. 대신 전체 분기의 모든 커밋을 하나의 커밋으로 스쿼시합니다. 아주 좋아요
Robert

감사합니다! 이것은 내 머리에 스쿼시 커밋을 그리는 방법을 git가 만드는 방법입니다!
Marjan Venema

놀라운 답변, 대안보다 훨씬 간단

분명히,이 답변이 경우에 적합하지 않은 경우 ac함께 합병 유지 될 필요 b그대로.
Talha Ashraf

2
최신 버전의 git에서 변경된 것이 있습니까? git checkout -b combine-last-two-commits "HEAD^2"git 버전 2.17에서 첫 번째 명령 ( )을 시도하면 오류가 발생합니다.fatal: 'HEAD^2' is not a commit and a branch 'combine-last-two-commits' cannot be created from it
mhucka

23

당신은 리베이스를 취소 할 수 있습니다

git rebase --abort

대화식 rebase 명령을 다시 실행하면 'squash; commit은 목록에서 pick commit 아래에 있어야합니다.


16

나는 종종 git reset --mixed 를 사용 하여 병합하려는 여러 커밋 전에 기본 버전을 되 돌린 다음 새 커밋을 수행하여 커밋을 최신 상태로 만들 수 있습니다.

commit ac72a4308ba70cc42aace47509a5e
Author: <me@me.com>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <me@me.com>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <ralph@me.com>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

헤드 두 커밋을 하나로 병합하려면 먼저 다음을 사용하십시오.

git reset --mixed 249cf9392da197573a17c8426c282

"249cf9392da197573a17c8426c282"는 세 번째 버전이며 병합하기 전에 기본 버전이기도합니다. 그 후 새 커밋을 수행합니다.

git add .
git commit -m 'some commit message'

모두가 희망입니다. 희망은 모든 사람을위한 또 다른 방법입니다.

참고로 git reset --help:

 --mixed
     Resets the index but not the working tree (i.e., the changed files are
     preserved but not marked for commit) and reports what has not been
     updated. This is the default action.

나는 '--mixed'에 대한 문서를 읽지 못했지만 다른 사람들이 게시물을 읽고 같은 것을 궁금해합니다. --mixed를 사용하면 어떤 이점이 있습니까? 매뉴얼 페이지의 스 니펫을 포함하도록 게시물을 개선 할 수 있습니다.
funroll

@funroll 몰랐어요-이 답변을 작성하기 전에 많이 혼합 되었습니다. 내 경험에 따르면 혼합 작업은 저장소 HEAD 버전으로 인수로 전달한 버전을 지정하며 해당 버전 이후에는 아무것도 잃을 수 없습니다. 그래도 이러한 변경 사항을 처리 할 수 ​​있습니다.
VinceStyling

14

$ git rebase --abort

git rebase를 취소하려면 언제든지이 코드를 실행하십시오.

$ git rebase -i HEAD~2

마지막 두 커밋을 다시 적용합니다. 위의 명령은 코드 편집기를 엽니 다

  • [ 최신 커밋은 맨 아래에 있습니다 ]. 마지막 커밋을 스쿼시로 변경하십시오. 스쿼시는 이전 커밋과 융합됩니다.
  • 그런 다음 esc 키를 누르고 : wq를 입력하여 저장하고 닫습니다.

: wq 이후에는 활성 리베이스 모드가됩니다

참고 : 경고 / 오류 메시지가 없으면 다른 편집기가 표시됩니다. 오류가 있거나 다른 편집기가 표시하지 않는 경고가 표시되면$ git rebase --abort오류가 발생하면 경고를 보내거나 달리 실행하여 계속 진행하면중단 될 수 있습니다 $ git rebase --continue

커밋 메시지 2 개가 표시됩니다. 하나를 선택하거나 커밋 메시지를 작성하고 저장하고 종료하십시오 : [: wq]

참고 2 : rebase 명령을 실행하는 경우 변경 사항을 원격 저장소로 강제로 푸시해야 할 수도 있습니다 .

$ git push -f

$ git push -f origin master


1
참고 2 : git push -f origin/master다른 답변이 누락되었습니다. +1
Rishabh Agrahari

2

나는 git cherry-pick거의 모든 것에 사용 하기 때문에 여기에서도 그렇게하는 것이 당연합니다.

내가 branchX체크 아웃하고 그 끝에 두 개의 커밋이 있다고 가정하면 그 커밋을 내용과 결합하여 하나의 커밋을 만들고 싶습니다.

git checkout HEAD^ // Checkout the privious commit
git cherry-pick --no-commit branchX // Cherry pick the content of the second commit
git commit --amend // Create a new commit with their combined content

나는 branchX또한 업데이트하고 싶다면 (그리고 이것이이 방법의 단점이라고 가정한다) 나는 또한 :

git checkout branchX
git reset --hard <the_new_commit>

1

마스터 브랜치 git log가 다음과 같은 경우 :

commit ac72a4308ba70cc42aace47509a5e
Author: <me@me.com>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <me@me.com>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <ralph@me.com>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

상위 두 커밋을 병합하려면 다음과 같은 쉬운 단계를 수행하십시오.

  1. 첫 번째 안전한 커밋은 별도의 지점에서 마지막 커밋을 확인하십시오. 지점 이름을 지정할 수 있습니다.git checkout 77df2a40e53136c7a2d58fd847372 -b merged-commits
  2. 이제 마지막 커밋에서이 새로운 브랜치에 대한 변경 사항을 다음과 같이 선택하십시오 git cherry-pick -n -x ac72a4308ba70cc42aace47509a5e. (만약 충돌이 발생하면 해결)
  3. 이제 마지막 커밋의 변경 사항이 두 번째 마지막 커밋에 있습니다. 그러나 여전히 커밋해야하므로 먼저 체리 선택 한 변경 사항을 추가 한 다음 실행하십시오 git commit --amend.

그게 다야. 원하는 경우이 병합 된 버전을 "병합 커밋"분기로 푸시 할 수 있습니다.

또한 이제 마스터 브랜치에서 연속적인 두 커밋을 버릴 수 있습니다. 마스터 브랜치를 다음과 같이 업데이트하십시오.

git checkout master
git reset --hard origin/master (CAUTION: This command will remove any local changes to your master branch)
git pull

0

가장 최근의 두 커밋을 결합하고 이전 커밋 메시지를 사용하려는 경우을 사용하여 프로세스를 자동화 할 수 있습니다 expect.

나는 가정 :

  • vi를 편집기로 사용하고 있습니다.
  • 커밋은 한 줄씩

나는로 테스트했다 git version 2.14.3 (Apple Git-98).


#!/usr/bin/env expect
spawn git rebase -i HEAD~2

# change the second "pick" to "squash"
# down, delete word, insert 's' (for squash), Escape, save and quit
send "jdwis \033:wq\r"

expect "# This is a"

# skip past first commit message (assumed to be one line), delete rest of file
# down 4, delete remaining lines, save and quit
send "4jdG\r:wq\r"

interact

스크립트가 무엇을하는지 분명하지 않습니다.
buhtz

@buhtz 댓글을 더 추가했습니다. 여전히 혼란스럽고 어떤 부분이 있는지 알려주세요.
erwaman

당신의 흠집이 무엇을하는지 여전히 불분명합니다. 또한 설명 expect되지 않습니다.
buhtz

@buhtz 어느 부분이 불분명합니까? 에 대한 추가 문서가있는 페이지에 대한 링크를 제공했습니다 expect.
erwaman

스크립트에 대한 일반적인 설명이 없습니다. 그것이 무엇인지 확실하지 않습니다. 확실하지 않은 부분이 없습니다. 스크립트 자체의 의도는 불분명합니다.
buhtz
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.