병합과 충돌

병합

분리된 브랜치를 하나로 합친다.

하나씩 직접 비교하는 수동 병합

일일히 하나씩 비교해야 하므로 불편하다.

깃으로 자동 병합

깃에서 제공하는 병합. 그러나 완벽하지는 않아 충돌이 발생한다.

병합 방식

  • Fast-Forward 병합
  • 3-Way 병합

Fast-Forward 병합

빨리 감기라고 표현하는 방식, 모든 변경 사항이 순차적으로 이루어질 때 처리하는 방법

브랜치 생성과 수정 작업

  • 포인터 확인

      $ git rev-parse {branch-name}
      679293db51377e7f977206d2970aa9e43886d5c4
    
  • 소스 작업으로 아래 상태 만들기

    • 브랜치 생성

    Untitled

    • 브랜치 수정 및 커밋 이동

      Untitled

    • 추가 커밋 진행 상태

      Untitled

병합 위치

깃의 merge 명령어는 브랜치를 병합한다.

현재 브랜치를 기준으로 다른 브랜치의 모든 커밋을 병합한다.

  • 기준 브랜치로 이동

    Untitled

Fast-Forward 병합 적용

  • merge 명령 수행, 기준은 master 브랜치 이며 병합 대상 브랜치는 feature

      dk@Chiptune gitstudy08 % git merge feature
      업데이트 중 679293d..1ac1f56
      Fast-forward
       index.htm | 4 ++++
       1 file changed, 4 insertions(+)
    
  • merge 후 상황

    Untitled

    • feature 브랜치의 커밋들이 master로 이동함.
  • 깃 로그 확인

      dk@Chiptune gitstudy08 % git log -1
      commit **1ac1f56**a5e37bcd5e5ad2efd66ec6315dae5277e (HEAD -> master, feature)
      Author: Chiptune93 <eoen012@gmail.com>
      Date:   Wed Jun 21 00:48:42 2023 +0900
        
          add menu2
    
  • Fast-Forward 병합은 작업한 브랜치의 시작 커밋을 원본 브랜치 이후의 커밋으로 가리킨다. (1ac1f56)
  • 이는 단순히 커밋 위치를 최신으로 옮기는 것과 비슷하다.

3-way 병합

브랜치 생성과 수정 작업

master 브랜치에서 새 브랜치 hotfix를 생성하여 작업 수행

마스터 변경

hotfix 브랜치에서 master 로 변경하여 다시 추가 작업 수행

공통 조상

위 작업을 마치면 공통 조상인 커밋이 생기고, 브랜치가 총 3개로 나뉘게 되는데

이를 하나로 병합하는 것을 브랜치가 3개 있다고 하여 3-way 병합이라고 한다.

Untitled

병합 커밋

위 처럼 병합을 완료하고 나면 새로운 커밋을 하나 생성 하는데 이를 병합 커밋이라고 한다.

병합 커밋은 부모 커밋이 2개라는 특징이 있다.

병합 메세지

깃은 병합한 후에 새로운 커밋을 하면서 동시에 메세지를 자동 생성한다.

자동으로 작성하는 메세지는 사용자에게 띄워지며, 편집 하거나 하지 않고 저장하면 완료된다.

만약 미리 직접 작성하고 싶다면 git merge {branch-name} --edit 을 하면 된다.

브랜치 삭제

병합 후 삭제

3-way 병합 뒤에는 필요없는 브랜치는 삭제를 해주도록 한다.

git branch -d {branch-name} -d 옵션은 병합을 완료한 브랜치만 삭제 한다.

충돌

충돌이 생기는 상황

같은 위치의 코드를 동시에 수정했기 때문에 발생

실습을 위한 충돌 만들기

새로운 브랜치를 만들어 소스의 일부를 수정.

기존 브랜치에서 이전 브랜치에서 수정한 부분을 내용만 다르게 하여 다시 수정

이후, 병합을 시도 한다.

dk@Chiptune gitstudy08 % git checkout -b footer
새로 만든 'footer' 브랜치로 전환합니다
dk@Chiptune gitstudy08 % git commit -am "edit footer"
[footer 5675ea0] edit footer
 1 file changed, 1 insertion(+), 1 deletion(-)
dk@Chiptune gitstudy08 % git checkout master
'master' 브랜치로 전환합니다
dk@Chiptune gitstudy08 % git commit -am "edit year"
[master bea84a3] edit year
 1 file changed, 1 insertion(+), 1 deletion(-)
dk@Chiptune gitstudy08 % git merge footer
자동 병합: index.htm
충돌 (내용): index.htm에 병합 충돌
자동 병합이 실패했습니다. 충돌을 바로잡고 결과물을 커밋하십시오.
dk@Chiptune gitstudy08 %

