연습 - 병합 충돌 해결

완료됨

어떤 경우에는 아무리 계획을 잘 세웠더라도 일이 잘 진행되지 않을 수 있습니다. 두 명의 개발자가 동시에 동일한 프로젝트 파일에서 작업한다고 가정해 보겠습니다. 첫 번째 개발자는 변경 내용을 아무 문제 없이 프로젝트 리포지토리의 main 분기로 푸시합니다. 두 번째 개발자가 변경 내용을 푸시하려고 할 때 Git에서 ‘병합 충돌’이 있다는 메시지를 표시합니다. 두 번째 개발자가 수정하려고 하는 파일은 최신 변경 내용 또는 파일 버전을 기준으로 더 이상 최신 상태가 아닙니다. 두 번째 개발자의 변경 내용을 병합하려면 먼저 파일 버전을 최신 상태로 만들어야 합니다. 버전 제어를 사용하는 개발자에게 병합 충돌보다 무서운 것은 거의 없습니다.

이와 같은 충돌이 발생할 수 있으므로 이를 처리하는 방법을 ‘알고 있어야’ 합니다. 다행하게도 Git에서는 병합 충돌을 처리하기 위한 솔루션을 제공합니다.

Alice 및 Bob을 위한 분기 만들기

Alice를 위한 분기와 Bob을 위한 분기를 만드는 것부터 시작하겠습니다. 두 개발자 친구는 프로젝트 리포지토리의 파일을 동시에 업데이트합니다. 이들은 로컬 분기에서 업데이트를 수행하기 때문에 서로의 변경 내용을 알지 못합니다.

  1. Alice 디렉터리에 있는지 확인한 다음, Alice가 작업할 수 있도록 add-cat이라는 분기를 만듭니다.

    git checkout -b add-cat
    
    
  2. Bob 디렉터리로 전환한 Bob이 작업할 수 있도록 style-cat이라는 분기를 만듭니다.

    cd ../Bob
    git checkout -b style-cat
    
    

이제 분기에서 몇 가지를 변경하겠습니다.

Alice로 변경 내용 적용

먼저 Alice의 역할을 맡아 웹 사이트 홈페이지를 변경합니다. Bob의 고양이 사진을 Alice의 고양이 사진으로 바꿉니다.

  1. Alice 디렉터리로 다시 변경합니다.

    cd ../Alice
    
    
  2. 앞서 리소스를 다운로드하지 않았다면 이 단원에 수반되는 리소스가 들어 있는 zip 파일을 다운로드합니다. 리소스 파일의 압축을 풉니다.

    wget https://github.com/MicrosoftDocs/mslearn-branch-merge-git/raw/main/git-resources.zip
    unzip git-resources.zip
    
    
  3. bombay-cat-180x240.jpg 파일을 Alice의 Assets 디렉터리로 이동하고 다른 파일을 삭제합니다.

    mv bombay-cat-180x240.jpg Assets/bombay-cat-180x240.jpg
    rm git-resources.zip
    rm bobcat2-317x240.jpg
    
    
  4. index.html 파일을 열고 Bob의 고양이 사진 중 하나를 사용하는 다음 문을

    <img src="Assets/bobcat2-317x240.jpg" />
    

    Alice의 고양이 사진 중 하나를 사용하는 다음 문으로 바꿉니다.

    <img class="cat" src="Assets/bombay-cat-180x240.jpg" />
    
  5. 파일을 저장하고 편집기를 닫습니다.

  6. 이제 다음 Git 명령을 실행하여 변경 내용을 프로젝트 리포지토리로 푸시합니다. 먼저 Assets 폴더에 생성된 커밋을 추가합니다. 그런 다음, main 분기로 다시 전환하고 git pull을 실행하여 아무 것도 변경되지 않았는지 확인합니다. 마지막으로 add-cat 로컬 분기를 main 분기에 병합한 다음 리포지토리에 변경 내용을 푸시합니다.

    git add Assets
    git commit -a -m "Add picture of Alice's cat"
    git checkout main
    git pull
    git merge --ff-only add-cat
    git push
    
    

푸시가 성공했는지 확인하여 완료합니다.

Bob으로 변경 내용 적용

Alice가 어떤 작업을 수행하는지 알지 못하는 Bob은 Alice의 마지막 푸시가 cats라는 CSS 스타일을 리포지토리의 site.css에 추가했음을 알게 됩니다. 그래서 Bob은 해당 클래스를 고양이 사진에 적용하기로 결정합니다.

  1. Bob 디렉터리로 돌아갑니다.

    cd ../Bob
    
    
  2. index.html 파일을 엽니다. Bob의 고양이 사진을 사용하는 문을 <img> 요소에 class="cat" 특성을 추가하는 다음 문으로 바꿉니다.

    <img class="cat" src="Assets/bobcat2-317x240.jpg" />
    
  3. 파일을 저장하고 편집기를 닫습니다.

  4. 이제 Alice의 리포지토리를 업데이트했을 때와 마찬가지로 다음 Git 명령을 실행하여 프로젝트 리포지토리의 변경 내용을 동기화합니다. 변경 내용을 커밋하고, main 분기로 전환하고, git pull을 실행한 다음 스타일 변경을 병합합니다.

    git commit -a -m "Style Bob's cat"
    git checkout main
    git pull
    git merge style-cat
    
    

