브랜치 통합에는 merge
를 사용하는 방법과 rebase
를 사용하는 방법의 2가지 종류가 있다.
어느 쪽을 사용하느냐에 따라 통합 후의 브랜치의 이력이 크게 달라진다. 하나씩 어떤 의미인지 알아보자.
merge를 사용하면 여러 개의 브랜치를 하나로 모을 수 있다. 예를 들어, 아래 그림과 같이 master
브랜치에서 뻗어 나오는 bugfix
라는 브랜치를 보자.
현재 상황은 master 브랜치에서 뻗어 나온 이후로 bugfix
에서 커밋을 2번 해서 위의 그림과 같이 진행이 된 상황이다.
이 bugfix
브랜치를 master
브랜치로 병합할 때, master
브랜치의 상태가 bugfix 브랜치를 만들었을 때의 상태와 같다면 매우 쉽게 merge
할 수 있다.
bugfix
브랜치는 master
브랜치의 이력을 모두 포함하고 있기 때문에, master
브랜치는 단순히 이동하기만 해도 bugfix
브랜치와 합쳐질 수 있다.
이 같은 병합을 fast-forward(빨리 감기)병합
이라고 한다.
그러면 GitKraken
과 CLI
를 이용해서 실습을 해보자.
현재의 상황은 위의 그림과 같고 여기서 feature_jg
라는 브랜치를 만들어서 브랜치에서 약간의 수정을 한 후에 커밋을 해보자.
위의 터미널은 master
브랜치에서 feature_jg
브랜치를 만들면서 이동하고 feature_jg 브랜치에서 fast.md
라는 파일을 만들어 간단히 내용을 적어준 후에 commit까지 한 상태이다.
그리고 나서 GitKraken
을 확인해보면 브랜치를 만들었음에도 불구하고 master
브랜치에서 가지처럼 뻗어나가는 것이 아니라 일자의 모양을 볼 수 있다.(일자 모양이라고 해서 브랜치가 없다고 생각하면 안된다.
)
일자인 이유는 master 브랜치에 상태변화가 없기 때문이다. 만약 master 브랜치에도 커밋을 하고 feature_jg에도 커밋을 한다면 일반적인 가지치는 모양이 나올 것이다.
현재 상황이 가장 맨 위에 첫 번째 그림의 상황과 같다. 한마디로 여기서 master 브랜치와 feature_jg 브랜치를 merge
하면 fast-forward-merge
가 되는 것이다.
그리고 master
브랜치를 돌아와서 feature_jg
브랜치와 merge
를 하면 어떻게 되는지 확인해보자. 머지하는 명령어는 아래와 같다.
git merge 브랜치이름
ex) git merge feature_jg
(현재는 feature_jg를 master에 merge하는 상황이기 때문에 master 브랜치로 와서 feature_jg와 병합을 해야 한다.)
그러면 위와 같이 merge
가 성공한 것을 볼 수 있고, Fast-forward
라는 것이 뜨는 것도 확인할 수 있다. 한마디로 master 브랜치를 feature_jg 브랜치가 있는 곳까지 빨리감기
를
한 상황이다.
예를들어 master 브랜치에는 A라는 파일을 만들고, feature_jg 브랜치에서는 B라는 파일을 만들어서 두 개의 브랜치를 merge 하면 어떻게 될까? 어떻게 되는지 바로 해보자.
위와 같이 feature_jg
에서 새로운 파일을 하나 만들고 master
브랜치로 넘어가자.
그리고 master 브랜치에서도 새로운 파일을 하나 만들었다.
이번에는 두 개의 브랜치에서 모두 수정을 했기 때문에 GitKraken
을 확인해보면 브랜치의 모양이 일자가 아니라 가지모양이 만들어진 것도 확인할 수 있다. 이제 master브랜치에서 두 개의 브랜치를 merge 해보자.
git merge feature_jg
그러면 위와 같이 머지가 되기 전 commit message
를 입력할 수 있는 화면이 나올 것이다. 나는 기본으로 제공해주는 커밋 메세지
로 merge를 하였다. (vi 에디터에서 저장하고 나오기처럼 하면 된다 ex) ESC + : + wq + Enter
)
그러면 성공적으로 머지가 된 것을 확인할 수 있고, 각 브랜치에서 만들었던 새로운 파일들이 문제없이 잘 합쳐진 것도 확인할 수 있다.
만약 두 개의 브랜치에서 동시에 같은 파일의 같은 곳을 수정하고, 그것을 병합 한다면 충돌(Conflict)
이 발생한다. 그리고 충돌이 발생했을 때 해결하는 것을 Conflict resolve
라고 한다.
지금은 충돌이 발생했을 때, CLI
에서 해결 하는 법과 GitKraken
을 이용해서 resolve
하는 법에 대해서 알아보자.
먼저 강제로 충돌을 일으켜보자. master 브랜치에서 본인이 원하는 파일을 원하는 대로 수정을 해보자!
그리고 feature_jg 브랜치로 가서 master 브랜치에서 수정했던 파일의 같은 라인을 다른 것으로 수정해보자.
나는 위와 같이 첫 번째 줄을 Gangnam!!
에서 Git Study
로 바꿨다. 그리고 다시 master 브랜치로 돌아와서 merge를 시도해보자.(master 브랜치에서 merge를 하는 이유는 master는 병합 할 브랜치
이고, feature_jg 브랜치는 병합 될 브랜치이기
때문이다.)
그러면 위와 같이 충돌이 발생하는 것을 볼 수 있다.
충돌이 발생한 파일을 들어가보면 위와 같이 충돌이 일어난 부분을 표시해주는 것을 볼 수 있다.
- 충돌이 발생한 부분의 시작 : <<<<<HEAD
- 충돌 난 부분의 끝 : >>>>>feature_jg
- 중간 경계선 표시 : =========
양 쪽의 브랜치에서 같은 파일의 같은 행을 수정했기 때문에 Git은 어떤 수정 사항을 선택할 것인지 사용자에게 맡기는 것이다.
이런 경우 충돌 난 두 브랜치 중 하나의 내용을 선택하거나, 두 수정 내역을 합치는 등 수동으로 충돌을 해결해야 한다.
(Tip : vi 명령모드에서 x : 문자 하나 삭제, dd : 한줄삭제
)
강제로 충돌이 일어나는 상황을 만든 후에 두 개의 브랜치를 병합하면 위와 같은 화면을 볼 수 있다. 그리고 오른쪽 위를 클릭한 후에 충돌이 일어난 파일을 클릭해보자.
그러면 위와 같이 master
브랜치의 파일에서 충돌이 일어난 부분을 표시해주고, feature_jg
브랜치의 파일에서 충돌이 일어난 부분도 표시해준다.
그리고 아래의 Output은 원래 원본 파일의 내용이다.
그리고 이번에는 충돌 해결(Conflict Resolve)
를 해보자.
충돌 해결을 하는 건 두 개의 파일의 내용이 중복 되어 하나의 파일 내용을 삭제해야 할 수도 있고, 둘 다 필요한 내용일 수도 있다. 그래서 위의 사진처럼 브랜치의 파일 코드 옆을
눌러 보면 초록색 체크
가 나오는 것을 알 수 있다.
그와 동시에 아래 output에서도 순서가 정해져서 파일의 내용이 결정된다. (한마디로 코드의 순서가 중요하다면 순서에 맞게 선택해서 파일을 완성해야 한다는 뜻이다.)
이렇게 3개의 파일을 보여주는 이유는 Git에서 merge를 할 때 3-way merge를 사용하기 때문이다.
3-way merge
는 Git에서 파일을 병합시킬 때 사용하는 것인데 어떤 것인지는 아래의 설명을 보면서 이해해보자.
먼저 아래 테이블의 의미는 각 열(세로)마다 하나의 파일이라고 생각하면 된다. 예를들어 1열은 master 브랜치의 A라는 파일, 2열은 A라는 파일의 원본, 3열은 feature_jg 브랜치의 A라는 파일이라고 생각하자.
(그리고 테이블 안의 행은 파일안에 줄(line)
이라고 생각하면 된다
master | Base | feature_jg |
---|---|---|
A | A | |
B | B | B |
1 | C | 2 |
D | D |
A
B
C
D
A
B
1
B
2
D
정리하자면 line1은 feature_jg 만 파일의 상태가 다르고, line2는 모두가 같고, line3은 master만 다르고, line4는 master만 파일의 상태가 다르다.
이제 feature_jg 브랜치를 master 브랜치로 병합(merge)하려고 할 때 어떻게 자동으로 병합(merge)
이 되는지를 알아보자.
3-way merge를 보기 전에 먼저 2-way merge가 어떤 것인지 알고 가자.
master | feature_jg | 2-way merge |
---|---|---|
A | master의 파일에는 line에 내용이 있고, feature_jg 파일의 line에는 내용이 없기 때문에 무엇을 채워야 할 지 모르기 때문에 Conflict 발생 |
|
B | B | master의 파일의 line과 feature_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
가 더 많이 발생하게 된다.
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
보다 훨씬 효율적으로 병합(merge)를 할 수 있다.