[Git] 7.3. CLI로 3-way 병합하기

업데이트:

카테고리:

태그: , , ,

긴급한 버그 처리 시나리오

갑작스레 버그를 발견한 상황을 가정. 하나 이상의 브랜치로 다른 기능을 개선하고 있는 경우 버그 수정은 다음과 같이 이루어진다.

1. (옵션) 오류가 없는 버전(주로 Tag가 있는 커밋)으로 롤백
2. [master] 브랜치로부터 [hotfix] 브랜치 생성
3. 빠르게 소스 코드 수정 / 테스트 완료
4. [master] 브랜치로 병합 (Fast-forward) 및 배포
5. 개발 중인 브랜치에도 병합 (충돌 발생 가능성이 높음)


버그가 발생한 경우, 원래 작업 중인 브랜치도 [master] 브랜치로부터 시작했기 때문에 같은 버그를 가지고 있다. 때문에 [hotfix] 브랜치의 내용은 [master] 브랜치와 개발 브랜치 모두에 병합되어야 한다. 보통 [master] 브랜치의 병합은 빨리 감기이기 때문에 쉽게 되는 반면 개발 중인 브랜치의 병합은 병합 커밋이 생성되고, 충돌이 일어날 가능성이 높다.


위의 상황을 실습해보자.

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git branch # 브랜치의 종류와 현재 체크아웃된 브랜치 확인

- master

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git checkout -b feature1 # [feature1] 브랜치 생성 및 체크아웃
Switched to a new branch 'feature1'

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1)
$ echo "기능1 추가" >> file1.txt # file1.txt 내용 추가

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1)
$ git add file1.txt # 스테이징
warning: LF will be replaced by CRLF in file1.txt.
The file will have its original line endings in your working directory

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1)
$ git commit -m "새로운 기능 1 추가" # 커밋
[feature1 c201e9e] 새로운 기능 1 추가
1 file changed, 1 insertion(+)

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1)
$ git log --oneline --graph --all -n2 # 로그 확인

- c201e9e (HEAD -> feature1) 새로운 기능 1 추가
- 9e5110b (tag: v0.1, origin/master, master) mybranch1 두 번째 커밋

위 코드의 실행결과이다.

image


이 상황에서 버그가 발생했다?

버그를 고치기 위해 [master] 브랜치로부터 [hotfix] 브랜치를 생성해 버그를 고쳐 커밋한다. 그리고 [hotfix] 브랜치를 [master] 브랜치에 merge한다. ([master] 브랜치의 최신 커밋 기반으로 [hotfix] 브랜치 작업을 했기 때문에 빨리 감기 병합이 가능하다.)


tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1)
$ git checkout -b hotfix master # master 브랜치로부터 hotfix 브랜치 생성, 체크아웃
Switched to a new branch 'hotfix'

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (hotfix)
$ git log --oneline --all -n2 # 2개의 커밋 로그만 보기
c201e9e (feature1) 새로운 기능 1 추가
9e5110b (HEAD -> hotfix, tag: v0.1, origin/master, master) mybranch1 두 번째 커
밋

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (hotfix)
$ echo "some hot fix" >> file1.txt # file1.txt 파일에 내용 추가

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (hotfix)
$ git add file1.txt
warning: LF will be replaced by CRLF in file1.txt.
The file will have its original line endings in your working directory

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (hotfix)
$ git commit -m "hotfix 실습"
[hotfix bc26b63] hotfix 실습
1 file changed, 1 insertion(+)

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (hotfix)
$ git log --oneline -n1
bc26b63 (HEAD -> hotfix) hotfix 실습

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (hotfix)
$ git checkout master # master 브랜치로 체크아웃
Switched to branch 'master'
Your branch is up to date with 'origin/master'.

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git merge hotfix # hotfix 브랜치 빨리 감기 병합
Updating 9e5110b..bc26b63
Fast-forward
file1.txt | 1 +
1 file changed, 1 insertion(+)

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 308 bytes | 308.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/Orchemi/hello-git-cli.git
9e5110b..bc26b63 master -> master

