[Git] Merge vs Rebase

minidoo·2021년 3월 5일
1

Git

목록 보기
3/3
post-thumbnail

Merge

브랜치 또는 특정 커밋의 내용을 현재 브랜치에 병합하는 것
Merge의 3가지 동작 : Fast forward / 3-Way Merge / Rebase
Merge의 3가지 전략 : Merge (Merge Commit) / Squash and Merge / Rebase and Merge

$ git merge <branch> or <commit>

Merge의 3가지 동작

Fast forward / 3-Way Merge / Rebase

1. Fast forward

merge할 브랜치가 가리키고 있던 commit이 현 브랜치가 가리키는 것보다 앞서 진행한 commit이기 때문에 master 브랜치 포인터는 최신 commit으로 이동한다.

예를 들어, 현재 C2(master)를 부모로 가진 iss53에서 작업중이라고 가정해보자. 여기서 C2(master)을 부모로 가진 hotfix 브랜치를 생성해 commit하고 hotfix에서 master 브랜치를 merge 해야 한다.

master 브랜치는 hotfix보다 앞서 진행한 commit이기 때문에 별도의 추가적인 merge가 필요 없는 상황이다. 따라서 단순히 포인터를 최신 커밋으로 옮기면 되고 이러한 방식을 Fast forward 라고 부른다.

2. 3-Way Merge

병합할 때 별도의 커밋을 생성하고 master 브랜치는 그 커밋을 가리키도록 이동한다.

현재 master가 가리키는 커밋(C4)은 merge할 브랜치(iss53)의 조상이 아니다.
따라서 Fast forward가 적용되지 않는다.

따라서 공통 조상은 C2가 되고 각 브랜치가 가리키는 커밋 C4, C5와 공통 조상 C2를 이용해 새로운 커밋 C6을 만들고 3-Way Merge를 수행하게 된다. 이런 commit은 부모가 여러개이며 Merge Commit이라고 부른다.

* Merge의 충돌

두 브랜치에서 같은 파일을 동시에 수정하고 Merge 하면 Conflict가 발생한다. 작업 내역을 비교하면서 merge할 부분을 적용해야 한다.

<<<<<<< HEAD
내가 작업한 내역
=======
merge하려고 한 브랜치의 작업 내역
>>>>>>> fjdkweqwj123dkdo41jf92kdd71j28
// 다운로드를 통해 충돌난 커밋 번호의 식별자

* 리소스 파일의 충돌 (ex. 이미지)

$ git pull origin master
...
warning: Cannot merge binary files: 이미지.jpg (HEAD vs. 439dc8c08869c342438...)
Auto-merging 이미지.jpg
CONFLICT (add/add): Merge conflict in 이미지.jpg
Automatic merge failed; fix conflicts and then commit the result

$ git checkout 을 사용해 해결 가능하다.

  1. 내가 작업한 파일 사용
$ git checkout HEAD 이미지.jpg
$ git add 이미지.jpg
$ git commit -m "내가 작업한 파일 사용"
  1. 원격지 작업 파일 사용
$ git checkout 439dc8c0 이미지.jpg
$ git add 이미지.jpg
$ git commit -m "원격지 작업 파일 사용"
  1. 두 개의 파일 모두 사용
$ git checkout HEAD 이미지.jpg
$ git mv 이미지.jpg 이미지-me.jpg		// 내 파일 이름 변경
$ git checkout 439dc8c0 이미지.jpg
$ git mv 이미지.jpg 이미지-remote.jpg	// 원격지 파일 이름 변경

$ git rm 이미지.jpg			// tracked 된 파일 untracking

$ git add 이미지-me.jpg
$ git add 이미지-remote.jpg
$ git commit -m "두 개의 파일 모두 사용"

3. Rebase

브랜치의 공통 조상이 되는 base를 다른 브랜치의 커밋 지점으로 바꾸는 것
참고 사이트 : https://velog.io/@godori/Git-Rebase

Rebase 하려는 브랜치 commit들의 변경 사항을 Patch 라는 것으로 만든 후 어딘가에 임시 저장한다.
그리고 이를 master 브랜치에 하나씩 적용하여 새로운 커밋을 만든다.

ex. feature를 master에 rebase 하는 과정

$ git checkout feature
$ git rebase master
$ git checkout master
$ git merge feature

Step1

$ git checkout feature

feature 브랜치로 체크아웃한다. head는 feature을 가리킨다.

Step2

$ git rebase master

