ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Git] 브랜치 병합(Merge) & 충돌(Conflict) & 해결(Resolve)에 대하여
    Github/Git 2020. 11. 19. 19:56
    728x90
    반응형

    브랜치 병합(Merge)란? 

    merge 명령어를 사용하면 여러 개의 브랜치를 하나로 모을 수 있다. 예를들어, 아래 그림과 같이 master 브랜치에서 뻗어 나오는 bugfix 브랜치를 봐보자. 

     

    출처: https://backlog.com/git-tutorial/kr/stepup/stepup1_4.html

     

    현재 상황은 master 브랜치에서 뻗어나온 bugfix 브랜치에서 X, Y 커밋을 한 상태이다. 

     

    출처: https://backlog.com/git-tutorial/kr/stepup/stepup1_4.html

    여기서 Merge를 하면 위의 그림과 같이 두 개의 브랜치가 합쳐지게 된다. bugfix 브랜치master 브랜치로 병합할 때, master 브랜치의 상태가 bugfix 브랜치를 만들었을 때의 상태와 같다면 매우 쉽게 merge 할 수 있다. bugfix 브랜치는 master 브랜치의 이력을 모두 포함하고 있기 때문에, master 브랜치는 단순히 이동하기만 해도 bugfix 브랜치와 합쳐질 수 있다. 이와 같은 병합을 빨리 감기(fast-forward) 병합이라고 한다.  

     

     

    빨리 감기(fast-forward) 병합을 GitKraken과 CLI를 이용해서 실습을 해보자.

    먼저 내가 실습하려고 하는 저장소는 위와 같은 상태이다. (master 브랜치에 커밋만 한 상태이다) 그래서 이번에 feature_jg 브랜치를 만들어서 수정을 한 후에 커밋을 해보자. 

     

    git checkout -b 옵션을 사용하면 브랜치를 만들면서 바로 이동할 수 있다. 그리고 새로 만든 브랜치에서 fast.md 파일을 만든 후에 커밋을 진행해보자. 

     

    그리고 GitKraken을 통해서 확인해보면 위와 같이 master 브랜치와 feature_jg 브랜치가 생긴 것을 볼 수 있다. 그런데 일반적으로 생각하는 가지치는 모양이 아니라 일자로 되어 있다. (일자의 모양이라고 브랜치가 없다고 생각하면 안된다.)

     

    출처: https://backlog.com/git-tutorial/kr/stepup/stepup1_4.html

    위와 같은 모양을 생각했는데 GitKraken으로 확인하면 일자의 모양이다. 모양이 일자인 이유는 위에서 말했던 것처럼 master 브랜치의 상태 변화가 없기 때문이다. 만약 master 브랜치에도 커밋을 하고 feature_jg에도 커밋을 했다면 위의 그림과 같은 가지치는 모양이 나올 것이다. 정리하자면, 위와 같은 상태에서 병합(Merge)를 하면 빨리 감기(fast-forward) 병합이 된다.

     

     

    그러면 바로 master 브랜치로 돌아와서 feature_jg 브랜치와 merge를 하면 fast-forward-merge가 되는지 확인해보자.

    git merge 브랜치이름 (master 브랜치에서 명령어를 실행해야 한다.)
    ex) git merge feature_jg

     

     

    위와 같이 master 브랜치feature_jg 브랜치병합(Merge)가 되었을 때, Fast-forward가 뜨는 것을 볼 수 있다. 따라서 master 브랜치가 feature_jg 브랜치가 있는 곳까지 빨리감기를 한 상황이다. 

     

     

    2개 브랜치를 수정한 후에 병합해보기 

    이번에는 master 브랜치에는 A라는 파일을 만들고, feature_jg 브랜치에는 B라는 파일을 만들어서 두 개의 브랜치를 merge하면 어떻게 될지를 알아보려 한다. 

    위와 같이 feature_jg 브랜치에서 gyunny.md 파일을 만들고 커밋까지 진행해보자. 그리고 feature_jg 브랜치에서 master 브랜치로 이동해보자.

     

    master 브랜치에는 Gangnam.md 파일을 만들고 여기서도 commit까지 진행해보자. 

     

    그리고 GitKraken에서 확인을 해보면 이번에는 일자의 모양이 아닌 가지치는 모양으로 만들어진 것을 확인할 수 있다.

    이제 master 브랜치에서 feature_jg 브랜치와 merge를 해보자.

    git merge feature_jg

    merge 명령어를 치면 위와 같은 화면을 볼 수 있다. Default commit message가 위와 같이 되어 있는데 원한다면 수정할 수 있다. 하지만 필자는 그대로 merge를 했다.

     

    그러면 위와 같이 문제 없이 merge가 되었고 feature_jg 브랜치에서 만들었던 fast.md 파일도 master 브랜치에 존재하는 것을 볼 수 있다. 

     

    출처: https://backlog.com/git-tutorial/kr/stepup/stepup1_4.html

     

     

    충돌 해결(Conflict resolve)

    만약 두 개의 브랜치에서 동시에 같은 파일의 같은 곳을 수정하고, 그것을 병합 한다면 충돌(Conflict)이 발생한다.  그리고 충돌이 발생했을 때 해결하는 것을 Conflict resolve라고 한다. 이번 글에서는 충돌이 발생했을 때 CLI에서 해결하는 법과 GitKraken을 이용해서 해결(Resolve)하는 법에 대해서 알아보자.

     

    먼저 충돌을 강제로 발생시키기 위해서 master 브랜치에서 원하는 파일 하나를 수정해보자. 필자는 Gangnam.md 파일에서 첫 번째 줄의 내용을 수정했다.

     

    이번에는 feature_jg 브랜치로 와서 첫 번째 줄을 수정했다. 그러면 master 브랜치와 feature_jg 브랜치가 같은 파일의 같은 줄을 다르게 수정한 상태이다. 

     

     

    그리고 git merge를 해보면 위와 같이 충돌이 발생하는 것을 알 수 있다. 이렇게 같은 파일의 같은 내용을 두 개의 브랜치가 동시에 수정한다면 충돌이 발생하게 된다. 

     

     

     

    1. CLI로 충돌 해결하기

    그리고 Gangnam.md 파일을 보면 위와 같이 되어 있을 것이다. 충돌이 일어난 부분을 표시해주는 것이다.

    • 충돌이 발생한 부분의 시작: <<<<<HEAD
    • 충돌 난 부분의 끝: >>>>>feature_jg
    • 중간 경계선 표시: ========

     

    양 쪽의 브랜치에서 같은 파일의 같은 행을 수정했기 때문에 Git은 어떤 수정 사항을 선택할 것인지 사용자에게 맡기는 것이다. 이런 경우 충돌 난 두 브랜치 중 하나의 내용을 선택하거나, 두 수정 내역을 합치는 등 수동으로 충돌을 해결해야 한다. 

     

     

    2. GitKraken에서 충돌 해결

    강제로 충돌  상황을 만든 후에 GitKraken에서 두 개의 브랜치를 병합하면 위와 같은 화면을 볼 수 있다. 그리고 오른쪽 위를 클릭한 후에 충돌이 일어난 파일을 클릭하면 아래와 같은 화면이 나온다. 

     

    그러면 위와 같이 master 브랜치의 파일에서 충돌이 일어난 부분을 표시해주고, feature_jg 브랜치의 파일에서 충돌이 일어난 부분도 표시해준다. 그리고 아래의 Output은 원래 원본 파일의 내용이다. 

     

    이번에는 충돌 해결(Conflict Resolve)를 해보자. 충돌 해결을 하는 건 두 개의 파일의 내용이 중복 되어 하나의 파일 내용을 삭제해야 할 수도 있고, 둘 다 필요한 내용일 수도 있다. 그래서 위의 사진처럼 브랜치의 파일 코드 옆을 눌러 보면 초록색 체크가 가능하다. 

     

    그와 동시에 아래 output에서도 순서가 정해져서 파일의 내용이 결정된다. 따라서 순서가 중요하다면 초록색 버튼을 순서에 맞게 잘 체크해야 한다. 이렇게 3개의 파일을 보여주는 이유는 Git에서 merge를 할 때 3-way-merge를 사용하기 때문이다.

     

     

    3-way merge란?

    3-way merge는 Git에서 파일을 합칠 때 사용하는 것인데 어떤 것인지 알아보자. 

     

    master Base feature_jg
    A A  
    B B B
    1 C 2
      D D

    위의 테이블의 의미는 각각의 브랜치에 파일의 내용을 보여주는 것이다. 가로는 파일의 줄을 의미하는 것이다. 

     

     

    다시 정리하자면, 파일의 원본(Base) 내용은 아래와 같다.

    A
    B
    C
    D

    그리고 master 브랜치에서 파일의 내용을 아래와 같이 수정했다.

     

    A
    B
    1

    그리고 feature_jg 브랜치에서는 파일의 내용을 아래와 같이 수정했다.

     


    B
    2
    D

    정리하자면 line1은 feature_jg 브랜치만 상태가 다르고, line2는 모두가 같고, line3는 master만 다르고, line4는 master만 파일의 상태가 다르다. 이제 feature_jg 브랜치를 master 브랜치로 병합(merge)하려고 할 때 어떻게 자동으로 병합(merge)이 되는지를 알아보자.

     

     

    일단 그 전에 2-way merge가 무엇인지 먼저 알고 가자.

    master feature_jg 2-way merge
    A   master 파일에는 line에 내용이 있고, feature_jg 파일의 line에는 내용이 없기 때문에 무엇을 채워야 할 지 모르기 때문에 Conflict 발생
    B B master 파일의 line과 feaeture_jg의 파일 line이 같기 때문에 그대로 B 유지
    1 2 master 파일의 line과 feature_jg의 파일 line이 다르기 때문에 Conflict 발생
      D master 파일의 line에는 내용이 없고, feature_jg 파일의 line에는 내용이 있기 때문에 무엇을 채워야 할 지 모르기 때문에 Conflict 발생

    위와 같이 2-way merge는 master 브랜치의 파일과 feature_jg 브랜치의 파일 2개의 대상만 보고 병합(merge)를 하는 것이다. 이렇게 2-way merge를 사용하면 2개의 파일로만 비교해야 하기 때문에 Conflict가 더 많이 발생하게 된다. 

     

     

    3-way merge란?

    master Base(원본) feature_jg 3-way merge
    A A   master에는 파일의 내용이 원본과 같고 feature_jg에서는 파일의 내용이 원본에서 지워진 상태이기 때문이다. 이렇게 지워진 상태에서는 feature_jg 파일의 상태로 합쳐진다 (Conflict 발생하지 않음)
    B B B 3개의 파일 상태가 같기 때문에 B유지
    1 C 2 3개가 모두 다 다르기 때문에 Conflict 발생
      D D 이것도 첫 번째 줄의 상태와 같다. (Conflict는 발생하지 않고 원본 파일에서 지워진 상태로 병합이 된다)

    이렇게 3-way merge는 master 브랜치의 파일, 원본파일, feature_jg의 파일 총 3개를 비교하기 때문에 2-way merge보다 더 효율적이고 충돌(Conflict)가 더 적게 발생하게 된다.

    반응형

    댓글

Designed by Tistory.