관리 메뉴

프로그래밍

[Git] 왜 사람들은 git을 어렵다고 느낄까?(Merge와 Conflict) 본문

Git

[Git] 왜 사람들은 git을 어렵다고 느낄까?(Merge와 Conflict)

시케 2025. 5. 20. 11:53
728x90
반응형

왜 사람들은 git을 어렵다고 느낄까?

git을 사용하면서 어렵다고 느끼는 지점은 "merge를 하려고 할때" 찾아오는것 같다

그럼 왜 Merge를 할때면 git의 작동방식을 이해하기가 힘든지

도대체 conflict(충돌)은 언제 일어나는지

git은 무엇을 기준으로 병합판단을 하는지에 대해서 알아보자

Merge

먼저 Merge는 병합이다

내가 가진 여러개의 브랜치, 거기에 따른 커밋기록을 다시 하나의 브랜치를 합친다

변경사항을 버전 관리를 하다가 해당 사항들을 합쳐주어서 하나의 버전(소스코드)를 만들 수 있다

보통 여러명이 각각 기능 개발을 하고 완성이 되면 개발 브랜치에 합치는 경우를 예시로 들 수 있다

 

브랜치 구조

        C  ← 병합 대상 (ex: feat_a)
       /
A — B
       \
        D  ← 현재 브랜치 (ex: main)

main 브랜치

LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'

main에서 파생된 feat_a 브랜치

LANGUAGE_CODE = 'kr'	# 변경
TIME_ZONE = 'UTC'

feat_a -> main 병합 결과

LANGUAGE_CODE = 'kr'	# 변경 적용
TIME_ZONE = None

이런 간단한 경우는 쉽게 이해할 수 있을것이다

하지만 브랜치가 많아지고 Conflict가 난다면 복잡해진다

conflict

Conflict는 충돌이다

git이 자동으로 변경사항을 병합하지 못했을 경우 발생한다

주로 같은 지점을 변경할 경우 발생한다

 

main 브랜치

LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'

main에서 파생된 feat_a 브랜치

LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'ABC'	# 변경함

main에서 수정

LANGUAGE_CODE = 'en-us'
TIME_ZONE = None	# 변경함

수정된 main 브랜치와  feat_a 브랜치 병합시도

-> 충돌 발생

 

같은 곳을 다른 내용으로 수정했기에 git은 "둘 중에 뭐가 맞아?"라고 하며 충돌이 발생하게 된다

만약 다른 줄을 수정했다면 충돌은 발생하지 않았을 것이다

상황 Git 판단 결과
양쪽 모두 변경 안함 그대로 둠 ✅ 유지
한쪽만 변경 변경한 쪽 반영 ✅ 자동 병합
양쪽 모두 다르게 변경 충돌 발생 ⚠️ 수동 해결 필요

Target 브랜치와 Source 브랜치

Target 브랜치는 우리가 흔히 말하는 main이고

Source 브랜치는 feature 브랜치가 될것이다

병합은 Target 브랜치에 Source 브랜치의 변경사항을 적용한다

 

그럼 두 브랜치가 바뀌면 병합의 결과가 달라질까?

-> 달라지지 않는다

 

git은 변경한쪽의 내용을 따른다

이때 변경한 브랜치가 Target 브랜치든 Source 브랜치든 상관없이 변경한쪽의 내용을 무조건 따른다

그렇기에 두 브랜치의 변경사항을 모두 반영할 수 있는것이다

 

★Merge는 덮어쓰기가 아니다

병합을 하는 원리는 공통 조상을 파악 후 비교하여 변경을 적용하는것이다

만약 덮어쓰기라면 무조건 최신 변경사항을 적용할 것이고

그럼 충돌이 날 일은 없을 것이다

Merge 예시

브랜치가 여러개 파생된 예시를 보고 Merge의 원리를 이해해보자

 

브랜치 구조

main 브랜치
A — B — C — D(main 브랜치 HEAD)

사용자 E 브랜치 (B에서 시작)
        ↘︎
          E(feature 브랜치)

다른 사용자가 최신 변경 사항(D)을 반영하지 않고 과거 시점(B)에서 브랜치를 파서 작업한 경우이다

꽤 자주 발생할 수 있는 상황이다

 

main 브랜치의 Head인 D사용자 E 브랜치를 병합한다면 어떻게 될까?

(보통은 과거 시점 브랜치를 보유한 작업자가 pull을 받아 충돌을 해결 후 다시 Merge하는 방법을 추천)

 

먼저 두 브랜치의 공통 조상main 브랜치의 B시점이다

해당 시점을 기준으로 비교하여 병합이 실행될것이다

 

main 브랜치 B

A = 1
B = 2
C = 3

main 브랜치 C

A = 1          # 변경 없음
B = 2          # 변경 없음
C = 4          # C 변경

main 브랜치 D

A = 1          # 변경 없음
B = 3          # B 변경
C = 4          # C는 C 브랜치에서 이미 바뀐 걸 그대로 유지

B시점에서 파생된 브랜치 E

A = 0          # A 변경
B = 2          # 변경 없음
C = 3          # 변경 없음 (즉, B의 상태와 동일)
D = 10         # 새 항목 추가

병합 판단 기준

공통 조상(B)에서 무엇이 변경되었는지를 기준으로 판단한다

항목 B(공통 조상) D 브랜치 E 브랜치 병합결과
A 1 1 (변경 X) 0 (변경 O) 0 ← E만 변경
B 2 3 (변경 O) 2 (변경 X) 3 ← D만 변경
C 3 4 (변경 O) 3 (변경 X) 4 ← D만 변경
D - - 10 (추가) 10 ← E만 추가

 

최종 병합 결과

A = 0      # E에서만 변경 → 반영됨
B = 3      # D에서만 변경 → 반영됨
C = 4      # D에서만 변경 → 반영됨
D = 10     # E에서 새로 추가됨 → 반영됨

만약 단순 덮어쓰기였다면 Source 브랜치인 E 브랜치의 내용이 우선 반영되고

E브랜치가 갖고 있지 않은 브랜치 C, D의 변경사항은 날라갔을 것이다

하지만 공통 조상 기준으로 비교하여 반영하므로 브랜치 C, D의 변경사항 또한 반영되었다

공통 조상 (Base)         현재 브랜치 (HEAD)            병합 대상 (Other)
       B                        D                          E
    ---------               ---------               	---------
    A = 1                   A = 1           		A = 0   ← 변경됨
    B = 2                   B = 3   ← 변경됨		B = 2
    C = 3                   C = 4   ← 변경됨		C = 3
    (없음)                  (없음)          		D = 10  ← 추가됨
        A
        │
        B  ← 공통 조상 (Merge 기준점)
       / \
      /   \
     C     E
      \   /
       D ← 현재 main HEAD (여기에 merge E)

정리

  • Merge는 덮어쓰기가 아니다
  • Merge의 기준은 가장 최신의 공통 조상이다
  • 같은 곳의 변경이 동시에 일어날 경우 Conflict가 발생한다

 

728x90
반응형
Comments