이미 원격 지점으로 푸시 된 병합 커밋을 되 돌리는 방법은 무엇입니까?


960

git revert <commit_hash>혼자서는 작동하지 않습니다. -m지정해야하며 꽤 혼란 스럽습니다.

아무도 전에 이것을 경험 했습니까?


3
이 질문에 대한 답을 살펴보십시오 : stackoverflow.com/questions/2318777/…
eugen


여기 링크는 병합 된 커밋을 되 돌리는 가장 좋은 예입니다. christianengvall.se/undo-pushed-merge-git
SK Venkat

이것은 디자인이 모든 사람이 사용 git하는 git-flow-ish 워크 플로 와 일치하지 않는 예입니다 . 물론develop 체크 아웃 한 경우 오랫동안 공유 dev 분기가 아닌 버그가 발생한 2 커밋 기능 분기를 되돌리려 고합니다. 말도 안되는 느낌이 든다 . -m 1
pkamb

2
전에 나에게 결코 발생하지 않은 한 가지 다른 제안-분기의 커밋 목록 중 하나가 작은 경우 전체 커밋 분기 대신 개별 커밋을 되 돌리는 것이 더 편할 수 있습니다.
Sridhar Sarnobat

답변:


1153

-m옵션은 부모 번호를 지정합니다 . 이는 병합 커밋이 둘 이상의 부모를 가지고 있기 때문에 Git은 어떤 부모가 메인 라인인지, 어떤 부모가 병합을 해제하려는 브랜치인지 자동으로 알지 못하기 때문입니다.

의 출력에서 ​​병합 커밋을 보면 git log다음으로 시작하는 행에 부모가 나열됩니다 Merge.

commit 8f937c683929b08379097828c8a04350b9b8e183
Merge: 8989ee0 7c6b236
Author: Ben James <ben@example.com>
Date:   Wed Aug 17 22:49:41 2011 +0100

Merge branch 'gh-pages'

Conflicts:
    README

이 상황에서 git revert 8f937c6 -m 1이 있다는 당신에게 나무를 얻을 것이다 8989ee0, 그리고 git revert -m 2이 있다는 트리를 복원합니다 7c6b236.

부모 ID를 더 잘 이해하려면 다음을 실행하십시오.

git log 8989ee0 

git log 7c6b236

127
두 숫자에서 8989ee0, 7c6b236갈 하나. 어떻게 이해할까요?
Arup Rakshit

12
되 돌린 후에 소스 분기의 코드 를 쉽게 수정하고 다시 병합 할 수 없다고 생각 합니까? kernel.org/pub/software/scm/git/docs/howto/…
IsmailS

10
더 나은 설명을 찾기 위해 인터넷 검색을하면서 세부 사항을 다루는 데 도움이되는이 기사를 찾았습니다. 필자가 실제로 찾고 있던 것은 RESET 명령이었고 강제 푸시가 발견되었습니다. 아마 다른 사람을 도울 것입니다. atlassian.com/git/tutorials/…
Funktr0n

46
당신이 실행하는 경우 @ArupRakshit git log 8989ee0하고 git log 7c6b236, 당신은 답을 알고 있어야합니다.
BMW

4
git log-병합하여 모든 병합을보고 git log --no- 병합하여 병합없이 기록을 볼 수 있습니다. 브랜치를 병합하면 병합 된 브랜치 히스토리를 대상으로 가져와 일반 자식 로그를 사용하기 어렵게 만듭니다
Alex Punnen

369

다음은 누군가에게 도움이되기를 희망하는 완전한 예입니다.

git revert -m 1 <commit-hash> 
git push -u origin master

어디 <commit-hash>를 이용해서 복귀하고 싶다고 병합의 해시를 저지하고,의 설명에 명시된 바와 같이 이 응답 , -m 1당신이 병합하기 전에 먼저 부모의 트리로 복귀하고 싶은 것을 나타냅니다.

git revert ...두 번째 줄은 원격 지사에 밀어 변경 사항을 공개하게하면서 라인은 본질적으로 변경 사항을 커밋합니다.


21
git revert명령이 이미 커밋 객체를 커밋 했다고 믿었 습니다. 그러지 않으려면 --no-commit플래그 를 입력해야합니다
Delfic

