Merge 충돌
- Git에서 Merge를 수행할 때 충돌이 발생할 수 있습니다.
- 먼저, Merge하기 전에 워킹 디렉토리를 정리하는 것이 좋습니다. 작업 중이던 파일을 임시로 저장하거나 Stash를 사용하여 변경사항을 백업합니다.
-
function hello() { console.log('hello world'); } hello();
- hello wolrd를 출력하는 javascript 파일이 있습니다.
- mundo 브랜치를 생성 후 hello mundo로 변경 후 커밋합니다.
-
// mundo 브랜치 function hello() { console.log('hello mundo'); } hello();
- master 브랜치에서 hello master로 변경 후 커밋합니다.
-
// master 브랜치 function hello() { console.log('hello master'); } hello();
- master 브랜치에서 mundo 브랜치를 merge하면 충돌이 발생합니다.
-
$git merge mundo Auto-merging hello.js CONFLICT (content): Merge conflict in hello.js Automatic merge failed; fix conflicts and then commit the result.
Merge 되돌리기
- merge 후 자신의 상태를 체크합니다.
-
$git status --sb ## master M hello.js
- merge를 중단합니다.
-
$git merge --abort
- 중단 후 자신의 상태를 체크합니다.
-
$git status --sb ## master
- 만약 Merge 이전에 워킹 디렉토리에 Stash하지 않았거나 커밋하지 않은 변경사항이 있는 경우에는 --abort 명령어를 수행할 수 없습니다.
-
fatal: There is no merge to abort (MERGE_HEAD missing).
- 이럴 경우에는 reset으로 되돌려야합니다.
-
$git reset --hard HEAD
- 변경사항은 저장되지 않지만 따로 임시 저장하여 작업해야합니다.
Merge 공백 무시하기
-
$ git merge -Xignore-space-change whitespace mundo
- 이 명령은 모든 공백 변경을 무시하고 Merge를 시도합니다.
- 이 옵션은 팀원 중 누군가가 스페이스를 탭으로 바꾸거나 탭을 스페이스로 바꾼 경우에 유용하게 사용될 수 있습니다.
수동 Merge
- 각 버전의 파일 가져오기
- stages 숫자를 사용하여 각 버전의 파일을 가져옵니다.
-
$git show :1:hello.js > hello.common.js $git show :2:hello.js > hello.ours.js $git show :3:hello.js > hello.theirs.js
- Plumbing 명령을 사용하여 각 버전의 파일을 가져올 수 있습니다.
-
$ git ls-files -u 100755 ac51efdc3df4f4fd328d1a02ad05331d8e2c9111 1 hello.js 100755 36c06c8752c78d2aff89571132f3bf7841a7b5c3 2 hello.js 100755 e85207e04dfdd5eb0a1e9febbc67fd837c44a1cd 3 hello.js $ git show ac51efdc3df4f4fd328d1a02ad05331d8e2c9111 > hello.common.js $ git show 36c06c8752c78d2aff89571132f3bf7841a7b5c3 > hello.ours.js $ git show e85207e04dfdd5eb0a1e9febbc67fd837c44a1cd > hello.theirs.js
- Merge 수행
- 이제 세 파일을 가지고 수동으로 충돌을 해결하고 Merge를 수행합니다.
-
$ git merge-file -p hello.ours.js hello.common.js hello.theirs.js > hello.js
- 변경 사항 확인
- Merge를 완료한 파일을 양쪽 부모와 비교하여 변경 사항을 확인할 수 있습니다.
-
$ git diff --ours $ git diff --theirs -b $ git diff --base -b
- 불필요한 파일 제거
-
$ git clean -f
-
충돌 파일 Checkout
- 충돌이 일어난 후 checkout을 통해 해결을 해봅니다.
-
$ git checkout --conflict=diff hello.js Recreated 1 merge conflict
- 위 명령을 실행하면 충돌이 발생한 파일 hello.js의 충돌 부분을 아래와 같이 표시하여 보여줍니다.
-
// greeting function hello() { <<<<<<< ours console.log('hello world2'); ||||||| base console.log('hello world'); ======= console.log('hello mundo'); >>>>>>> theirs } hello();
- 이때 ours는 현재 브랜치 내용 base는 공통 조상의 내용 theirs는 Merge하려는 브랜치의 내용입니다.
- hello.js에서 충돌 해결 후 커밋하면 됩니다.
Merge 로그
- Triple Dot 문법을 사용하여 Merge에 사용된 양 브랜치의 모든 커밋 목록을 얻습니다. 각 커밋은 왼쪽 또는 오른쪽 브랜치에 속하는지에 따라 < 또는 > 기호로 표시됩니다.
-
$git log --oneline --left-right HEAD...MERGE_HEAD < f1270f7 update README < 9af9d3b add a README < 694971d update phrase to hola world > e3eb223 add more tests > 7cff591 add testing script > c3ffff1 changed text to hello mundo
- --merge 옵션을 사용하여 충돌이 발생한 파일이 속한 커밋만 보여줍니다.
-
$git log --oneline --left-right --merge < 694971d update phrase to hola world > c3ffff1 changed text to hello mundo
- -p 옵션을 추가하여 충돌이 발생한 파일의 변경사항을 보여줍니다.
-
$git log --oneline --left-right --merge -p < 0cec34d (HEAD -> master) 2 diff --git a/hello.js b/hello.js index 6fda48f..4351403 100644 --- a/hello.js +++ b/hello.js @@ -1,6 +1,6 @@ // greeting function hello() { - console.log('hello world'); + console.log('hello world2'); } hello(); \ No newline at end of file < d52d4a2 greeting diff --git a/hello.js b/hello.js index f5c4135..6fda48f 100644 --- a/hello.js +++ b/hello.js @@ -1,3 +1,4 @@ +// greeting function hello() { console.log('hello world'); } > 66a9861 hello mundo diff --git a/hello.js b/hello.js index f5c4135..fce9e06 100644 --- a/hello.js +++ b/hello.js @@ -1,5 +1,5 @@ function hello() { - console.log('hello world'); + console.log('hello mundo'); } hello(); \ No newline at end of file
Combined Diff 충돌 해결
- 충돌이 발생한 부분은 `<<<<<<<`와 `>>>>>>>`로 표시됩니다. 이는 해당 코드가 어느 브랜치에서 추가되었는지를 표시합니다.
-
$ git diff diff --cc hello.rb index 0399cd5,59727f0..0000000 --- a/hello.rb +++ b/hello.rb @@@ -1,7 -1,7 +1,11 @@@ #! /usr/bin/env ruby def hello ++<<<<<<< HEAD + puts 'hola world' ++======= + puts 'hello mundo' ++>>>>>>> mundo end hello()
- 충돌이 발생한 부분을 수정하여 원하는 결과물을 얻을 수 있도록 합니다. 이때 충돌 마커를 제거하고 양쪽 브랜치에서 필요한 부분을 조합합니다.
- 충돌을 해결한 후에는 수정한 내용을 스테이징 영역에 추가하고 커밋하여 변경사항을 저장합니다.
Merge 되돌리기
- Refs 수정
- 로컬 저장소에서만 Merge를 잘못한 경우, 브랜치를 원하는 커밋으로 옮기는 것이 가장 빠르고 쉬운 방법입니다.
-
$git reset --hard HEAD~
- 커밋 되돌리기
- 모든 변경 사항을 취소하는 새로운 커밋을 만들어서 실수를 되돌릴 수 있습니다.
-
$git revert -m 1 HEAD
다른 방식의 Merge
- 기본적으로 Merge를 수행할 때 Git은 충돌이 발생하면 사용자에게 충돌이 발생했음을 알려줍니다. 그러나 충돌을 직접 해결하는 대신 -Xours 또는 -Xtheirs와 같은 옵션을 추가하여 어느 쪽을 선택할지 미리 지정할 수 있습니다.
-
$git merge -Xours mundo
- Merge를 할 때 다른 브랜치의 변경 사항을 무시하고 현재 브랜치의 코드를 그대로 사용합니다.
-
$git merge -s ours mundo
- 서브트리 Merge는 하나의 프로젝트를 다른 프로젝트의 하위 디렉토리로 Merge하는 것을 말합니다.
-
$git read-tree --prefix=rack/ -u rack_branch
'GIT > Git 도구' 카테고리의 다른 글
[GIT] Git Reset과 Checkout 쉽게 이해하기 (1) | 2024.03.18 |
---|---|
[GIT] 히스토리 편집하기 (0) | 2024.03.18 |
[GIT] 히스토리 검색하기 (0) | 2024.03.18 |
[GIT] 작업에 서명하기 (0) | 2024.03.18 |
[GIT] Stashing과 Cleaning (0) | 2024.03.11 |