마루옵스서버 · 네트워크 · AI 기술 노트

소개문의

[Git·GitOps 09] 충돌 해결하기: 공통 조상과 3-way merge

노트북과 메모 도구를 위에서 본 모습

참고 사진 · 노트북과 메모 도구를 위에서 본 모습 · 사진: Aleksi Tappura a / 원본 / CC0 · 목록용 크기 조정

충돌은 Git이 어느 쪽의 의도를 선택해야 할지 결정할 수 없다는 뜻입니다. 파일이 망가졌다는 의미는 아니에요. 같은 설정값을 서로 다르게 바꾼 상황을 만들어, 사람이 판단해야 할 지점과 Git이 처리하는 지점을 나눠 보겠습니다.

기존 프로젝트를 건드리지 않도록 conflict-lab이라는 새 저장소를 사용합니다. Linux Bash 또는 Git Bash에서 실행하며 작성자 정보는 앞에서 설정한 상태를 전제로 합니다.

Git·GitOps 전체 연재 · 09 / 24

이 글의 목차

1. 같은 출발점에서 다른 값을 만든다

cd ~/git-lab
mkdir conflict-lab
cd conflict-lab
git init -b main
printf 'timeout=30\n' > app.conf
git add app.conf
git commit -m "Set initial timeout"
git switch -c feature/long-timeout
printf 'timeout=60\n' > app.conf
git commit -am "Increase timeout for slow requests"
git switch main
printf 'timeout=45\n' > app.conf
git commit -am "Adjust timeout for the default service"
git merge feature/long-timeout

commit -am은 이미 추적하는 파일의 수정과 삭제를 스테이징해 커밋합니다. 새 파일은 자동으로 담지 않으므로 첫 커밋에서는 별도의 add를 썼습니다. 마지막 merge는 이 예제에서 충돌을 내는 것이 정상입니다.

Git은 공통 조상과 양쪽 결과를 비교한다

일반적인 갈라진 이력의 병합에서는 공통 조상, 현재 브랜치, 합칠 브랜치의 세 상태를 사용합니다. 공통 조상의 timeout=30이 한쪽에서는 45, 다른 쪽에서는 60으로 바뀌었습니다. Git은 값의 문법을 알아도 서비스가 원하는 정책까지 알 수는 없습니다.

git status
git diff -- app.conf
git ls-files -u
cat app.conf

파일에는 아래와 같은 충돌 표시가 들어갑니다. 표시 사이의 두 줄을 전부 남긴 채로 커밋하면 설정 자체가 잘못될 수 있습니다.

<<<<<<< HEAD
timeout=45
=======
timeout=60
>>>>>>> feature/long-timeout

HEAD 쪽은 현재 체크아웃한 main의 내용입니다. rebase에서는 ours와 theirs의 의미가 직관과 다르게 보일 수 있으므로 “내 것 선택” 버튼만 외우지 않습니다. 비교 대상과 실제 최종 파일을 함께 읽으세요.

2. 의도한 최종 내용을 작성한다

이 실습에서는 기본 서비스도 60초를 쓰기로 결정했다고 가정합니다. 이 값은 서비스 성능을 측정해 권장하는 수치가 아니라 충돌 해결을 위한 예제입니다.

printf 'timeout=60\n' > app.conf
git add app.conf
git diff --staged
git diff --staged --check
git merge --continue
git log --oneline --graph --decorate -8

add는 이 파일의 충돌을 해결했다는 표시도 합니다. merge --continue에서 편집기가 열리면 병합 이유를 확인하고 저장합니다. 편집기를 쓸 수 없는 자동 실습에서는 git commit -m "Resolve timeout policy"로 병합 커밋을 남길 수도 있습니다.

실제 애플리케이션에서는 설정 문법 검사와 테스트를 실행한 뒤 공유합니다. 충돌 표시를 없앴다는 사실은 프로그램 동작이 맞다는 증거가 아닙니다. 두 변경의 요구사항을 모두 만족하는 세 번째 결과가 필요할 때도 있어요.

병합을 취소하고 다시 준비할 때

# Only while a merge is in progress:
git merge --abort
git status

이 명령은 이미 커밋한 병합을 되돌리는 명령이 아닙니다. merge 전에 미커밋 수정이 있으면 원래 상태를 완전히 재구성하기 어려운 경우도 있으므로, 시작 전에 작업 트리를 정리하는 이유가 됩니다.

같은 파일의 서로 다른 줄이라도 형식 변경과 기능 변경이 겹치면 리뷰가 어려워집니다. 대규모 자동 포맷과 동작 수정을 별도 커밋이나 PR로 나누고, 오래 열린 브랜치를 줄이면 충돌의 판단 범위를 작게 유지할 수 있습니다. 세부 동작은 git merge의 충돌 설명, rebase 중 선택 방향은 git restore에서 확인할 수 있습니다.

이전 글 · [Git·GitOps 08] 브랜치 만들고 합치기: switch·merge와 fast-forward · 다음 글 · [Git·GitOps 10] 원격 저장소 연결하기: clone·fetch·pull·push · 연재 목록과 예제 파일

댓글

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

닉네임·이메일·댓글 내용·IP 주소·브라우저 정보는 댓글 게시 및 관리에 사용됩니다. 이메일과 접속 정보는 공개 댓글에 표시하지 않습니다. 개인정보 요청은 운영자 이메일로 보내 주세요. 개인정보처리방침