브랜치(Branch) 병합(Merge)
브랜치를 사용하는 것은 안정적인 코드에 영향을 주지 않고 분리해 개발을 하기 위해서입니다.
버전 관리 시스템을 어떻게 운용하느냐에 따라
목적이 다를 수 있겠지만, 보통은 다음과 같이 운용합니다.
master 브랜치엔 안정된 버전의 소스를 둡니다.
안정된 버전의 소스라는 것은
실제 서비스에 적용되어 있는 버전과 동일한 버전의 소스를 얘기합니다.
그래서 실제 서비스에 배포했거나 배포할 코드만 master 브랜치에 둡니다.
그리고 추가 작업들은 브랜치를 만들어서 진행하고,
테스트까지 완료되면, master와 합치게 됩니다.
master와 합친 후 최종 테스트를 거쳐서 실제 서비스에 적용하게 됩니다.
이렇게 생성한 브랜치를 다른 브랜치와 합치는 작업을 병합이라고 합니다.
머지(Merge)한다고 합니다.
지금까지 실습을 유지하고 있다면,
현재 filea.html 파일의 내용이 master와 testbranch1 가 다음과 같이 다릅니다.
<!-- master 브랜치의 filea.html 파일 내용 -->
<h1>파일A를 만듭니다.</h1>
<h2>파일A를 수정합니다.</h2>
<h2>파일A를 두번째로 수정합니다.</h2>
<h2>파일A를 첫 커밋 이후 처음으로 수정합니다.</h2>
<h2>파일A를 두번째 커밋 이후 추가 수정합니다.</h2>
<!-- testbranch1 브랜치의 filea.html 파일 내용 -->
<h1>파일A를 만듭니다.</h1>
<h2>파일A를 수정합니다.</h2>
<h2>파일A를 두번째로 수정합니다.</h2>
<h2>파일A를 첫 커밋 이후 처음으로 수정합니다.</h2>
<h2>파일A를 두번째 커밋 이후 추가 수정합니다.</h2>
<h2>브랜치 testbranch1 에서 파일A를 수정합니다.</h2>
<h2>브랜치 testbranch1 에서 파일A를 두번째 수정합니다.</h2>
이 정도로 간단한 부분은 사람이 직접 확인하고 비교해서 합칠 수도 있겠습니다.
하지만, 실제 코드는 수정되는 파일도 많고 수정되는 내용도 상당히 많은 것이 일반적입니다.
그래서 사람이 직접 비교해서 합친다는 것은 개발하는 것보다 어려운 일이 될 수 있습니다.
이를 Git을 사용하면 쉽게 자동으로 합칠 수 있습니다.
하지만 아무리 좋은 도구라고 해도 자동으로 반영하지 못하는 것이 있습니다.
자동으로 합치지 못하는 경우를 충돌(Conflict)이라고 합니다.
Git은 병합을 함에 있어서 다음의 두 가지 방식을 제공합니다.
① Fast-forward 병합
② 3-way 병합
Git에서 충돌 없이 합치기 위해서는 이 두 가지 방식의 차이를 이해해야 합니다.
Fast-forward 병합
Fast-forward 병합은 가장 간단한 방식이며, 일반적으로 혼자 개발할 때 사용합니다.
지금까지 실습을 해오면서 아래와 같이 순차적으로 분기가 되었습니다.
보통 혼자 개발할 때는
브랜치가 생성된 커밋에 따라 순차적으로 분기가 되고,
코드 수정도 순차적으로 이뤄지는 경우가 많습니다.
이렇게 순차적인 커밋에 맞춰서 병합을 처리하는 방법이 Fast-forward 병합입니다.
Git에서 병합하는 명령어는 merge입니다.
merge 명령어는 현재 브랜치를 기준으로 다른 브랜치의 모든 커밋을 병합합니다.
사용법은 다음과 같습니다.
# 브랜치 병합(merge)
$ git merge <브랜치 이름>
예를 들어, 현재 브랜치가 master이고,
$ git merge testbranch1이라고 실행하면
현재 브랜치인 master에 testbranch1의 커밋을 병합한다는 의미입니다.
이는 병합한 기준이 현재 작업 중인 브랜치 master가 되고,
병합 대상은 testbranch1 이 되는 것입니다.
이렇듯 브랜치를 병합하기 위해서는 기준과 대상이 있어야 합니다.
그리고, 병합하고자 하는 브랜치는 같은 로컬 저장소에 있어야 합니다.
그럼, 앞서 testbranch1에서 작업한 사항을 master 브랜치에 병합해 보겠습니다.
이 얘기는 기준이 master 브랜치가 되고, 대상이 testbranch1 이 된다는 얘기입니다.
그래서 기준이 되는 브랜치로 체크아웃(checkout) 합니다.
현재 브랜치가 master라면 바로 머지(merge)하면 되겠습니다.
현재 브랜치가 master임을 확인했습니다.
다음으로 $ git merge testbranch1 을 실행합니다.
그 결과가 다음과 같습니다.
testbranch1 브랜치의 커밋을 master 브랜치에 병합했습니다.
병합 메시지에 Fast-forward라고 명시되어 있습니다.
Fast-forward 방식으로 병합되었다는 것을 알 수 있습니다.
이 결과를 그림으로 표현하면 다음과 같습니다.
분명히 병합이라고 하면 합치는 개념인데,
결과적으로 master 브랜치의 HEAD만 옮겨 간 결과가 되었습니다.
병합한 후에 master 브랜치의 마지막 커밋 위치와 testbranch1 브랜치의 마지막 커밋 위치가 같습니다.
동일한 HEAD 포인터를 가지게 되는 것입니다.
동일한 HEAD 포인터라는 것은 커밋 해시값이 같다는 것이기도 합니다.
이러한 처리 방식으로 인해 Git은 빠른 속도로 처리가 가능하다고 생각됩니다.
잘 합쳐졌는지 master 브랜치에서 filea.html 파일 내용을 확인해 봅니다.
확인해 보니 잘 병합이 되었음을 알 수 있습니다.
이와 같이 Fast-forward 병합은
원본(master)에 추가된 내용이 없다는 가정하에
변경한 파일을 대체하는 것과 같습니다.
3-way 병합
이번에는 3-way 병합에 대해 알아보겠습니다.
이 방식의 경우 여러 개발자와 협업으로 작업하는 경우 대부분 3-way 방식이 사용됩니다.
실습을 위해 이번에는 testbranch1과 master 브랜치에서 모두 수정한 후 병합해 보겠습니다.
이번엔 testbranch1 에서 fileb.html 파일을 수정하고 두 번 커밋하겠습니다.
commit 8과 commit 9를 만들고, 최종 fileb.html 파일 내용을 확인했습니다.
“<h2>testbranch1에서 파일B 첫번재 수정</h2>”을 추가하고 commit 8을 만들고,
“<h2>testbranch1에서 파일B 두번재 수정</h2>”을 추가하고 commit 9를 만들었습니다.
변경된 커밋 결과를 그림으로 나타내면 다음과 같습니다.
이제 master 브랜치로 가서 fileb.html 을 수정하고 두 번 커밋하겠습니다.
두 번째 줄에 “<h2>master에서 파일B에 2라인에 내용 추가</h2>” 내용 추가하고 master commit 8”을 만들고,
세 번째 줄에 “<h2>master에서 파일B에 3라인에 내용 추가</h2>” 내용을 추가하고 master commit 9”를 만들겠습니다.
그 내용이 다음과 같습니다.
변경된 커밋 정보를 그림으로 나타내면 다음과 같습니다.
master와 testbranch1 브랜치가 ‘일곱번째 커밋’에서 분기가 되고 있습니다.
마찬가지로, 소스트리에서 현재 상태를 한번 확인해 보면 다음과 같습니다.
그래프를 보면 ‘commit 7’ 에서 분기되는 것을 알 수 있습니다.
이와 같이 브랜치 모양이 갈라지는 형태로 나뉘게 될 때는 Fast-forward 방식으로는 병합할 수 없습니다.
이때는 3-way 방식이 이용됩니다.
master와 testbranch1 이 공통으로 만나는 커밋이 있습니다.
“일곱 번째 커밋”까지가 공통된 커밋입니다.
그리고, 각각 독립적인 여덟 번째, 아홉 번째 커밋을 가지고 있습니다.
이렇듯 ① ② ③영역으로 나뉘게 됩니다.
이렇게 3개를 하나로 병합해야 하기 때문에 3-way 병합이라고 합니다.
3-way 병합은 두 브랜치가 공통으로 만나는 커밋(위 예에서 “일곱 번째 커밋”)을 기준으로 브랜치를 병합합니다.
병합이 성공적으로 완료되면 새로운 커밋을 만들게 되는데, 이 커밋을 병합 커밋이라고 합니다.
master 브랜치가 기준이 되어 testbranch1 브랜치의 내용이 병합된 결과를 그림으로 표현하면 다음과 같습니다.
그럼, 기준이 되는 master 브랜치로 가서 testbranch1 브랜치를 병합해 보겠습니다.
실행 과정은 다음과 같습니다.
$ git merge testbranch1 라고 하면,
다음과 같은 메시지를 입력할 수 있는 편집기가 실행됩니다.
앞서 얘기했듯이 “병합 커밋”을 만들기 때문에
“커밋 메시지”를 작성하는 단계가 진행되는 것입니다.
기본 입력 값을 유지한 채 :wq를 입력하고 메시지 등록을 종료하면
다음과 같은 메시지가 출력되면서 병합이 완료됩니다.
마지막 Git 로그를 하나 확인해 보겠습니다.
최근 로그 하나만 확인할 때는 -1 을 옵션으로 사용하면 되겠습니다.
해당 커밋 로그에 Merge 항목이 있는 것을 알 수 있습니다.
이로써 병합 커밋임을 알 수 있습니다.
소스트리에서 확인한 결과도 마찬가지입니다.
그래프를 보면 “병합 커밋”에서 만나는 것을 알 수 있습니다.
이제 병합이 잘 되었는지 fileb.html 파일을 확인해 보겠습니다.
다음은 master 브랜치의 fileb.html 파일 내용을 확인한 결과입니다.
master에서 수정했던 내용에 testbranch1에서 수정했던 내용이 합쳐져 있는 것을 알 수 있습니다.
그럼, testbranch1 에서의 fileb.html 파일 내용을 확인하겠습니다.
당연히, 앞서 testbranch1에서 수정했던 내용 그대로입니다.
병합(merge) 취소
앞서 우리는 커밋 후 되돌리는 방법을 학습했습니다.
병합을 했다는 것도 어차피 커밋을 한 것과 마찬가지입니다.
따라서 reset 명령어로 취소할 수 있으며,
소스트리에서 같은 방법으로 취소할 수 있습니다.
병합 실행 후 터미널에서 취소하기 위해서는 다음과 같이 할 수 있습니다.
# 병합(merge) 취소하기
$ git reset --hard HEAD^
reset 명령을 hard 옵션으로 현재 HEAD의 직전 HEAD로 실행한다는 의미입니다.
실제 실행 결과 화면입니다.
지금까지 브랜치에서 작업한 내용을
하나로 합치는 병합(merge)을 실습을 통해 확인해 봤습니다.
다음에는 브랜치를 삭제하고 이름을 변경하는 방법에 대해 알아보겠습니다.
감사합니다.
'코딩해보니 > Git' 카테고리의 다른 글
[Git_32] 충돌(Conflict) - 충돌이란? & 충돌 상황 만들기 (0) | 2023.01.14 |
---|---|
[Git_31] 브랜치(Branch) 삭제, 이름변경 그리고 ... (0) | 2023.01.10 |
[Git_29] 브랜치(Branch)와 커밋(Commit) (0) | 2023.01.03 |
[Git_28] 브랜치(Branch) 이동(checkout) (0) | 2022.12.28 |
[Git_27] 브랜치(Branch) 만들기 (0) | 2022.12.27 |
댓글