이때 ‘끔찍한 병합 충돌’이 발생하고 말았습니다. 동일한 파일의 동일한 줄이 두 명의 사용자에 의해 변경된 것입니다. Git에서 충돌을 인식하고 "자동 병합 실패"를 보고합니다. Git에서는 <img> 요소의 src 특성이 bobcat2-317x240.jpg 파일 또는 bombay-cat-180x240.jpg 파일 중 무엇을 참조할지 알 수 있는 방법이 없습니다.

Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

Git의 출력은 index.html 파일을 충돌 소스로 식별합니다.

이제 문제는 Bob은 어떻게 해야 하는가입니다.

병합 충돌 해결

이 시점에 Bob에게 몇 가지 옵션이 있습니다. Bob은 다음 작업 중 하나를 사용할 수 있습니다.

  • git merge --abort 명령을 실행하여 main 분기를 병합을 시도하기 전 상태로 복원합니다. git pull 명령을 실행하여 Alice의 변경 내용을 가져옵니다. 그런 다음 새 분기를 만들고, 변경을 수행하고, 이 분기를 main 분기에 병합합니다. 마지막으로 변경 내용을 푸시합니다.
  • git reset --hard 명령을 실행하여 병합을 시작하기 전의 위치로 돌아갑니다.
  • Git에서 영향을 받는 파일에 삽입하는 정보를 사용하여 수동으로 충돌을 해결합니다.

개발자들은 마지막 옵션을 선호하는 것으로 보입니다. Git는 콘텐츠 버전의 충돌을 감지하면 두 버전의 콘텐츠를 ‘모두’ 파일에 삽입합니다. Git에서는 충돌을 식별하고 해결하는 데 도움이 되도록 왼쪽 꺾쇠 괄호 <<<<<<<, 이중 대시(등호) =======, 오른쪽 꺾쇠 괄호 >>>>>>> 같은 특수 서식을 사용합니다. 일련의 대시 ======= 위의 콘텐츠는 현재 분기의 변경 내용입니다. 구분선 아래의 내용은 병합하려는 분기의 콘텐츠 버전을 보여 줍니다.

Bob의 리포지토리에 있는 index.html 파일은 이제 다음과 같이 표시됩니다. 충돌이 발생한 콘텐츠 주위에 특수 서식이 있습니다.

<!DOCTYPE html>
<html>
  <head>
    <meta charset='UTF-8'>
    <title>Our Feline Friends</title>
    <link rel="stylesheet" href="CSS/site.css">
  </head>
  <body>
    <nav><a href="./index.html">home</a></nav>
    <h1>Our Feline Friends</h1>
    <<<<<<< HEAD
    <img class="cat" src="Assets/bombay-cat-180x240.jpg">
    =======
    <img class="cat" src="assets/bobcat2-317x240.jpg">
    >>>>>>> style-cat
    <footer><hr>Copyright (c) 2021 Contoso Cats</footer>
  </body>
</html>

index.html 파일을 편집하여 병합 충돌을 해결해 보겠습니다. 이 병합 충돌은 빠른 수정이므로 여전히 Bob 디렉터리에 있더라도 main 분기에서 직접 변경할 것입니다.

  1. index.html 파일을 열고 특수 서식 줄을 삭제합니다. 다른 문은 제거하지 마세요.

    <<<<<<< HEAD
    =======
    >>>>>>> style-cat
    
  2. 파일을 저장하고 편집기를 닫습니다.

    이제 index.html 파일에는 두 <img> 요소가 있습니다. 하나는 Bob의 고양이 그림에 대한 요소이고 다른 하나는 Alice의 고양이 그림에 대한 요소입니다.

    일부 텍스트 편집기는 Git와 통합되어 병합 충돌을 나타내는 텍스트가 표시되는 경우 지원을 제공합니다. Visual Studio Code에서 index.html 파일을 열면 다음 코드가 표시됩니다.

    Screenshot that shows how to resolve merge conflicts in Visual Studio Code.

    편집기에서 두 가지 변경 모두 수락을 선택하면 <img> 요소 주변의 줄이 삭제되고 두 요소 모두 그대로 남습니다.

  3. 다음 명령을 실행하여 변경 내용을 커밋합니다.

    git add index.html
    git commit -a -m "Style Bob's cat"
    
    

    git add 명령은 Git에 index.html 파일에서 충돌이 해결되었다고 알려줍니다.

  4. 변경 내용을 원격의 main 분기로 푸시합니다.

    git push
    
    
  5. 변경 내용을 Alice의 리포지토리에 동기화하여 마칩니다.

    cd ../Alice
    git pull
    
    
  6. 마지막으로, Alice의 index.html 파일을 열고 해당 버전에도 고양이 사진이 포함된 두 개의 <img> 태그가 있는지 확인합니다.