위 코드의 실행결과는 다음과 같다.

image

[hotfix] 브랜치에 버그를 수정한 코드를 커밋하고 [master] 브랜치와 병합하여 버그 수정된 코드를 반영하였다. 하지만 버그가 존재하는 잘못된 [master] 브랜치를 기반으로 만들어진 [feature1] 브랜치에도 버그를 반영해야 한다. 하지만 이미 [feature1]과 [master] 브랜치는 서로 다른 분기로 진행되어 빨리 감기 병합이 불가능하므로 3-way 병합 을 해야 한다. 따라서 병합 커밋이 생성될 것이다.


일단 3-way 병합을 해보자.

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git branch # 등록된 브랜치와 현재 위치하는 브랜치를 확인
feature1
hotfix

- master

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git checkout feature1 # feature1 브랜치로 체크아웃
Switched to branch 'feature1'

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1)
$ git log --oneline --all -n2 # feature1 브랜치의 log 확인
bc26b63 (origin/master, master, hotfix) hotfix 실습
c201e9e (HEAD -> feature1) 새로운 기능 1 추가

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1)
$ git merge master # master 브랜치와 병합 시도
Auto-merging file1.txt
CONFLICT (content): Merge conflict in file1.txt
Automatic merge failed; fix conflicts and then commit the result.

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1|MERGING)
$ git status # 실패 원인 파악
On branch feature1
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)

Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: file1.txt

no changes added to commit (use "git add" and/or "git commit -a")

위 코드의 실행결과는 다음과 같다.

image

$ git merge master 명령이 충돌로 인해 실패했다. $ git status 명령을 실행하여 충돌 대상 파일을 확인할 수 있으며, 결과 메시지에서처럼 $ git merge --abort 명령을 통해 merge를 취소할 수도 있다.


image

VSC로 충돌이 일어난 파일을 열면 충돌 부분이 다른 색으로 표시되고 위 쪽에는 옅은 색으로 선택 메뉴가 보인다. 첫 번째는 HEAD의 내용만 선택, 두 번째는 master의 내용만 선택, 세 번째는 둘 다 선택, 네 번째는 다른 내용을 확인하는 버튼이다. 이 상황에서는 두 내용 모두가 필요하므로 세 번째인 ‘Accept Both Changes’ 버튼을 클릭하면 모두 반영이 된다.

image

위의 사진처럼 두 내용이 모두 반영된 것을 확인할 수 있다. 추가적으로 Conflict 상황에서 생기는 ««HEAD, ======, »» master 등의 지저분한 내용도 자동으로 지워주어 한결 깔끔하다.


이제 변경 내용을 저장하고 다시 스테이지에 추가 및 커밋하면, 수동 3-way 병합이 완료된다.


tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1|MERGING)
$ cat file1.txt # cat file1.txt 내용 확인
hello git
second
third - my branch
fourth - my branch
기능1 추가
some hot fix

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1|MERGING)
$ git add file1.txt

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1|MERGING)
$ git status
On branch feature1
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)

Changes to be committed:
modified: file1.txt

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1|MERGING)
$ git commit -m "hotfix 실습" # merge commit 생성
[feature1 4665ef6] hotfix 실습

tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1)
$ git log --oneline --all --graph -n4 # 로그 확인

- 4665ef6 (HEAD -> feature1) hotfix 실습
  |\
  | \* bc26b63 (origin/master, master, hotfix) hotfix 실습
- | c201e9e 새로운 기능 1 추가
  |/
- 9e5110b (tag: v0.1) mybranch1 두 번째 커밋

위의 코드를 실행한 결과는 다음과 같다.

image

병합 커밋이기 때문에 커밋 메시지는 편집하지 않아도 됐는데 ‘hotfix 실습’ 이라는 커밋 메시지로 바꾸었다. 커밋 메시지를 편집하지 않으면 ‘Merge branch ‘master’ into feature1’의 병합 커밋 메시지가 자동으로 남는다.


Reference

  • 팀 개발을 위한 Git GitHub 시작하기, 한빛미디어, 정호영,진유림

댓글남기기