Git 기초편 4편 — merge와 충돌 해결

2026. 5. 10. 18:08·블로그, 컴퓨터/DevOps

git 연재글 썸네일

"Git을 공부하면서 쓰는 시리즈" 4편입니다.
1편: git init · 2편: 브랜치 · 3편: git log 트리


시작하면서

3편까지 따라왔다면 지금 이런 상태입니다.

* c1d2e3f (feature/login) 로그인 페이지 초안 추가
* a9b3c12 (HEAD -> main) README에 프로젝트 설명 추가
* 3f2a1b4 첫 번째 커밋: README 추가

feature/login에서 작업을 마쳤습니다. 이제 이걸 main에 합쳐야 합니다. 그게 merge입니다.

그런데 merge를 찾아보다 보면 "fast-forward", "merge commit", "conflict" 같은 단어가 나옵니다. 처음엔 다 뭔가 싶었습니다. 이번 편에서 하나씩 짚어봅니다.


git merge 기본 사용법

main 브랜치로 이동한 다음 merge합니다.

git switch main
git merge feature/login
Updating a9b3c12..c1d2e3f
Fast-forward
 login.md | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 login.md

Fast-forward라는 말이 보입니다. 이게 뭔지 먼저 이해해야 다음이 편합니다.


Fast-forward merge

현재 상태를 그림으로 보면 이렇습니다.

main:          C1 ── C2
                         \
feature/login:            C3

main은 C2에 머물러 있고, feature/login은 C3까지 앞서 있습니다. 그리고 C3는 C2의 직계 자손입니다. 중간에 다른 갈래가 없어요.

이 경우 Git은 굳이 새로운 merge 커밋을 만들지 않습니다. 그냥 main 포인터를 C3까지 앞으로 당기면 끝입니다.

main:          C1 ── C2 ── C3
                               ↑
                          (HEAD, main, feature/login)

포인터만 이동한 거라서 "빨리감기(Fast-forward)"라고 부릅니다. merge 커밋이 따로 생기지 않습니다.

git lg로 확인해보면 이렇습니다.

* c1d2e3f (HEAD -> main, feature/login) 로그인 페이지 초안 추가
* a9b3c12 README에 프로젝트 설명 추가
* 3f2a1b4 첫 번째 커밋: README 추가

main과 feature/login이 같은 커밋을 가리키고 있습니다.


Merge commit — 두 흐름이 만날 때

이번엔 다른 경우를 만들어봅니다. feature/login을 작업하는 동안 main에도 새 커밋이 생긴 상황입니다.

# main에서 다른 파일 수정
git switch main
echo "공지사항 추가" > notice.md
git add notice.md
git commit -m "공지사항 파일 추가"

이제 구조가 이렇게 됩니다.

main:          C1 ── C2 ── C4
                         \
feature/login:            C3

main도 C4로 앞으로 나갔고, feature/login도 C3이 있습니다. 두 브랜치가 C2에서 각자 다른 방향으로 갈라진 거예요.

이 상태에서 merge하면 fast-forward가 불가능합니다. 단순히 포인터를 당기는 것만으로는 두 흐름을 합칠 수 없으니까요. Git은 두 브랜치를 하나로 엮는 merge 커밋을 새로 만듭니다.

git switch main
git merge feature/login
Merge made by the 'ort' strategy.
 login.md | 1 +
 1 file changed, 1 insertion(+)

git lg로 보면 이렇게 됩니다.

*   e7f8a9b (HEAD -> main) Merge branch 'feature/login'
|\
| * c1d2e3f (feature/login) 로그인 페이지 초안 추가
* | b3c4d5e 공지사항 파일 추가
|/
* a9b3c12 README에 프로젝트 설명 추가
* 3f2a1b4 첫 번째 커밋: README 추가

|\와 |/로 갈라졌다가 합쳐지는 모양이 보입니다. e7f8a9b가 두 브랜치를 묶어주는 merge 커밋입니다. 부모가 두 개인 특수한 커밋이에요.