2
@Delfic이 언급했듯이 커밋은 이미 첫 번째 줄에서 관리하므로 (확인하기 위해 : wq가 필요함) 두 번째 줄은 필요하지 않습니다.
eka808

1
혼란 스럽습니다. 2 줄만 있고 git commit은 없습니다. 누군가 편집 할 수 있습니다.
제이 랜덤

176

Ben은 병합 커밋을 되 돌리는 방법을 알려 주었지만 그렇게하는 것이 매우 중요 합니다.

"... 는 병합으로 인해 트리 변경 사항을 가져 오지 않기를 선언합니다. 결과적으로 나중에 병합하면 이전에 되 돌린 병합의 조상이 아닌 커밋에 의해 도입 된 트리 변경 사항 만 가져옵니다. 당신이 원하는 것. " (git-merge man page) .

기사 / 메일 링리스트 메시지 man 페이지에서 링크가 포함되는 메커니즘과 고려 사항에 대해 자세하게 설명합니다. 병합 커밋을 되 돌리면 나중에 분기를 다시 병합 할 수 없으며 동일한 변경 사항이 다시 발생할 것으로 기대할 수 있습니다.


80
그러나 실제로 필요한 경우 되돌리기를 되돌릴 수 있습니다.
dalore

5
감사. 버그로 인해 병합을 취소하는 유스 케이스로 알고, 버그가 수정되면 전체 분기를 다시 병합하는 것이 일반적입니다.
구성 요소 10

3
나와 같고 나중에 병합을 원하면 되돌리기를 되돌 리거나 되 돌린 변경 사항을 체리로 선택할 수 있습니다.
UnitasBrooks

내 상황에서 변경 사항을 다시 발급 받기 위해 '되돌리기'를해야했습니다. 체리 따기는 더 깔끔한 방법이 될 수 있습니까? 다음에해볼 게요 ...
Steven Anderson

79

다음 단계에 따라 잘못된 커밋을 되돌 리거나 원격 분기를 다시 HEAD / 상태로 다시 재설정 할 수 있습니다.

  1. 원격 지사를 로컬 리포지토리로 체크 아웃하십시오.
    git checkout development
  2. 커밋 해시 (즉, 잘못된 커밋 직전 커밋의 ID)를 자식 로그에서 복사하십시오. git log -n5

    산출:

    커밋 7cd42475d6f95f5896b6f02e902efab0b70e8038 "브랜치 '잘못된 커밋'을 '개발'로 병합 '
    커밋 f9a734f8f44b0b37ccea769b9a2fd774c0f0c012"이것은 잘못된 커밋입니다 "
    커밋 3779ab50e72908da92d2ff

  3. 이전 단계에서 복사 한 커밋 해시로 분기 재설정
    git reset <commit-hash> (i.e. 3779ab50e72908da92d2cfcd72256d7a09f446ba)

  4. 를 실행하여 git status잘못된 커밋의 일부인 모든 변경 사항을 표시하십시오.
  5. git reset --hard모든 변경 사항을 되돌리려면 간단히 실행하십시오 .
  6. 로컬 지사를 원격으로 강제 푸시하고 커밋 히스토리가 오염되기 전과 같이 깨끗한 지 확인하십시오.
    git push -f origin development

4
그 동안 20 명의 개발자가 최신 개발 병합을 가져간 경우 어떻게됩니까?
Ewoks

2
팀에 해당 지점을 사용하는 20 명의 개발자가있을 때 개발 지점을 강요하지는 않습니다. :)이 경우에는 되돌리기 커밋을하는 것이 현명합니다.
ssasi

4
이것은 당신이 혼자서 일하거나 다른 개발자가 당신이 망친 커밋을 뽑지 않았다는 것을 확신 할 때 매우 좋은 해결책입니다.
Kyle B


30

아무 일도 일어나지 않았을 때 로그를 깨끗하게 유지하려면 (이 접근법의 단점은 -f로 인해) :

git checkout <branch>
git reset --hard <commit-hash-before-merge>
git push -f origin HEAD:<remote-branch>

'commit-hash-before-merge'는 병합 후 로그 (git log)에서 나옵니다.


힌트 : 회사에서이 작업을 수행하는 경우 권한이 없을 수 있습니다.
eneski

3
push -f공유 repo에 절대하지 마십시오
Baptiste Mille-Mathias

