Merge
merge의 의미와 충돌
[Git] Merge
앞서, master 브랜치에서 새로운 브랜치를 생성해 보았다. 개별적인 문제를 해결하고자 생성한 브랜치는 결국 기존의 브랜치와 합쳐야 하는데, 이 때 사용하는 것이 merge이다.
예제 진행 과정
아래의 과정을 수행하며 자세한 내용을 알아보자.
- 웹사이트가 있고 뭔가 작업을 진행하고 있다.
- 새로운 이슈를 처리할 새 Branch를 하나 생성한다.
- 새로 만든 Branch에서 작업을 진행한다.
이때 중요한 문제가 생겨서 그것을 해결하는 Hotfix를 먼저 만들어야 한다. 그러면 아래와 같이 할 수 있다.
- 새로운 이슈를 처리하기 이전의 운영(Production) 브랜치로 이동한다.
- Hotfix 브랜치를 새로 하나 생성한다.
- 수정한 Hotfix 테스트를 마치고 운영 브랜치로 Merge 한다.
- 다시 작업하던 브랜치로 옮겨가서 하던 일 진행한다.
새로운 브랜치에서 작업
-
현재 상황
아직까지는 새로운 브랜치 없이 master 브랜치만을 사용한다.
-
이슈 발생 - 브랜치 생성
이 때, 해결이 필요한 이슈가 등장한다. 새로운 브랜치를 생성하여 문제를 해결해보자.
$ git checkout -b iss53 #위의 명령은 아래의 명령 두 개를 합친 것과 같다. $ git branch iss53 $ git checkout iss53
git checkout
의-b
옵션은branch
,checkout
을 동시에 진행한다. 브랜치를 생성하고 HEAD를 해당 브랜치로 이동하는 것이다. -
작업 진행
새로운 브랜치에서 문제를 해결하며 새로 커밋했다. master 브랜치와 iss53브랜치가 가리키는 커밋이 다른 모습이다.
master에서 갈라진 두 개의 브랜치
-
기존의 브랜치로 이동
이 상황에서 급히 해결해야할 문제가 발생한다. iss53과 코드가 섞이는 것을 방지하기 위해, master에서 새로운 브랜치를 생성해야 한다.
브랜치를 이동하려면 아직 커밋하지 않은 파일이 체크아웃할 브랜치와 충돌하는지 확인해야한다. 만약 충돌한다면 체크아웃을 진행할 수 없다.(stashing, cleaning에서 설명)
충돌하지 않게끔 커밋을 진행하고
$ git checkout master
를 통해 마스터 브랜치로 이동한다. -
새로운 브랜치 생성
$ git checkout -b hotfix
명령어를 통해 브랜치의 생성, HEAD의 이동을 한다. 위의 이미지는 hotfix브랜치에서 한 차례 커밋을 진행해, master 브랜치와 분리된 모습이다. -
Merge 진행
hotfix가 끝났으면 master브랜치와 hotfix 브랜치를 합쳐야한다. 합체의 중심이 되는 브랜치인 master로 이동 후, merge를 진행한다.
$ git checkout master $ git merge hotfix Updating *** Fast-forward <파일명> | <수정> * file changed, * insertions(+)
Fast-forward
는 merge하려는 브랜치의 커밋(C4)이 현재 커밋(C2)에 기반했기 때문에 나타난다. 예를 들어 A 브랜치에서 다른 B 브랜치를 Merge 할 때 B 브랜치가 A 브랜치 이후의 커밋을 가리키고 있으면 그저 A 브랜치가 B 브랜치와 동일한 커밋을 가리키도록 이동시킬 뿐이다. hotfix 브랜치가 가리키는 곳을 master 브랜치 또한 가리키게 된다.필요 없어진 hotfix 브랜치는
$ git branch -d hotfix
명령으로 삭제하자.-d
옵션은 삭제를 의미한다. -
기존 작업의 진행 및 merge
이제 남은 브랜치는 master와 iss53이다. iss53 브랜치로 이동 후, 문제를 해결하고 커밋(C5)한 상황에 도달했다. 이 브랜치는 어떻게 병합할까?
$ git checkout master Switched to branch 'master' $ git merge iss53 Merge made by the 'recursive' strategy. <파일이름> | *+ * file changed, * insertion(+)
hotfix를 merge 했을 때 처럼, master 브랜치로 체크아웃 후 merge를 시도했다. hotfix와는 다르게
Fast-forward
표시는 뜨지 않는데, 현재 iss53브랜치가 가리키는 커밋이 merge할 브랜치의 조상이 아니기 때문이다. 이런 경우에는 새로운 커밋을 만들어 두 브랜치를 병합한다(3-way Merge).C6는 merge 커밋이다. 각 브랜치가 가리키는 커밋 두 개와(C4, C5) 공통 조상 하나(C2)를 사용하여 병합한 것이다. master 브랜치는 merge 커밋을 가리키며, iss53 브랜치는 이전 위치에 머무른다. 필요가 없으니
$ git branch -d iss53
명령어로 삭제하자.
Merge시의 충돌
가끔씩 3-way Merge가 실패할 수 있다. 서로 다른 브랜치에서 같은 파일의 한 부분을 동시에 수정한 경우가 그렇다. 아래와 같은 메세지로 확인할 수 있다.
CONFLICT (content): Merge conflict in <파일이름>
Automatic merge failed; fix conflicts and then commit the result.
혹은 git status
명령어로 문제가 되는 파일을 알 수 있다. unmerged 상태로 표시되는데, 충돌이 난 부분 또한 표시된다.
<<<<<<< HEAD:<파일이름>
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> iss53:<파일이름>
위쪽이 HEAD 버전이고, 아래쪽이 병합되는 브랜치이다. 둘 중 하나를 고르거나 아예 새로 작성하여 충돌을 해결할 수 있다. 수정 이후에는 <<<<<<<
, =======
, >>>>>>>
가 포함된 행을 삭제하고 git add
로 다시 git에 저장하면 된다. 이후 git status
로 충돌이 해결되었는지 확인하고 git commit
으로 merge한 내용을 커밋하면 병합이 완료된다.