Original article: How to Resolve Merge Conflicts in Git – A Practical Guide with Examples

How to Resolve Merge Conflicts in Git – A Practical Guide with Examples

Git은 오픈소스 분산 버전 컨트롤 시스템입니다. Git은 로컬 브랜칭, 스테이징, 워크플로우 등을 사용하여 여러분이 프로젝트 파일들을 쉽게 관리할 수 있도록 도와줍니다.

오늘날 많은 개발자가 Git을 사용하며, 아래와 같은 기본적인 Git 사용법에 익숙합니다.

  • 저장소(repository)를 초기화하기
  • 브랜치들을 생성하기
  • 변경을 stage/unstage하기
  • 수정사항을 커밋하기
  • 원격 저장소에 커밋을 푸시하기

그러나 많은 개발자들이 머지, 머지 충돌 해결과 같은 개념들에 대해 혼란스러워 합니다. 이 게시글에서는 실천을 통해서 머지 충돌을 어떻게 해결하는지 배울 것입니다. 즉, 여러분은 이 글을 통해 읽고, 이해하고, 직접 시도해보는 것을 진행할 것입니다.

만약 비디오 영상을 통해서도 배우고 싶다면, 아래 영상을 참고하면 됩니다. 여러분께서 Git이 처음이고 기본 컨셉들을 모두 배우고 싶다면, 영상 Demystifying Git for Beginners | Learn Git | Using the Git Bash CLI
이 도움이 될 것입니다.

개발자들은 "머지 충돌"에 대해 어떻게 이야기할까?

최근 저는 트위터, 링크드인, 유튜브에서 개발자들을 대상으로 깃 머지 충돌을 편하게 해결할 수 있냐는 질문으로 투표를 진행했습니다. 결과가 어땠을까요?

70-80%의 개발자들이 깃 머지 충돌을 해결하는데 어려움을 느낀다고 답했습니다. 이를 통해 머지 충돌을 해결하는 것이 중요한 주제라는 것을 알 수 있습니다.

깃 머지 충돌에 대한 투표 결과

깃 머지와 머지 충돌이 무엇인가?

Git은 여러분의 모든 파일들의 버전 히스토리를 가지고 있는 버전 컨트롤 시스템입니다. 덕분에 여러분에 원하는 버전으로 언제든지 되돌아갈 수 있습니다.

만약 여러분이 abc.txt라는 파일을 만들고 Git 저장소로 푸시(push)했다고 가정해보죠. 이 때, 이 파일은 현재 버전에 해당합니다. 만약 여러분의 동료가 같은 파일을 수정하고 저장소에 푸시했다면, 그 파일은 새 버전을 가지게 됩니다.

Git merge는 현재 파일들의 내용을 이전 버전들과 동기화하는 기능입니다. 이 기능은 필수적인 기능인데, 누가 어떤 시점에서도 최신 파일 위에 작업을 시작할 수 있게 해주기 때문입니다. 이번 버전에 수정사항을 오버라이딩(overriding)하지 않고도 말이죠.

Git merge은 동일한 파일에 새로운 변경 사항을 반영하기 전에 다른 개발자들이 수정한 내용들을 통합하는데 도움을 줍니다.

image-46

우리가 깃 머지에 대해 알아야 할 것은 2가지 입니다:

  1. 변경사항 : 두 버전의 파일 사이에 어떤 유형의 작업이 수행되었나? 새로운 내용이 추가되었는지, 제거되었는지, 또는 기존 내용을 업데이트했는지.
  2. 가능성 : 수정이 파일 내 다른 영역에 발생했는지 아니면 같은 영역의 파일에 발생했는지 2가지의 가능성이 있습니다. 여기서 같은 영역이라는 의미는 개발자들이 파일 내 가까운 지역의 내용들을 각자 수정했다는 의미입니다. (예를 들어, 같은 문단이거나 같은 라인)

다행히, Git은 auto-merge 전략으로 대부분의 문제들을 해결합니다. 그러나 파일 내 같은 영역에서 수정 작업들이 발생한 경우, auto-merge가 수행되지 않습니다. 대신, Resolve the Merge Conflicts 메시지를 보여줍니다.

공포의 Git 머지 충돌

알렉스와 티나, 두 명의 개발자들의 이야기를 예시로 이해하는 시간을 가져보겠습니다.

