본문 바로가기
Git

Fast-forward와 3-way 그리고 git Merge 옵션(--ff, --no-ff)

by Sondho 2024. 4. 18.

들어가기 전

  • 이 글의 출처는 맨 아래 참고 자료에 추가했습니다.
  • 맨 아래 실습을 직접 해보셔도 좋으나, 브랜치 병합 과정만 해보고 싶으신 분들을 위해 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

그림 1

$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward				// Fast-forward 라는 문구가 있다.
 index.html | 2 ++
 1 file changed, 2 insertions(+)

 

그림 2. Fast-forward Merge

 

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

그림 3

$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html |    1 +
1 file changed, 1 insertion(+)

그림 4. 커밋 3개를 병합
그림 5. 3-way Merge

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

Fast-forward 라는 문구를 볼 수 있다.

 

결과: git merge를 통한 Fast-forward Merge

 

실습 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

Fast-forward 라는 문구 대신 Merge made by the 'ort' strategy. 라는 문구가 있다.
결과: git merge를 통해 3-way Merge

실습 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

3-way Merge 방식과 동일하게 Fast-forward 라는 문구 대신 Merge made by the 'ort' strategy. 라는 문구가 보인다.
git merge --no-off를 통해 강제로 3-way Merge 방식으로 브랜치 병합

 


참고 자료

[Git Documentation] 3.2 Git 브랜치 - 브랜치와 Merge의 기초

 

Git - 브랜치와 Merge 의 기초

Merge 시에 발생한 충돌을 다루는 더 어렵고 요상한 내용은 뒤에 고급 Merge 에서 다루기로 한다.

git-scm.com

 

[위키독스::Visual studio 사용자를 위한 git] 05-03 merge의 종류 : fast-forward, 3-way merge

 

05-03 merge의 종류 : fast-forward, 3-way merge

브랜치간 merging을 할 때 새로운 commit이 생겨날 수도 있고, 그렇지 않을 수도 있다. 본 절에서는 대표적인 merge의 종류인 fast-forward와 3-way m…

wikidocs.net

 

[위키독스::Visual studio 사용자를 위한 git] 05-04 merge 옵션 : --ff, --no-ff, --squash

 

05-04 merge 옵션 : --ff, --no-ff, --squash

> *앞에서 dev1 브랜치의 작업 내용을 `git merge` 하였더니 fast-forward merge가 되면서 master에 dev1의 commit이 모두 합쳐졌다. …

wikidocs.net

 

댓글