들어가기 전
- 이 글의 출처는 맨 아래 참고 자료에 추가했습니다.
- 맨 아래 실습을 직접 해보셔도 좋으나, 브랜치 병합 과정만 해보고 싶으신 분들을 위해 Github Repository를 만들어놨습니다.
- 실습은 ls -al ,git log, git log --graph 등 명령어를 통해 눈으로 직접 확인하면서 진행하는 걸 추천드립니다.
공부하게 된 이유 및 상황 설명
- 전까지는 Github에서 PR 후, 브랜치 Merge(이하 '병합')을 진행하다가 최근에 혼자 프로젝트를 진행하면서 PR을 하지 않고 CLI 환경에서 병합를 했습니다.
- 브랜치 병합 후, 브랜치 그래프에서 feature 브랜치가 dev 브랜치와 합쳐져있는 걸 확인하게 됐고 그 원인을 몰라서 찾아보게 됐습니다.
# dev 브랜치에서 feature 브랜치 생성 후, 이동
$ git branch --show-current
dev
$ git checkout -b feature
# feature 브랜치에서 파일 생성 후, add -> commit -> push
$ touch test_file.txt
$ git add .
$ git commit -m "merge 테스트를 위한 커밋"
$ git push --set-upstream origin feature
# dev 브랜치로 이동 후, dev 브랜치에서 feature 브랜치를 병합
$ git checkout dev
$ git merge feature
git merge의 기본 동작
Fast-forward Merge
A 브랜치에서 다른 B 브랜치를 병합할 때 B 브랜치가 A 브랜치 이후의 커밋을 가리키고 있으면 A 브랜치가 B 브랜치와 동일한 커밋을 가리키도록 이동하는데, 이를 Fast-forarward Merge라 한다.
# 설명
hotfix 브랜치가 가리키는 C4 커밋이 C2 커밋에 기반한 브랜치이기 때문에 브랜치 포인터는 병합 과정 없이 그저 최신 커밋으로 이동하는 걸 볼 수 있다.
참고: 아래 그림 1, 그림 2
$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward // Fast-forward 라는 문구가 있다.
index.html | 2 ++
1 file changed, 2 insertions(+)
3-way Merge
A 브랜치에서 다른 B 브랜치를 병합할 때 A 브랜치가 B 브랜치의 조상이 아닌 경우, Git은 각 브랜치가 가리키는 커밋 두 개와 공통 조상 하나를 사용하여 병합하게 되는데 이를 3-way Merge라 한다.
# 설명
hotfix 를 Merge 했을 때와 메시지가 다르게 현재 브랜치가 가리키는 커밋이 병합할 브랜치의 조상이 아니므로 Git은 Fast-forward Merge 방식으로 병합하지 않는다.
단순히 브랜치 포인터를 최신 커밋으로 옮기는 게 아니라 3-way Merge 의 결과를 별도의 커밋으로 만들고 나서 해당 브랜치가 그 커밋을 가리키도록 이동시킨다. 그래서 이런 커밋은 부모가 여러 개고 Merge 커밋이라고 부른다. (그림 5의 C6)
참고: 아래 그림 3, 그림 4, 그림 5
$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html | 1 +
1 file changed, 1 insertion(+)
Git Merge의 옵션별 설명
bash에서 `git merge --help` 옵션을 통해 나온 설명을 기반으로 내용을 추가했습니다.
옵션 | 설명 |
--ff | git merge의 기본값으로 설정되있는 옵션으로 생략 가능합니다. 가능한 경우, Fast-forward 방식으로 브랜치를 병합합니다. Fast-forward 가 불가능한 경우, 3-way Merge 로 브랜치를 병합합니다. |
--no-ff | 모든 경우의 Merge 커밋을 생성합니다. 이 경우 브랜치 병합이 Fast-forward 방식로 해결될 수 있는 경우에도 마찬가지입니다. Github에서 Pull Request 를 통해 병합할 경우, 해당 방식이 사용됩니다. |
실습
실습 1. git merge를 통한 Fast-forward Merge 브랜치 병합
# 1. 테스트를 위한 브랜치로 생성, 이동 후, 현재 브랜치 확인
$ git checkout -b dev/merge
$ git branch --show-current
dev/merge
# feature 브랜치 생성 후, 이동
$ git checkout -b feat/fast-forward
# feature 브랜치에서 fast-forward-feat 파일을 생성하고 commit 후, push
$ touch fast-forward-feat
$ git add .
$ git commit -m "dev/merge 브랜치에서 git merge feat/fast-forward 하기 위한 커밋"
$ git push
# develop 브랜치로 이동후, feature 브랜치를 병합
$ git checkout dev/merge
$ git merge feat/fast-forward
$ git log --graph
실습 2. git merge를 통한 3-way Merge 브랜치 병합
# 1. 테스트를 위한 브랜치로 생성, 이동 후, 현재 브랜치 확인
$ git checkout -b dev/merge
$ git branch --show-current
dev/merge-3-way
# 2. feature 브랜치 생성 후, 이동
$ git checkout -b feat/3-way
# 3. feature 브랜치에서 3-way-feat 파일을 생성하고 commit 후, push
$ touch 3-way-feat
$ git add .
$ git commit -m "dev/merge 브랜치에서 git merge feat/3-way 하기 위한 커밋"
$ git push
# 4. develop 브랜치로 이동 후, 3-way-dev 파일을 생성하고 commit 후, push
$ git checkout dev/merge
$ touch 3-way-dev
$ git add .
$ git commit -m "3-way Merge 를 테스트 하기 위한 커밋"
$ git push
# 5. develop 브랜치에서 feature 브랜치를 병합
$ git merge feat/3-way
$ git log --graph
실습 3. git merge --no-ff 를 통해 강제로 3-way Merge 방식으로 브랜치 병합
# 1. 테스트를 위한 브랜치로 생성, 이동 후, 현재 브랜치 확인
$ git checkout -b dev/merge
$ git branch --show-current
dev/merge
# feature 브랜치 생성 후, 이동
$ git checkout -b feat/no-ff
# feature 브랜치에서 no-ff 파일을 생성하고 commit 후, push
$ touch no-ff
$ git add .
$ git commit -m "dev/merge 브랜치에서 git merge --no-ff feat/no-ff 하기 위한 커밋"
$ git push
# develop 브랜치로 이동후, feature 브랜치를 병합
$ git checkout dev/merge
$ git merge --no-ff feat/no-ff
$ git log --graph
참고 자료
[Git Documentation] 3.2 Git 브랜치 - 브랜치와 Merge의 기초
[위키독스::Visual studio 사용자를 위한 git] 05-03 merge의 종류 : fast-forward, 3-way merge
[위키독스::Visual studio 사용자를 위한 git] 05-04 merge 옵션 : --ff, --no-ff, --squash
댓글