로컬에서 작업을 하다가 pull을 할 때 conflict가 발생한다.
원격 저장소의 변경사항과 로컬 저장소의 변경사항 사이에 누구를 우선적으로 반영할지 판단하기 어려워서 발생한 것 같다.
conflict를 해결해보자.
1. conflict 발생
늘 하던 대로 pull 했더니 다음과 같이 문제가 생겼다.
❯ git pull origin mysql
https://github.com/ramen4598/Study_nodeJS URL에서
* branch mysql -> FETCH_HEAD
힌트: You have divergent branches and need to specify how to reconcile them.
힌트: You can do so by running one of the following commands sometime before
힌트: your next pull:
힌트:
힌트: git config pull.rebase false # merge
힌트: git config pull.rebase true # rebase
힌트: git config pull.ff only # fast-forward only
힌트:
힌트: You can replace "git config" with "git config --global" to set a default
힌트: preference for all repositories. You can also pass --rebase, --no-rebase,
힌트: or --ff-only on the command line to override the configured default per
힌트: invocation.
fatal: Need to specify how to reconcile divergent branches.
Code language: PHP (php)


만약 bugfix를 위해서 새로운 branch를 만들어서 작업했다고 가정하자.
이제 작업을 마치고 master branch에 반영하려고 한다.
merge, rebase, fast-forward가 뭐 하는 건지 이해해 보자.
merge:fast-forward merge와no fast-forward merge로 나뉜다.

no fast-forward merge: : 충돌을 어떻게든 해결하고 두 branch를 통합해서 새로운 master branch commit을 생성한다.

rebase: bugfix branch의 이력이 master branch를 앞선다.

fast-forward:rebase만 하면 아래 그림에서와 같이, master의 위치는 그대로 유지된다. master branch의 위치를 변경하기 위해서는 master branch에서 bugfix branch를fast-foward(빨리감기) 병합하면 된다. 통합할 branch 즉 bugfix branch가 이미 HEAD(가장 앞에)에 있을 때 사용한다.

→ merge는 ff와 no-ff 방식이 존재하고 rebase는 ff할 필요가 있다.
실제로 fetch와 merge를 활용해서 conflict를 해결하는 방법을 배워보자.
이건 꼼지락거리다가 vscode에서 찾은 내 working tree다.


요기 누르면 된다.
출처 : https://backlog.com/git-tutorial/kr/stepup/stepup1_4.html
2. merge
기본적으로 충돌이 일어난 부분은 이렇게 일일이 확인해서 수정해 주어야 합니다.
일단 master, issue2, issue3 branch가 존재한다 가정한다.
가. fast-forward merge
issue2 branch는 master branch에서 myfile.txt라는 파일에 내용을 추가했다.
$ git checkout master
Switched to branch 'master'
$ git merge issue2
Updating b2b23c4..8f7aa27
Fast-forward ---------------------------> 여기!
myfile.txt | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
Code language: JavaScript (javascript)

나. no-ff merge
issue2를 병합하면서 master branch는 issue3를 생성한 이후에 변화가 생겼다.
이제 issue3를 병합하려고 한다면 conflict가 발생한다.
누구의 변화를 적용해서 하나의 master를 만들지 고민해야 한다.
$git merge issue3
Auto-merging myfile.txt
CONFLICT (content): Merge conflict in myfile.txt
Automatic merge failed; fix conflicts and then commit the result.
Code language: PHP (php)
충돌 부분을 모두 수정하고 다시 커밋한다.
# On branch master
$ git add myfile.txt
$ git commit -m "issue3 브랜치 병합"
nothing to commit (working directory clean)
Code language: PHP (php)
git merge --abort: merge 자체를 취소하고 싶으면 사용

병합되면서 master branch에 새로운 commit을 생성했다.
3. rebase
상황은 아직 issue3가 병합되기 전을 가정한다.