충돌이 발생하면, 깃은 ‘merge conflict’를 출력한다. 이때는 자동으로 커밋이 생성되지 않는다.

방금 실행한 병합을 취소할 때는 git merge --abort 를 실행한다.

수동으로 충돌 해결

에디터나 다른 방법으로 소스 내용을 열어서 병합 충돌 내용을 직접 수정한다.

깃에서 나타낸 화살표와 같은 기호까지 전부 클리어하여 해결하고, 커밋을 진행하면 해결된다.

소스 트리에서의 해결방법

충돌 해결 메뉴를 통해 해결한다.

브랜치 병합 여부 확인

어느 브랜치가 병합을 완료한 것인지 확인이 어려울 때는 아래와 같은 방법을 사용한다.

git branch --merged 를 사용하면, 병합한 브랜치와 아닌 브랜치를 구분할 수 있다.

병합이 완료된 브랜치는 * 표시가 나타난다.

병합하지 않은 브랜치는 --no-merged 옵션으로 확인 가능하다.

git branch --no-merged 를 수행한다.

병합하지 않은 브랜치는 -d 옵션으로는 삭제가 불가능 하니 -D 옵션을 사용한다.

리베이스

브랜치를 합치는 방법은 merge 또는 rebase 를 통해 가능하다.

베이스

특정 커밋에서 브랜치를 생성하면, 커밋이 파생되는데 이 때 기준이 된 커밋을 ‘베이스’ 라고 한다.

Untitled

베이스 변경

파생된 브랜치의 기준이 되는 베이스 커밋을 변경하는 것이다.

Untitled

리베이스 vs 병합

병합은 파생된 두 브랜치를 하나로 합치는 과정, 공통 조상 커밋을 찾아야 한다.

공통 조상 커밋은 두 브랜치를 병합하는 베이스 커밋이며 병합하는 두 브랜치는 순차적으로 커밋을 비교하면서 마지막 최종 커밋을 생성한다.

Untitled

반면 리베이스는 두 브랜치를 서로 비교하지 않고 순차적으로 커밋 병합을 시도 한다.

Untitled

리베이스 명령어

git rebase {bracnch-name}

리베이스 병합

리베이스는 병합 기준 브랜치가 merge와 반대이다.

  • merge → 기준 브랜치에 다른 브랜치를 엎는다.(파생을 원본에)

    Untitled

  • rebase → 기준 브랜치를 다른 브랜치에 엎는다.(원본을 파생에)

    Untitled

리베이스 명령이 실행되면, 파생 브랜치의 커밋들은 기준 브랜치의 마지막 커밋으로 재정렬된다.

리베이스 되었는지 확인

리베이스를 하게 되면 베이스 커밋을 변경하여 병합하므로, 커밋의 해시 값이 변경 된다.

리베이스 후 브랜치

리베이스는 커밋 위치를 재조정할 뿐, 브랜치의 HEAD 포인터까지 옮겨주지는 않는다.

따라서, 리베이스 한 후에는 이러한 병합 브랜치의 HEAD를 맞추어야 한다.

리베이스 된 브랜치를 병합해야 한다.

복잡한 트리 모양의 구조가 아니라 선형 구조로 브랜치를 변경 할 수 있다.

리베이스 충돌과 해결

리베이스는 커밋을 하나씩 따라가면서 위치를 재조정한다.

충돌을 수정한 후에는 rebase 명령어와 —continue 옵션을 사용하여 계속 진행 할 수 있다.

git rebase --continue

모든 충돌을 해결하면 리베이스는 종료된다.

이후, 브랜치를 정리하는 작업을 진행한다. 작업하였던 파생 브랜치를 병합하고 종료한다.

rebase 명령어로 커밋 수정

마지막 커밋은 —amend 옵션으로 수정할 수 있다.

이 방법 외에 rebase 명령어도 최종 커밋을 수정할 수 있다.

리베이스는 커밋을 재조정하는 것 외에도 여러 커밋을 한 커밋으로 묶을 수 있다.

이때는 -i 옵션을 사용한다.

git rebase -i HEAD~3 : 3커밋을 하나로 묶기

리베이스 할 때 주의할 점.

저장소를 외부에 공개했다면 공개된 순간부터 커밋은 리베이스를 사용하지 않는 것이 원칙.

공개된 커밋을 리베이스하면 위치와 해시 값이 너무 변경되어 혼란스럽다.

공개된 커밋을 변경할 때는 revert 명령어를 사용한다.


© 2024. Chiptune93 All rights reserved.