어느날,

  • 알렉스가 원격 저장소로에서 그의 로컬 저장소로 수정사항을 pull 했다
  • 그가 abc.txt라는 파일을 수정하고, 스테이징하고, 커밋한 뒤 마침내 원격 저장소에 이를 push했다
  • 그 동안, 알렉스가 abc.txt 파일을 수정한지 알아채지 못한 티나가 파일의 같은 영역에 일부 코드를 수정하고 원격 저장소로 push를 시도했다
  • 버전 관리 시스템인 Git으로부터 티나는 현재 원격 저장소에 있는 파일보다 오래된 버전의 파일을 수정했다는 경고 문구를 확인한다(알렉스가 이미 원격 저장소의 것을 수정했기 때문)
  • 이제, 티나는 우선 원격 저장소로부터 수정사항을 pull 받고, 파일을 업데이트한 다음 다시 푸시를 해야 한다
  • 티나가 작업을 수행했으나, auto-merge 실패라는 문구가 떴다. 그래서 그녀는 merge conflict를 해결해야만 하는 상황이다
image-45

이 이야기가 왠지 익숙하시다구요? 여러분에게도 비슷한 사건이 발생한적이 있나요? 여러분도 과거에 티나의 상황을 겪었을 가능성이 있을 겁니다. 만약 아니라면, 곧 경험하겠죠. 자, 이제 티나가 이 문제를 어떻게 생산적으로 해결했는지 알아보겠습니다.

Git에서 머지 충돌을 해결하는 방법

머지 충돌 해결하는 것은 들리는 것만큼 어려운 것이 아닙니다. 마음을 차분히 가지고 수정사항을 확실히 파악한다면 대부분의 문제를 어렵지 않게 해결할 수 있습니다.

사고 과정

일단 티나가 수정사항을 pull하게 되면, 티나의 로컬 파일에는 그녀의 수정사항과 Alex의 수정사항이 함께 존재하게 됩니다. 여기서 티나의 선택지는 4개가 있습니다:

  • 알렉스의 수정사항을 유지하고 그녀의 것을 제거하기
  • 알렉스의 수정사항을 지우고 그녀의 것을 유지하기
  • 알렉스의 수정사항과 그녀의 수정사항 둘 다 유지하기
  • 알렉스와 그녀의 수정사항 모두 지우기

이중 그녀는 어떤 방법을 선택해야 할까요? 프로젝트의 요구사항과 상황에 따라 완전히 다릅니다. 티나는 새로 들어온(incoming) 수정사항을 확인하고 그 상황에 적절한 작업을 수행할 것입니다.

새로 들어온(incoming) 수정사항이 무엇일까요? 티나는 이를 어떻게 확인할까요? 티나는 수정사항을 어떻게 만들까요? 여러가지 질문이 있습니다. 아래에서 몇 가지 실제 사례를 들면서 답을 찾아보겠습니다.

Git 머지 충돌을 해결하기 위한 단계들

머지 충돌에 관한 실제 사례들을 몇 가지 들어보고 이를 어떻게 해결할 지 배워봅시다. 혹시 이 개념들을 영상으로 배우고 싶다면 영상의 머지 충돌에 관한 부분을 확인해주세요.

사례 1: 파일의 같은 영역에 수정사항이 있을 경우

같은 영역에서 여러 수정사항이 있어 Git이 auto-merge를 수행하지 못할 경우, 특수 문자들로 충돌 지역을 표시합니다. 해당 특수문자들은 아래와 같습니다.

  • <<<<<<<
  • =======
  • >>>>>>>

<<<<<<<======= 사이에는 여러분의 로컬 환경의 수정사항들을 가르킵니다. 이 수정사항들은 아직 원격 저장소에 반영되지 않은 상태입니다. =======>>>>>>> 사이에는 원격 저장소 또는 다른 브랜치의 수정사항들을 가르킵니다. 이제 여러분은 2개의 섹션들을 확인하여 결정을 내려야 합니다.

아래 이미지는 충돌이 발생하여  auto-merge를 수행할 수 없는 파일의 내용들을 보여줍니다. 충돌 지점은 로컬에서 - Sleep이라는 코드를 추가하여 수정한 부분에 있습니다. 그동안 누군가가 같은 영역에 ‘- Gym’이라는 코드 한 줄을 추가한 수정내용을 push한 상황이네요.

