병합취소
병합을 시도했거나 완료한 뒤에 병합을 취소하고 싶다면?
병합을 취소하는 시점은 두 가지가 있다. 병합이 완료된 경우, 그리고 병합하려다가 충돌이 발생하여 잠시 중단된 경우이다.
병합중 충돌이 발생하여 취소하는 경우
각각의 두 브랜치(feature/1과 master)에서 stuff 파일을 다른 내용으로 수정했다고 가정하자.
그리고 feature/1 브랜치를 master 브랜치에 병합하는 과정에서 충돌이 발생했다고 가정하자.
$ git merge feature/1
Auto-merging stuff
CONFLICT (content): Merge conflict in stuff
Automatic merge failed; fix conflicts and then commit the result.
$ git branch
feature/1
* master
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: stuff
no changes added to commit (use "git add" and/or "git commit -a")
$ git ls-files --unmerged
100644 ed71c828ffe5de50062e95f380c1e573b43d8284 1 stuff
100644 d2c7593de4a4d5a3883444c1be9886f1eaa9db66 2 stuff
100644 d3ab27bf9681e93d0adae8816bf9e690b62f0b03 3 stuff
먼저, stuff 파일에서 충돌이 발생한 것을 병합 명령 이후 바로 알 수 있고, HEAD는 master 브랜치에 있다. git status
명령으로 충돌 상황을 확인할 수 있고, 또 git ls-files --unmerged
명령으로 현재 인덱스에 stuff 파일의 blob 세개가 얽혀 있음을 알 수 있다. 그리고 충돌이 발생하면 작업 디렉토리가 반드시 변하게 된다.
그러면 충돌 상황에서 병합을 취소하려면 어떻게 해야 할까?
생각해보면 변한 것은 병합 대상인 master 브랜치 밖에 없다. 그중에서도 master 브랜치의 인덱스와 작업 디렉토리가 변한 것이다. 그것들을 되돌려주면 되는 것이다.
$ git reset --hard HEAD
HEAD is now at f473009 edit stuff 'Here is master branch.'
$ git status
On branch master
nothing to commit, working directory clean
$ git ls-files --unmerged
git reset 명령에서 인덱스와 작업 디렉토리를 모두 되돌려주는 방법은 --hard
플래그를 사용하는 것이다. 그리고 HEAD를 기점으로 되돌려주면 된다.
병합이후에 병합 취소
$ git log
* 8ce7700 | (HEAD, master) 2015-03-26 10:48:55 +0900 (4 seconds ago)
|\ Merge branch 'feature/1' - Choi Leejun
| * 176a7cd | (feature/1) 2015-03-26 10:08:55 +0900 (40 minutes ago)
| | edit stuff 'Here is feature/1 branch' - Choi Leejun
* | f473009 | 2015-03-26 10:09:38 +0900 (39 minutes ago)
|/ edit stuff 'Here is master branch.' - Choi Leejun
* 8c302ea | 2015-03-25 15:20:59 +0900 (19 hours ago)
|\
병합하고 충돌을 해결하여 병합을 완료했다고 가정하자. 아마도 위와 비슷한 상태일 것이다. 만일 병합을 취소하고 현재 HEAD를 f473009 커밋으로 되돌리면 된다.
Git은 이러한 상황에 대비하여 ORIG_HEAD라는 참조 이름을 제공한다. ORIG_HEAD에는 병합이나 커밋이 진행될 때 이전 HEAD를 저장해두는 이름이다.
$ git show ORIG_HEAD
commit f473009a7d4900c264bf88d0356f64dda819a3f2
Author: Choi Leejun <[email protected]>
Date: Thu Mar 26 10:09:38 2015 +0900
edit stuff 'Here is master branch.'
diff --git a/stuff b/stuff
index ed71c82..d2c7593 100644
--- a/stuff
+++ b/stuff
@@ -2,3 +2,5 @@ This is a stuff.
Where is the second stuff.
Okay! The second stuff is here.
Hmm. Jump to next.
+
+Here is master branch.
ORIG_HEAD를 들여다보면 실제로 병합 이전의 커밋을 참조하고 있음을 알 수 있다.
$ git reset --hard ORIG_HEAD
HEAD is now at f473009 edit stuff 'Here is master branch.'
$ git log
* f473009 | (HEAD, master) 2015-03-26 10:09:38 +0900 (49 minutes ago)
| edit stuff 'Here is master branch.' - Choi Leejun
| * 176a7cd | (feature/1) 2015-03-26 10:08:55 +0900 (50 minutes ago)
|/ edit stuff 'Here is feature/1 branch' - Choi Leejun
* 8c302ea | 2015-03-25 15:20:59 +0900 (20 hours ago)
|\ Merge branch 'feature/1' - Choi Leejun
병합이 취소된 것을 알 수 있다.