충돌(Conflict)이란

여기까지는 각 브랜치가 서로 다른 파일을 건드렸기 때문에 Git이 자동으로 합쳐줬습니다.

문제는 두 브랜치가 같은 파일의 같은 줄을 서로 다르게 수정했을 때입니다. Git이 "어느 쪽이 맞는지 나는 모르겠다"고 판단하면 충돌이 납니다.

충돌 상황을 직접 만들어봅니다.

# main에서 README.md 수정
git switch main
echo "main 브랜치에서 수정한 내용" > README.md
git add README.md
git commit -m "main에서 README 수정"

# feature/login 브랜치에서도 같은 파일 수정
git switch feature/login
echo "feature 브랜치에서 수정한 내용" > README.md
git add README.md
git commit -m "feature에서 README 수정"

# main으로 돌아와서 merge 시도
git switch main
git merge feature/login
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.

CONFLICT가 났습니다. merge가 중단된 상태입니다.


충돌 마커 읽는 법

충돌이 난 파일을 열어보면 이런 내용이 들어있습니다.

<<<<<<< HEAD
main 브랜치에서 수정한 내용
=======
feature 브랜치에서 수정한 내용
>>>>>>> feature/login

세 가지 기호가 각각 영역을 나눕니다.

  • <<<<<<< HEAD ~ ======= : 현재 브랜치(main)의 내용
  • ======= ~ >>>>>>> feature/login : 합치려는 브랜치(feature/login)의 내용

Git이 "여기 둘 중에 뭘 쓸지 결정해줘"라고 표시해둔 겁니다.


충돌 해결하기

해결 방법은 단순합니다. 파일을 직접 열어서 원하는 내용으로 고치고, 충돌 마커를 전부 지우면 됩니다.

예를 들어 두 내용을 모두 남기기로 결정했다면 이렇게 수정합니다.

main 브랜치에서 수정한 내용
feature 브랜치에서 수정한 내용

<<<<<<<, =======, >>>>>>> 세 줄이 남아있으면 안 됩니다. 이 마커들은 결과물이 아니라 Git이 임시로 표시해둔 안내선이니까요.

수정이 끝나면 add하고 commit합니다.

git add README.md
git commit

커밋 메시지 입력창이 열립니다. 기본으로 Merge branch 'feature/login'이 채워져 있는데, 그대로 저장해도 됩니다.


충돌 중에 현재 상태 확인하기

충돌이 난 상태에서 git status를 치면 어느 파일이 문제인지 알 수 있습니다.

git status
On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   README.md

no changes added to commit

both modified가 충돌난 파일입니다. 여러 파일에서 동시에 충돌이 나는 경우도 있는데, 이 목록을 보면서 하나씩 해결하면 됩니다.


merge를 취소하고 싶다면

충돌을 해결하다가 일단 원상복구하고 싶을 때가 있습니다. 이럴 때는 --abort를 씁니다.

git merge --abort

merge 시작 전 상태로 돌아갑니다. 충돌 마커도 전부 사라집니다.


fast-forward와 merge commit, 어느 게 낫나요?

사람마다 의견이 좀 다른 주제입니다.

fast-forward를 선호하는 쪽 — 히스토리가 깔끔하게 일직선으로 이어집니다. 나중에 git log로 볼 때 단순해서 읽기 편합니다.

merge commit을 선호하는 쪽 — "이 기능이 언제 합쳐졌는지"가 커밋 기록에 남습니다. 브랜치 단위로 작업 흔적이 보존되기 때문에 나중에 추적하기 쉽습니다.

fast-forward 상황에서도 merge commit을 강제로 만들고 싶다면 --no-ff 옵션을 씁니다.

git merge --no-ff feature/login

어느 쪽이 정답이라기보다는 팀의 규칙에 따르는 편이 좋습니다. 혼자 작업할 때는 취향 차이입니다.


이번 편 정리