17

롤백하는 가장 효과적인 방법은 뒤로 물러서서 교체하는 것입니다.

git log

두 번째 커밋 해시 (전체 해시, 실수 전에 다시 되돌리려는 해시)를 사용한 다음 다시 시작하십시오.

git checkout -b newbranch <HASH>

그런 다음 이전 분기를 삭제하고 새 분기를 그 자리에 복사 한 다음 다시 시작하십시오.

git branch -D oldbranch
git checkout -b oldbranch newbranch

브로드 캐스트 된 경우 모든 리포지토리에서 이전 분기를 삭제하고 다시 실행 분기를 가장 중앙으로 밀고 다시 모든 분기로 당깁니다.


4
방송에 대한 경고는 이것이 얼마나 끔찍한 아이디어인지에 대해 더 분명해야합니다. 이렇게하면 해당 분기의 모든 버전이 손상되며 액세스 권한이있는 원격 저장소 (github / bitbucket)로 작업하는 경우에만 유용합니다.
RobbyD

수정 된 구성 파일을 다운 스트림으로 프로덕션으로 푸시하는 것만 큼 나쁘지 않습니다. 손상되지 않고 이전 커밋을 다시 브랜치하므로 분기 포인터를 이전 버전으로 이동하는 원형 방법입니다. 바라건대에만 영향을 로컬 저장소
ppostma1

5

merge커밋 을 되돌리려면 다음 을 수행하십시오.

  1. 먼저을 확인 git log하여 병합 커밋의 ID를 찾으십시오. 또한 병합과 관련된 여러 상위 ID를 찾을 수 있습니다 (아래 이미지 참조).

여기에 이미지 설명을 입력하십시오

병합 커밋 ID를 노란색으로 표시하십시오. 부모 ID는 다음 줄에로 쓰여진 것입니다 Merge: parent1 parent2. 지금...

단편:

  1. 병합 된 지점으로 전환하십시오. 그런 다음 커밋 메시지를 입력하기위한 콘솔을 git revert <merge commit id> -m 1열면됩니다 vi. 쓰기, 저장, 종료, 완료!

긴 이야기:

  1. 병합 된 지점으로 전환하십시오. 제 경우에는 test지점이며 feature/analytics-v3지점에서 지점 을 제거하려고 합니다.

  2. git revert커밋을 되 돌리는 명령입니다. 그러나 merge커밋을 되돌릴 때 불쾌한 트릭 이 있습니다. -m플래그 를 입력해야합니다 . 그렇지 않으면 실패합니다. 여기서부터 브랜치를 되돌릴 지, 정확히 온 브랜치인지 parent1또는 다음과 같이 보이게할지 결정해야합니다 parent2.

git revert <merge commit id> -m 1(로 되돌아 감 parent2)

git revert <merge commit id> -m 2(로 되돌아 감 parent1)

이 부모를 로그하여 원하는 방법을 알아낼 수 있으며 이것이 모든 혼란의 근원입니다.


5

모든 답변은 이미 대부분의 내용을 다루었지만 5 센트를 추가 할 것입니다. 요약하면 병합 커밋을 되 돌리는 것은 매우 간단합니다.

git revert -m 1 <commit-hash>

권한이있는 경우이를 "마스터"분기로 직접 푸시 할 수 있고, 그렇지 않으면 간단히 "복귀"분기로 푸시하여 풀 요청을 작성하십시오.

이 주제에 대한 더 유용한 정보는 여기에서 찾을 수 있습니다 : https://itcodehub.blogspot.com/2019/06/how-to-revert-merge-in-git.html


1

두 개의 알려진 끝점 사이에 역 패치를 만들고 해당 패치를 적용하면 효과가 있음을 알았습니다. 이는 마스터 브랜치에서 스냅 샷 (태그)을 생성했거나 마스터 브랜치 백업 (master_bk_01012017)을 생성 한 것으로 가정합니다.

