#git merge 커밋 리버트(revert)

2 minute read

merge 한 커밋(commit)이 잘못됐다. push 해버려서 amend는 불가능. amend 가능해도 못하겠네. 꽤 복잡한 문제라서 revert를 하고 찬찬히 봐야겠다.

$ git revert 6babfa4
error: Commit 6babfa43e22010e7504a3bd658faa8e5e21f9f8e is a merge but no -m option was given.
fatal: revert failed

revert 하는 것 자체도 두근거리는데, 안 된다니깐 심장이 빨리 뛴다.

-m parent-number

\­\­mainline parent-number

Usually you cannot revert a merge because you do not know which side of the merge should be considered the mainline. This option specifies the parent number (starting from 1) of the mainline and allows revert to reverse the change relative to the specified parent.

생각해보면 당연하다. revert 대상은 커밋 여러 개가 만나는 커밋이다. revert 하려면? 만나기 전 어떤 커밋으로 돌아갈지 결정해야 한다. 즉, A와 B 커밋을 merge 해 C 커밋을 만들었다면 A 혹은 B 커밋으로 revert해야 한다.

$ git log 6babfa4 -n 1
commit 6babfa43e22010e7504a3bd658faa8e5e21f9f8e
Merge: 15a1193 fc3a989
Author: ohyecloudy <ohyecloudy@gmail.com>
Date:   Mon Jul 2 09:37:19 2018 +0900

    Merge branch 'dev'

부모 번호는 로그를 보면 알 수 있다. 위 예제에서 1번은 15a1193, 2번은 fc3a989.

$ git log --oneline --graph
*   6babfa4 Merge branch 'dev'
|\
| * fc3a989 hello git
* | 15a1193 hello world
|/
* a0653bc hello

간단한 예제를 만들었다. hello 문자열은 hello git, hello world로 수정해 충돌이 나게 했다. hello whatever로 resolve 해서 머지 커밋을 만들었다.

$ git revert 6babfa4 -m 1
$ git log --oneline --graph
* 5c8e06f Revert "Merge branch 'dev'"
*   6babfa4 Merge branch 'dev'
|\
| * fc3a989 hello git
* | 15a1193 hello world
|/
* a0653bc hello

$ git diff 6babfa4 5c8e06f
diff --git a/test b/test
index 3371098..3b18e51 100644
--- a/test
+++ b/test
@@ -1 +1 @@
-hello whatever
+hello world

-m 1 옵션을 사용해서 15a1193 커밋으로 revert 했다.

$ git revert 6babfa4 -m 2
$ git log --oneline --graph
* cf2053f Revert "Merge branch 'dev'"
*   6babfa4 Merge branch 'dev'
|\
| * fc3a989 hello git
* | 15a1193 hello world
|/
* a0653bc hello

$ git diff 6babfa4 cf2053f
diff --git a/test b/test
index 3371098..8d0e412 100644
--- a/test
+++ b/test
@@ -1 +1 @@
-hello whatever
+hello git

-m 2 옵션을 사용하면? fc3a989 커밋으로 revert한다.

merging보다 rebasing을 선호한다. 히스토리가 갈래 없이 직선(linear history)이라서 선후 파악이 쉽기 때문이다. merging에도 장점이 있다. 바로 revert. rebasing으로 한다면 커밋 여러 개를 revert해야 한다. 만약 merging이라면? merge 커밋만 revert를 하면 된다. cherry-pick 할 때도 마찬가지다.

적당한 선에서 타협해도 된다. rebasing 하지만 merge 커밋을 만드는 방법도 있다. 보기 좋은 히스토리도 유지하고 기능 구현 브랜치가 master 브랜치에 merge 되는 시점도 파악할 수 있다. revert도 쉽다. gitlab에서 이런 히스토리를 semi-linear history라고 부른다.