상황 Git의 동작
합치려는 브랜치가 현재 브랜치의 직계 자손 Fast-forward — 포인터만 이동, 새 커밋 없음
두 브랜치가 각자 다른 커밋을 가짐 Merge commit 생성 — 부모가 두 개인 새 커밋
같은 파일의 같은 줄을 서로 다르게 수정 Conflict — 사람이 직접 해결해야 함

충돌 해결 순서

  1. 충돌난 파일 열기
  2. <<<<<<<, =======, >>>>>>> 마커 확인
  3. 원하는 내용으로 직접 편집, 마커 모두 제거
  4. git add <파일>
  5. git commit

명령어 모음

명령어 하는 일
git merge <브랜치> 현재 브랜치에 지정 브랜치를 합치기
git merge --no-ff <브랜치> fast-forward 상황에서도 merge commit 생성
git merge --abort 진행 중인 merge 취소, 원상복구

다음 편 예고

merge를 배웠으니 이제 로컬에서 만든 걸 GitHub 같은 원격 저장소에 올리고 싶어집니다. 다음 편에서는 git remote, push, pull, fetch를 다룹니다. 원격 저장소와 로컬이 어떻게 연결되는지, pull이 사실 두 동작의 합성이라는 것도 알아봅니다.


이 시리즈의 다른 글

  • [기초편 1편] git init과 첫 커밋까지
  • [기초편 2편] 브랜치, 어렵지 않아요
  • [기초편 3편] git log를 트리로 보는 법
  • [기초편 5편] 원격 저장소 연결하기
반응형
저작자표시 비영리 변경금지 (새창열림)

'블로그, 컴퓨터 > DevOps' 카테고리의 다른 글

Git 기초편 6편 — .gitignore 제대로 쓰기  (0) 2026.05.11
Git 기초편 5편 — 원격 저장소 연결하기  (0) 2026.05.11
Git 기초편 3편 — git log를 트리로 보는 법  (1) 2026.05.10
Git 기초편 2편 — 브랜치, 어렵지 않아요  (0) 2026.05.09
Git 기초편 1편 — git init과 첫 커밋까지  (0) 2026.05.09
'블로그, 컴퓨터/DevOps' 카테고리의 다른 글
  • Git 기초편 6편 — .gitignore 제대로 쓰기
  • Git 기초편 5편 — 원격 저장소 연결하기
  • Git 기초편 3편 — git log를 트리로 보는 법
  • Git 기초편 2편 — 브랜치, 어렵지 않아요
생각사람
생각사람
지극히 사적인 연구실
  • 생각사람
    생각사람의 별장
    생각사람
  • 전체
    오늘
    어제
    • 분류 전체보기 (207) N
      • 금융 (57)
        • 주식 공부 (11)
        • 파생상품 입문 (17)
        • 파생상품 기초 (15)
        • 파생상품 실전 (14)
      • 블로그, 컴퓨터 (83) N
        • 프로그래밍 (16)
        • DevOps (8)
        • AI, RL, ML, ... (5)
        • 애드센스, SEO (23)
        • 임베디드 (3)
        • 컴퓨터 관련 (7)
        • Cheatsheets (21) N
      • 다른 공부들 (67)
        • 읽고 쓰기 (18)
        • 수학 (15)
        • 물리 (9)
        • 사진 공부 (25)
  • 인기 글

  • 최근 글

  • 최근 댓글

  • 태그

    스트랭글
    version control
    GIT
    슈뢰딩거 방정식
    코딩
    github
    파생상품
    선물 옵션
    공업수학
    AI
    스트래들
    깃허브
    Kreyszig
    오펜하이머
    구글 애드센스
    독후감
    소니 a6000
    옵션 투자
    c
    선형대수학
    c++
    벡터
    옵션
    행렬
    웹크롤러
    깃
    프로그래밍
    양자역학
    CheatSheet
    cmake
  • hELLO· Designed By정상우.v4.10.6
생각사람
Git 기초편 4편 — merge와 충돌 해결
상단으로

티스토리툴바