$ git checkout issue3
Switched to branch 'issue3'
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: pull 설명을 추가
Using index info to reconstruct a base tree...
<stdin>:13: new blank line at EOF.
+
warning: 1 line adds whitespace errors.
Falling back to patching base and 3-way merge...
Auto-merging myfile.txt
CONFLICT (content): Merge conflict in myfile.txt
Failed to merge in the changes.
Patch failed at 0001 pull 설명을 추가
When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To check out the original branch and stop rebasing run "git rebase --abort".
Code language: JavaScript (javascript)
우리가 issue3를 merge할 때는 conflict를 해결하고 새로 commit했었다.
하지만 rebase의 경우 충돌 부분을 수정한 후 commit 이 아니라 rebase 명령에 --continue 옵션을 지정하여 실행해야 한다.
$ git add myfile.txt
$ git rebase --continue
Code language: JavaScript (javascript)
--abort: rebase 자체를 취소하고 싶으면 사용

아직 master branch는 저 뒤에 있다.
이제 master로 전환해서 issue3의 변경 사항을 모두 ff-merge한다.
$ git checkout master
Switched to branch 'master'
$ git merge issue3
Updating 8f7aa27..96a0ff0
Fast-forward
myfile.txt | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
Code language: JavaScript (javascript)

4. fetch, diff를 해보자.
사실 앞에서는 merge와 rebase를 수행하는 방법에 대해서 알아보았다.
어떻게 충돌을 해결하면 좋을진 아직 모르겠다.
충돌이 발생하는 부분은 모두 일일이 확인해서 수정해야 한다.
일단 어디에서 왜 충돌이 발생하는지 알아낸다.
가. fetch
원격 저장소에서 코드를 내려받는다.
단, 내려받은 후 현재 브랜치와 병합하진 않는다.
git fetch origin <branch>
Code language: HTML, XML (xml)
이때 원격 저장소에서 커밋된 코드는 임시 branch (일명 FETCH_HEAD) 형태로 로컬에 존재한다.
git checkout FETCH_HEAD
FETCH_HEAD의 이름으로 체크아웃할 수도 있다.
나. diff
git diff <branch>
Code language: HTML, XML (xml)
로컬 저장소의 브랜치와 원격 저장소 브랜치 사이의 어떤 차이점을 확인한다.
git diff <branch1> <branch2>
Code language: HTML, XML (xml)
혹은 서로 다른 branch를 비교하고 싶다면 이렇게 사용한다.
다. fetch → diff → merge의 삼단콤보
git fetch origin <branch>
Code language: HTML, XML (xml)
git diff FETCH_HEAD <branch>
Code language: HTML, XML (xml)
원격 저장소와 로컬 저장소의 차이를 확인할 수 있다.

git checkout <branch>
git merge FETCH_HEAD
Code language: HTML, XML (xml)
나중에 push 할 때를 생각해서 FETCH_HEAD에서 작업하면 안 된다!
❯ git merge FETCH_HEAD
자동 병합: gitconflict.txt
충돌 (추가/추가): gitconflict.txt에 병합 충돌
자동 병합이 실패했습니다. 충돌을 바로잡고 결과물을 커밋하십시오.
gitconflict.txt에서 충돌이 발생했다.
vim gitconflict.txt
Code language: CSS (css)
그냥 충돌이 발생한 파일을 vim으로 열었는데 바로 충돌 부분을 확인할 수 있다.

<<<<<< HEAD~ : 지금 checkout하고 있는FETCH_HEAD의 코드========: 기준점- ~
>>>>>>>: merge할FETCH_HEADbranch의 코드
수정하기 위해서는 보이는 기호를 포함해서 필요 없는 모든 것은 지우고, 필요한 것은 추가해서 저장하면 된다.
수정이 완료했으면 새로 commit한다.
# 주의 mysql branch에서 수행
$ git add .
$ git commit -m "브랜치 병합"
$ git push origin mysql
Code language: PHP (php)

5. pull vs merge
결국 git pull = git fetch + git merge다.
가능하다면 fetch와 merge를 활용해서 차근차근 conflict를 해결하는 방법을 사용하자.
출처 : https://www.atlassian.com/ko/git/tutorials/syncing/git-fetch