master에 병합 한 코드 분기가 mycodebranch라고 가정하십시오.

  1. 체크 아웃 마스터.
  2. 마스터와 백업간에 전체 바이너리 리버스 패치를 작성하십시오. git diff --binary master..master_bk_01012017 > ~/myrevert.patch
  3. 패치 확인 git apply --check myrevert.patch
  4. 사인 오프로 패치 적용 git am --signoff < myrevert.patch
  5. 이 코드가 일단 수정되면 다시 가져와야 할 경우 되 돌린 마스터에서 분기하고 수정 분기를 체크 아웃해야합니다. git branch mycodebranch_fix git checkout mycodebranch_fix
  6. 여기서 복귀를위한 SHA 키를 찾아 복귀를 되돌려 야합니다. git revert [SHA]
  7. 이제 mycodebranch_fix를 사용하여 문제를 해결하고 완료되면 커밋하고 다시 병합 할 수 있습니다.

1

정답이 표시된 답변은 저에게 도움이되었지만 시간을내어 진행 상황을 파악해야했습니다. 그래서 저는 저와 같은 사례에 대해 간단한 간단한 단계로 답변을 추가하기로 결정했습니다.

분기 A와 B가 있다고 가정 해 봅시다. 분기 A를 분기 B로 병합하고 분기 B를 자체로 푸시하여 이제 병합이 그 일부가되었습니다. 그러나 병합 전에 마지막 커밋으로 돌아가고 싶습니다 . 당신은?

  1. git root 폴더 (일반적으로 프로젝트 폴더)로 이동하여 git log
  2. 최근 커밋 내역이 표시됩니다. 커밋에는 commit / author / date 속성이 있고 병합에는 merge 속성도 있습니다. 따라서 다음과 같이 표시됩니다.

    commit: <commitHash> Merge: <parentHashA> <parentHashB> Author: <author> Date: <date>

  3. 사용 git log <parentHashA>git log <parentHashB>-해당 상위 브랜치의 커밋 히스토리를 볼 수 있습니다. 목록의 첫 번째 커밋은 최신 커밋입니다.

  4. <commitHash>원하는 커밋을 가져 와서 git root 폴더로 이동하여 사용 git checkout -b <newBranchName> <commitHash>하십시오. 병합 전에 선택한 마지막 커밋에서 시작하여 새 브랜치를 만듭니다. Voila, ready!


0

또한 GitHub 리포지토리의 마스터 브랜치에 병합 된 PR에서이 문제에 직면했습니다.

난 그냥 몇 가지 수정 된 파일을 수정하고 싶어하지만 전체 변화 홍보 가져온 이후, 나는에 있었다 와 .amendmerge commitgit commit --am

단계 :

  1. 수정 한 파일을 변경 / 되돌리려는 지점으로 이동
  2. 수정 된 파일에 따라 원하는 변경을 수행하십시오.
  3. 달리기 git add *또는git add <file>
  4. 실행 git commit --am및 유효성 검사
  5. 운영 git push -f

왜 흥미로운 지 :

  • PR의 저자 커밋을 변경하지 않고 유지합니다.
  • 자식 트리를 손상시키지 않습니다.
  • 커미터로 표시됩니다 (병합 커밋 작성자는 변경되지 않음)
  • Git은 충돌을 해결하는 것처럼 작동하며 수정 된 파일의 코드를 제거하거나 변경하여 GitHub가 그대로 병합하지 않도록 수동으로 지시합니다

0

링크 에서 병합을 되 돌리는 방법에 대한 좋은 설명을 찾았으며 아래 설명을 복사하여 아래 링크가 작동하지 않는 경우에 유용합니다.

결함이있는 병합을 되 돌리는 방법 Alan (alan@clueserver.org)은 다음과 같이 말했습니다.

마스터 지점이 있습니다. 우리는 일부 개발자들이 작업하고 있다는 점을 가지고 있습니다. 그들은 그것이 준비되었다고 주장한다. 우리는 이것을 마스터 브랜치로 병합합니다. 병합을 되돌릴 수 있도록 무언가를 끊습니다. 코드를 변경합니다. 그들은 그것이 정상이라고 말하고 우리가 다시 합병하는 지점까지 그것을 얻습니다. 살펴보면 되돌리기 전에 작성된 코드 변경 사항이 마스터 분기가 아니라 이후의 코드 변경 사항이 마스터 분기에 있음을 알 수 있습니다. 이 상황에서 회복하는 데 도움을 요청했습니다.

"병합 되돌리기"직후의 기록은 다음과 같습니다.

---o---o---o---M---x---x---W
              /
      ---A---B

