깃의 충돌(confilct)
깃을 사용하다 보면 많은 사람들이 끊임없이 브랜치를 만들고 병합하고 삭제하기를 반복하면서 개발을 해나간다. 원격 저장소를 사용 한다면 다른 사람이 작업한 내용과 병합하는 작업을 하다보면 오만가지 형태의 충돌이 발생하게 된다.
// 기존 master 브랜치의 f1.txt파일
function(){
return 'common';
}
- 하나의 파일(f1.txt)을 가지고 있는 브랜치(master)에서 새로운 브랜치(exp)를 생성하여 파일의 내용을 수정한 뒤 master 브랜치에서 exp을 병합해 보자
$ git checkout -b exp
// exp 브랜치의 f1.txt파일
function(){
return 'exp';
}
$ git checkout master
// master 브랜치의 f1.txt파일
function(){
return 'master';
}
- 위와 같이 같은 파일의 내용이 다른 브랜치를 병합 하고자 한다면 충돌이 일어나게 된다.
$ git merge exp
Auto-merging f1.txt
CONFLICT (content): Merge conflict in f1.txt
Automatic merge failed; fix conflicts and then commit the result.
충돌이 발생 했을 때 깃은 내부적으로 어떠한 변화를 겪게 될까?
- 충돌이 발생하여 index의 stage의 값이 변경 된 것을 확인할 수 있다. (기존에 0이었던)
$ git ls-files --stage
100644 e541a4178e6603b24d22ef570ca1efa21cedc587 1 f1.txt
100644 4fdcca5027e1aea348b8c69d4261466a7d197f5e 2 f1.txt
100644 2093f38880ed7601e48e9da2da4eb938f62b784b 3 f1.txt\
[<tag> ] <mode> <object> <stage> <file>
// mode 타입과 권한을 의미
// 100644: 일반 파일
// 100755: 실행 가능한 일반 파일
// object : SHA-1 값
// stage : 이 값은 보통 0 이며, 컨플릭트가 발생했을 경우 각 스테이지 넘버를 표현한다.
// file : path name
- master와 exp 브랜치가 공통으로 가지고 있던 f1.txt의 내용
// 100644 e541a4178e6603b24d22ef570ca1efa21cedc587 1 f1.txt
function(){
return 'common';
}
- 현재 checkout해서 merge를 하고 있는 브랜치(master)의 f1.txt의 내용
// 100644 4fdcca5027e1aea348b8c69d4261466a7d197f5e 2 f1.txt
function(){
return 'master';
}
- 병합이 될 대상 브랜치(exp)의 f1.txt내용
// 100644 2093f38880ed7601e48e9da2da4eb938f62b784b 3 f1.txt
function(){
return 'exp';
}
index의 브랜치의 공통이 되는 파일과 각자의 파일, 세가지 정보를 통해 깃은 자동으로 병합 작업(3way-merge)을 시도한다.
- MERGE_HEAD : 병합이 될 대상 브랜치가 가르키는 최신 커밋의 커밋 아이디를 가진다.
- MERGE_MSG : 충돌시 커밋 메시지에 사용된다.
- ORIG_HEAD :병합은 위험한 작업이기 때문에 현재 브랜치가 가르키는 최신 커밋을 기록한다.
- 충돌이 일어난 파일에 대한 내용을 가지는 객체가 생성되고 f1.txt파일의 내용이 변경된다.
$ cat f1.txt
function(){
<<<<<<< HEAD
return 'master';
=======
return 'exp';
>>>>>>> exp
}
외부 도구를 사용한 충돌 처리
충돌을 처리할 때 직접 vim 에디터를 사용하여 구분선 지우고, <<,>>를 지우는 등 직접 충돌을 처리할 수 도 있지만 외부도구를 사용해서 merge의 충돌을 제어할 수 있다.
- 그 중 3-way merge 알고리즘을 사용하는 kdiff를 사용한다.
// kdiff3 설정
$ git config --global merge.tool kdiff3
// 머지 명령을 실행할 때 해당 툴이 사용되게 된다.
- mergetool 명령어를 통해 kdiff3 GUI tool을 실행시켜 병합 과정에서의 충돌을 빠르게 처리할 수 있다.
// kdiff3 실행
$ git mergetool
Merging:
f1.txt
Normal merge conflict for 'f1.txt':
{local}: modified file
{remote}: modified file
- Ouput부분의 <Merge Conflict>에 커서를 옮긴 뒤 [A, B, C] 버튼을 누르면 충돌난 부분의 내용이 변경된다. 이후 직접 수정도 가능하다.
- 수정이 끝나고 파일을 저장한 뒤 프로그램을 종료하면 자동으로 mergetool 명령어가 자동으로 add명령이 실행된다.
- 변경한 내용대로 워크 스페이스의 파일의 내용이 변경됨을 확인할 수 있다.
$ vim f1.txt
function(){
return 'master', exp';
}
- add명령이 실행되어 index의 내용이 변경됨을 확인할 수 있다.
$ git ls-files --stage
100644 0fe0de5f509afc245b49d60b8cd04d3ab363119c 0 f1.txt
$ git cat-file -p 0fe0de5f509afc245b49d60b8cd04d3ab363119c
function(){
return 'master', exp';
}
- git commit명령어를 입력하면 어떤 부분에서 충돌이 발생하는지와 병합되었음 알려주고 브랜치의 병합이 완료된다.
$ git commit
Merge branch 'exp'
# Conflicts:
# f1.txt
#
# It looks like you may be committing a merge.
# If this is not correct, please run
# git update-ref -d MERGE_HEAD
# and try again.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# All conflicts fixed but you are still merging.
#
# Changes to be committed:
# modified: f1.txt
#
* commit 49b10927170121937a860d9a29e7cd7f9541f62d (HEAD -> master)
|\ Merge: 6b5944c 85e17be
| | Author :
| | Date: Sun Apr 7 19:19:25 2024 +0900
| |
| | Merge branch 'exp'
| |
'Git' 카테고리의 다른 글
[Git] 내가 보려고 만든 Git-flow기반 브랜치 전략 및 컨벤션 (6) | 2024.10.14 |
---|---|
[Git] Git-flow (0) | 2024.06.17 |
[Git] 깃(Git)의 원리(3, Branch 정리)와 브랜치 병합(Merge / rebase) (0) | 2024.06.10 |
[Git] 커밋 취소/되돌리기/덮어쓰기(reset / revert / amend) (0) | 2024.06.04 |
[Git] 태그(tag)의 기초와 사용법 (0) | 2024.06.02 |