드디어 git의 발암물질, 충돌에 대해 알아볼 차례이다.
충돌이 무엇인지는 이전 섹션에서 간단히 설명했으므로, 충돌이 어째서 발생하는지에 대해 조금 더 설명하도록 하겠다.
이제 Git에 대해서도 많이 공부했으니 Git에서 Commit은 버전을 의미하고 각 Commit은 Parent Commit(이전 커밋)의 ID를 저장하고 있는 LinkedList 형식으로 이루어졌다는 것을 알고 있을 것이다
Git은 협업을 위한 도구이며 당연히 1개 커밋에서 여러 개의 브랜치를 생성해 여러 명의 유저가 작업을 수행할 수 있다.
커밋 A를 기준으로 Branch B1과 Branch B2가 만들어졌고 협업이 수행되었다고 가정하자.
이후 Branch B1이 먼저 커밋 A에 Push 하여 최신 브랜치를 B1으로 만들었다고 치자.
이후 Branch B2가 작업하면 분명 Branch B2가 만들어졌을 때만 해도 커밋A 기준으로 만들었으니 커밋A가 최신 브랜치여야 할 텐데, 웬 이상한 Branch B1 작업물이 최신 브랜치가 된 것이다.
Git에서는 변경된 부분만 Staging Area에 등록되기 때문에 만약 Branch B1과 B2의 작업물이 겹치지 않는다면 정상적으로 병합 커밋(Merge Commit)이 발생할 것이다.
하지만, 동일한 파일에 대하여 작업이 수행되었다면 커밋 A를 기준으로 만들어진 Branch B2는 B1의 작업물을 알지 못하는 상태이므로 충돌이 발생하는 것이다.
이런 충돌은 Git에서 생각보다 빈번하게 일어난다.
빈번하게 일어나는 만큼 충돌의 해결법도 알아둬야 한다.
지금까지 Git에서 충돌이 발생했다면 일단 머지를 시도한 뒤 Github나 VSCode 같은 툴에서 <<<<<<
, ======
, >>>>>
같은 기호 사이에 있는 코드를 잘 조합하는 걸로 해결했을 것이다.
필자도 원래는 그렇게 했지만 이전 회사에서 사용했던 호스팅 사이트 Bitbucket에는 머지 시 충돌을 Bitbucket 사이트에서 해결할 수가 없었다.
그래서 회사 선배에게 배웠던 이런 상황에서도 충돌을 해결할 수 있는 현업 맞춤용 충돌 해결법을 설명하도록 하겠다.
추가로, 충돌은 CLI로 해결하기엔 너무 까다롭다. 특히 프로젝트의 규모가 커질수록 CLI로 충돌을 해결하는 것은 사실상 불가능해진다.
따라서, 충돌 해결은 IntelliJ나 VSCode 같은 작업 툴에서 하도록 하자.
필자는 README 파일을 수정하였고 main 브랜치는 Main 브랜치 등장!
문구를, 새로 생성한 branch_b1 브랜치에는 B1 브랜치 등장!
이라는 문구를 추가한 뒤 각자 커밋 해줬다.
(무조건 충돌이 일어나도록 두 브랜치 파일 동일한 Line에 해당 문구를 추가했다. 요즘 Git이 많이 발전해서 Line이 다르면 충돌이 아니라고 판단하는 경우도 있다)
checkout
)협업을 할 때는 베이스로 할 브랜치가 main 브랜치 혹은 develop 브랜치인 경우가 많다.
문제는 대부분 그 경우 main 브랜치나 develop 브랜치는 개발 서버, 혹은 운영 서버와 연결되어 있고 조금 좋은 회사로 가면 CI/CD 자동화까지 잘 되어 있어 함부로 머지 시키기도 힘들다.
따라서 이 경우에는 베이스로 할 브랜치를 기반으로 새로운 브랜치를 만든 뒤 새로 생성한 브랜치로 checkout
하는 것을 추천한다.
필자는 main 브랜치를 기반으로 merge_main
브랜치를 새로 생성한 뒤 이동했다.
1번 과정에서 Main을 기반으로 만든 브랜치에 branch_b1
브랜치를 병합하자.
위와 같은 창이 나온다면 충돌이 성공적으로(?) 발생한 것이다.
물론 2번 과정에서 Accept Yours
, 혹은 Accept Theris
를 클릭해도 해결은 된다.
문제는 저 둘 중 하나를 선택한다면 다른 개발자가 작업한 작업물이 날아갈 위험성이 있다는 것이다.
예를 들어 Accept Yours
를 선택하면 (Main 브랜치에서 병합을 시켰으니) Main 브랜치 등장!
문구만 최종적으로 남을 것이고 Accept Theirs
를 선택하면 B1 브랜치 등장!
이라는 문구만 최종적으로 남을 것이다.
이런 리스크는 너무 위험하기 때문에 위험을 줄이기 위하여 파일 하나하나 꼼꼼히 더블클릭한 후 충돌이 어디서 발생했는지 확인해 보자.
아마 파일명을 더블 클릭하면 위 사진과 같이 "어떤 부분에서 충돌이 발생했는지"가 뜰 것이다.
위 사진을 보면 Main 브랜치 등장!
부분에서 병합 시 충돌이 발생했을 것이라고 직관적으로 이해 가능할 것이다.
여기에서 개발자는 2가지 선택을 할 수 있는데, >>
와 X
이다.
>>
는 병합이 발생한 부분을 최종 결과물에 반영하겠다는 것이고 X
는 병합 후 최종 결과물에 충돌이 발생한 부분을 삭제하겠다는 의미이다.
우리는 Main 브랜치 등장!
과 B1 브랜치 등장!
이라는 문구 2개를 모두 살리고 싶기 때문에 >>
와 <<
버튼을 클릭하도록 하자.
중간에 있는 창이 병합 후 최종 결과물이다.
중간 창을 보면 B1 브랜치 등장!
과 Main 브랜치 등장!
문구가 모두 살아있음을 볼 수 있다.
(만약 순서가 신경 쓰이거나 새로운 내용을 추가하고 싶을 경우 가운데 창에서도 작업을 수행할 수 있으므로 직접 수정해 주도록 하자)
이런 방식으로 창에 빨간색 부분(충돌이 발생한 부분)이 모두 없어지면 오른쪽 아래에 있는 Apply
버튼을 클릭해 주면 된다.
merge_main
브랜치 병합우리는 최종적으로 main 브랜치
혹은 develop 브랜치
에 작업물을 반영해야 한다.
그리고 아직 우리는 merge_main
이라는 main 브랜치
를 기반으로 만든 브랜치에만 작업물을 반영했다.
따라서 main 브랜치
로 이동한 후 Git > Merge 버튼을 클릭한 뒤 git merge merge_main
을 선택하면 충돌 없이(정확히는 충돌을 모두 해결한 상태로) 병합을 완료할 수 있다.
이는 merge_main
브랜치에 존재하는 커밋은 "이미 충돌이 해결된 커밋"으로 git에서 인지하기 때문에 main 브랜치
와 merge_main 브랜치
를 병합할 때 main 브랜치
에 "충돌이 해결된 작업물"을 머지 한다고 판단하여 충돌 없이 바로 병합 가능해지는 것이다.