A와 B가 부진한 측면 개발에 있고, M은 이러한 조기 변경을 메인 라인으로 가져 오는 병합이고, x는 사이드 브랜치가 수행 한 것과 관련이없는 변경이며, 메인 라인에서 이미 수행 된 변경이며, W는 " 병합 M을 되돌립니다 "(W가 거꾸로 보이지 않습니까?). "diff W ^ .. W"는 "diff -RM ^ .. M"과 유사합니다.

이러한 병합의 "복귀"는 다음을 사용하여 수행 할 수 있습니다.

$ git revert -m 1 M 사이드 브랜치 개발자가 실수를 고친 후 역사는 다음과 같습니다.

---o---o---o---M---x---x---W---x
              /
      ---A---B-------------------C---D

여기서 C와 D는 A와 B에서 깨진 것을 고치기위한 것이며, W 이후에 메인 라인에 다른 변화가있을 수 있습니다.

업데이트 된 사이드 브랜치를 병합하면 (끝 부분에 D가 있음) A 또는 B의 변경 사항은 W에 의해 되돌려 졌기 때문에 결과에 나타나지 않습니다. 이것이 Alan이 본 것입니다.

Linus는 상황을 설명합니다.

정규 커밋을 되 돌리면 해당 커밋이 수행 한 작업을 효과적으로 취소 할 수 있으며 매우 간단합니다. 그러나 병합 커밋을 되 돌리면 커밋이 변경 한 데이터 도 취소 되지만 병합이 수행 한 기록에 미치는 영향에는 전혀 영향을 미치지 않습니다 . 따라서 병합은 여전히 ​​존재하며 여전히 두 분기를 결합한 것으로 간주되며 향후 병합에서는 해당 병합이 마지막 공유 상태로 간주되며 병합을 되 돌린 되돌리기는 전혀 영향을 미치지 않습니다. 는 "되돌리기"그래서 데이터 변경 사항을 실행 취소,하지만 매우이다 하지저장소 실행 기록에 대한 커밋의 영향을 취소하지 않는다는 점에서 "실행 취소" "revert"를 "undo"로 생각하면 항상이 부분을 놓치게됩니다. 예, 데이터를 취소하지만 기록은 취소하지 않습니다. 이러한 상황에서는 먼저 이전 되돌리기를 되돌리려 고합니다. 그러면 기록이 다음과 같이 나타납니다.

---o---o---o---M---x---x---W---x---Y
              /
      ---A---B-------------------C---D

여기서 Y는 W의 복귀입니다. 이러한 "복귀의 복귀"는 다음과 같이 수행 할 수 있습니다.

$ git revert W 이 히스토리 (W와 W..Y가 변경된 것을 무시 함)는 히스토리에 W 또는 Y가 전혀없는 것과 같습니다.

---o---o---o---M---x---x-------x----
              /
      ---A---B-------------------C---D

사이드 브랜치를 다시 병합하면 이전 되돌리기 및 되돌리기의 복귀로 인해 충돌이 발생하지 않습니다.

---o---o---o---M---x---x-------x-------*
              /                       /
      ---A---B-------------------C---D

물론 C와 D의 변경 사항은 여전히 ​​x 중 하나와 수행 한 내용과 충돌 할 수 있지만 이는 단지 정상적인 병합 충돌입니다.


-2

Ryan이 언급했듯이 git revert도로에서 병합이 어려워 질 git revert수 있으므로 원하는 것이 아닐 수도 있습니다. git reset --hard <commit-hash-prior-to-merge>여기서 명령을 사용하는 것이 더 유용 하다는 것을 알았 습니다.

하드 리셋 부분을 완료 한 후에는 다음 원격 지점, 즉,에 밀어 강제 할 수 있습니다 git push -f <remote-name> <remote-branch-name>, <remote-name>종종 이름 origin. 이 시점에서 원하는 경우 다시 병합 할 수 있습니다.


4
당신이 레포를 사용하는 유일한 사람이 아니며, 당신이하고있는 일을 정확히 알고 있지 않다면 강제 푸쉬와 관련된 것은 나쁜 생각입니다. git revert를 사용하여 되돌리기 한 다음 git revert를 사용하여 되돌리기를 되 돌리는 것이 훨씬 더 안전한 대안입니다.
oyvind
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.