따라서 - Sleep 은 로컬 환경의 수정사항으로, - Gym은 원격 저장소나 다른 브랜치에서 incoming되는 수정사항으로 인식됩니다.

머지 충돌 영역 표시

같은 영역 내 수정으로 인해 발생한 머지 충돌

당신은 상황과 프로젝트의 수요에 기반하여 충돌을 해결할 것입니다. 만약 - Sleep 만 살리고 싶다면, 그것만 살리고 나머지 충돌 부분은 제거할 것입니다. 이 경우, 파일 내용은 아래와 같이 될 것입니다:

- Eat
- Read
- Sleep

반대로 - Gym만 살리고 - Sleep을 지울 수도 있습니다:

- Eat
- Read
- Gym

만약 두 줄 모두 살려야 한다면, 충돌 지점을 알려주는 기호들만 삭제하면 됩니다.

- Eat
- Read
- Sleep
- Gym

만약 어떠한 수정 내용도 반영하고 싶지 않다면, 모두 지우세요.

- Eat
- Read

현재 상황에서 어떤 수정사항을 선택할지 결정하는 것은 온전히 여러분의 몫입니다. 수정을 하고나서 충돌 지점을 알려주는 기호(<<<<<<<,  =======, >>>>>>>)들이 남아있지 않도록 확인해야 합니다. 수정이 끝나면, 아래처럼 진행해주세요.

수정사항을 스테이징(Stage) 하기:

git add <files>

메시지와 함께 수정 사항들을 커밋하기:

git commit -m "Message"

마지막으로, 원격 저장소로 수정사항을 푸시합니다:

git push

이번 시나리오에서 머지 충돌을 해결하는 방법은 이것이 전부입니다.

사례 2: 원격 저장소/다른 브랜치에서 파일이 삭제된 경우

다른 브랜치에서 한 개발자가 파일을 수정하는 동안, 또 다른 개발자가 자신의 브랜치에서 동일한 파일을 삭제한 상황입니다. 이 경우, 여러분은 파일을 유지하고 싶은지 아니면 지우는 것이 옳은지 판단해야 합니다.

삭제된 파일을 여러분의 브랜치에 다시 추가하기 위해, 이렇게 하세요:

git add <file-name>

파일을 지워주세요.

git rm <file-name>

그리고 다음 메시지와 함께 수정사항을 커밋해주세요.

git commit -m "Message"

마지막으로, 커밋을 푸시하세요.

git push

마치며

여러분이 위 두 사례에 대해 배우고 실습한다면 대부분의 상황들을 대처하고 머지 충돌을 해결할 수 있습니다. 그렇기 때문에 저는 여러분이 이것들을 여러번 연습하길 추천합니다.

여러분이 만약 새 시나리오를 경험하거나 머지 충돌을 해결하는데 어려움을 느낀다면, 이 비디오에 댓글을 달아주셔도 좋아요. 답변을 드릴 수 있도록 최선을 다 해볼게요!

정리하기 전에, 몇 가지 팁을 드려요:

  • 이 게시글에 나온 모든 예시들은 여러분이 GitBash를 사용하거나 또는 다른 Git CLI로 머지 충돌을 해결한다는 점을 가정합니다. 물론 다른 GUI 도구를 사용할  수  있습니다
  • 항상 새 코드를 작성하기 전에 원격 저장소 또는 관련 브랜치에서 pull을 받으세요. 여러분의 브랜치를 항상 최신 상태로 유지해줄 것이고 충돌 가능성도 줄여줍니다
  • 항상 push하기 전에 pull을 해서 Git이 거절하는 것을 방지하세요
  • 머지 충돌을 해결하는 동안 무엇을 살리고 무엇을 삭제할지 스스로 판단하기가 어렵다면 동료 개발자들에게 이야기하세요.

모두 감사합니다. Git 머지 충돌과 관련하여 여러분께 유익한 게시글이 되었길 바래요.

우리 소통해요.

  • 매일 웹 개발과 프로그래밍 팁을 얻고싶으시다면  트위터 계정을 팔로우 해주세요
  • 제 오픈소스 프로젝트는 GitHub에서 확인할 수 있어요
  • 제 유튜브 채널을 구독하시면 JavaScript, ReactJS, Node.js, Git 등 웹 개발 관련 실용적인 정보를 얻을 수 있어요

다음 게시글에서 봬요. 그때까지, 잘 지내시고 항상 행복하세요!