[GIT] Git Merge, PR

3 minute read

Published:

In this post, concept and usage of Git merge, and PR is introduced.

Git 이 무엇인가와 초기 세팅 방법에 대한 기초적인 내용은 여기 참고.

Git Merge

Fast Forward란, 두 브랜치가 갈라지지 않았을 때 새로운 merge commit 없이, 포인터만 앞으로 옮기는 병합을 의미한다. 아래 같은 경우 fast forward가 가능하다. 각 알파벳은 커밋을 의미한다.

A -- B -- C        (main)
            \
             D -- E   (feature)
A -- B -- C -- D -- E   (main)

반면, 아래와 같은 경우는 fast forward가 불가능하고 별도의 merge commit이 필요하다.

A -- B -- C -- F   (main)
     \
      D -- E        (feature)
A -- B -- C -- F ------ M   (main)
     \               /
      D -- E --------

M은 merge commit을 의미한다.

Gir merge 옵션에는 4가지가 있다.

  • --no-ff : fast-forward 가능해도 항상 merge 커밋 생성

  • --ff : 기본 설정. fast-forward 시도하고 불가하면 merge 커밋 생성.

  • --ff-only : fast-forward 시도하고 불가하면 merge 안함.

  • --squash : 위 예시에서 merge하여 main에 D, E 커밋 기록을 남기지 않고, 하나의 커밋을 남김.

    A -- B -- C -- S
    

PR

보통은 로컬에서 git merge를 한 다음, 이를 원격으로 push 하기보단, PR을 만들어서 GitHub에서 Merge 버튼을 누른다.

따라서, 위 4가지 merge 방법에 대응하는 PR merge 방법이 github에 버튼으로 존재한다.

PR 버튼내부적으로 하는 일CLI 개념
Create a merge commit항상 merge commit 생성git merge --no-ff
Squash and merge커밋 여러 개 → 하나로 합침git merge --squash
Rebase and merge커밋을 base 위로 재배치git rebase + git merge --ff-only
  • Create a merge commit

    • A -- B -- C -------- M
                  \      /
                   D -- E
      
    • 브랜치에서 작업한 D, E 커밋을 그대로 유지

    • 마지막에 “합쳤다”는 표시용 커밋 M 생성
  • Squash and merge

    • A -- B -- C -- S
      
    • D, E 같은 여러 커밋을 하나(S)로 합쳐서 main 브랜치에 한 커밋만 추가
  • Rebase and merge

    • A -- B -- C -- D' -- E'
      
    • D, E를 C 뒤로 “다시 써서” 붙임. merge 커밋 없음. fast-forward처럼 보임

git rebase란, git merge와 다르게 커밋 히스토리를 보존하지 않고 재작성하여 내 커밋들을 최신 브랜치 위로 다시 올려놓는 것을 의미한다. rebase B to A 시,

  1. A, B 공통 조상 찾는다
  2. B에서 공통 조상 이후 커밋들을 뽑아낸다
  3. A의 최신 커밋 위에 B 커밋을 하나씩 다시 적용(cherry-pick)
main:    A --- B --- C
                 \
feature:           D --- E

위 상황에서 git merge 하면 (git checkout feature, git merge main) 히스토리가 갈라졌다가 다시 합쳐져 커밋 그래프가 복잡해진다.

A --- B --- C
 \           \
  D --- E ---- M   (merge commit)

git rebase 하면 (git checkout feature, git rebase main) D, E를 잠깐 떼어내서 main 최신(C) 위에 다시 붙이게 된다.

A --- B --- C --- D' --- E'

PR merge conflict

merge conflict이 날 때 2가지 해결 방법이 있다. 그 전에 이를 이해하기 위해 branch와 fetch의 개념을 간단히 알아보자.

브랜치는 그냥 어느 커밋을 가리키고 있는 이름(포인터)다.

git fetch 는 원격 저장소 상황만 가져와서 알려주는 것으로, 로컬의 코드를 바꾸지 않는다. 예를들어, fetch 전 brach 상황이 아래와 같았다고 하자.

내 로컬:
main → C

원격(origin):
main → F

이 때, git fetch origin을 하면 아래처럼 바뀐다.

내 로컬:
main        → C
origin/main → F

origin/main은 원격 main을 로컬에 복사해둔 포인터이다.

이제 conflict 발생시 2가지 해결방법을 알아보자. (//ToDo 다음에 이해)

  • 내 로컬 브랜치에서 rebase(또는 merge)로 충돌을 해결하고 push

    • git checkout feature
      git fetch origin
      git rebase origin/main
      # 충돌 나면 파일 수정
      git add <수정한 파일들>
      git rebase --continue
      # 반복
      git push --force-with-lease
      
  • GitHub(PR)에서 “Resolve conflicts”로 해결해서 merge.

Git flow

git flow 란, 하나의 git 개발 규칙, 전략이다.

Leave a Comment