master와 feature의 공통 조상인 base 커밋부터 현재 브랜치까지의 변경사항(▵1, ▵2) 을 구해서 patch로 임시 저장한다.

Step3

$ git checkout master

head를 master로 변경한다.

Step4

$ Applying f1
$ Applying f2

head가 가리키고 있는 m2에 변경사항 ▵1를 적용하여 새로운 커밋 f1'를 생성한다.
f1'에 변경사항 ▵2를 적용하여 새로운 커밋 f2'를 생성한다.

Step5

feature이 f2'를 가리키도록 한다.

Step6

$ git merge feature

feature를 master로 Fast forward merge 하여 완료한다.


Merge의 3가지 전략

Merge (Merge Commit) / Squash and Merge / Rebase and Merge
브랜치를 merge 한다는 목적은 같지만, 커밋 히스토리가 기록되는 방식이 달라짐

1. Merge Commit

우리가 알고 있는 일반적인 머지 전략이다.

  • 장점
    • merge된 브랜치가 삭제되어도, 히스토리 그래프 상에는 다른 가지로 표기되어 남아있다.
    • 각 브랜치의 commit과 merge 내역 등의 자세한 정보를 얻을 수 있다.
  • 단점
    • 모든 merge, commit 순간을 히스토리에 기록하기 때문에 히스토리 그래프의 가독성이 떨어진다.

2. Squash and Merge

여러 개의 커밋을 하나로 합치는 머지 전략이다.

merge할 브랜치의 commit을 전부 하나의 commit으로 합친 뒤, 타켓 브랜치에 commit하는 방식이다.

  • 장점
    • merge 내역과 버전 별로 어떤 것이 변경 되었는지 히스토리 상에서 한 번에 알 수 있다.
  • 단점
    • 대상 브랜치의 commit을 하나로 합치기 때문에 일반적인 merge commit 보다는 정보력이 떨어진다.
    • merge한 사실 자체는 알 수 있지만, 어떤 상황에서 어떤 코드를 변경했는지는 알 수 없다.

3. Rebase and Merge

참고 사이트 : https://wnstkdyu.github.io/2018/06/21/aboutgit/

브랜치 히스토리들의 베이스를 변경하는 기능으로, A 브랜치의 변경 사항(commit)이 마치 B 브랜치에서 변경된 것처럼 바꿀 수 있게 하는 기능

  • 장점
    • 커밋 그래프를 단순하게 가져가고 의미있는 커밋들로 관리할 수 있다.
    • merge된 브랜치의 commit을 모두 살려놓기 때문에 수정 정보를 알 수 있다.
  • 단점
    • 해당 브랜치가 어느 시점에 merge 되었는지 알 수 없다.
    • 머지 충돌(Conflict)가 발생했을 경우, 각각 commit에 하나씩 충돌이 발생한다.

* Merge와 Rebase

merge는 비파괴적(non-destructive)이다.

각각의 브랜치에서 이루어진 commit들은 분기가 합쳐진 후에도 그대로 유지되기 때문에 나중에 코드가 변경된 브랜치를 좀 더 쉽게 찾아갈 수 있다.

하지만 merge는 불필요한 commit도 히스토리에 남기 때문에 히스토리 그래프의 가독성이 떨어진다는 단점이 있고, 대안으로 rebase라는 옵션을 사용한다.

rebase는 master 브랜치의 변경점들을 모두 반영하면서 feature 브랜치를 master 브랜치의 끝 부분에서 시작하도록 이동시킨다. merge와 달리 새로운 commit을 생성하여 합치는 것이 아니라, 원래 브랜치의 commit 마다 변경점이 반영된 새 commit으로 변경한다.

rebase는 브랜치를 한 번 정리해주기 때문에 깨끗한 commit 히스토리를 만들 수 있다. 즉, 불필요한 commit 내역은 포함이 되지 않는다.

* Rebase의 중요한 규칙

rebase는 public 브랜치에서 하지 않아야 한다.

예를 들어 feature 브랜치에서 rebase를 하는 경우로 가정해보자.

feature에서 rebase를 하면 master의 모든 commit이 feature 브랜치의 끝 부분으로 올라간다. 문제는 다른 사람들은 아직 master 브랜치를 사용하고 있다는 것이다. rebase가 새로운 commit으로 바꾸기 때문에 master 브랜치가 나와 다른 경우가 생긴다. 이런 상황을 방지하기 위해 rebase는 master 브랜치에서 하는 것을 권장한다.


Thanks to 팀장님 🙂🙃🙂

0개의 댓글