feature 브랜치를 main 위로 rebase하다 충돌이 났을 때, feature의 변경을 지키려고 git checkout --ours를 고르면 그 커밋이 오류 없이 사라질 수 있습니다. rebase에서 ours는 작업하던 브랜치가 아니기 때문입니다. 이 글을 읽고 나면 충돌 중에 어느 쪽이 어느 값인지 확인하고, 사라진 커밋을 되찾고, 파일을 통째로 고르는 명령이 다른 변경까지 되돌리는 경우를 피할 수 있습니다.
예제는 실제 프로젝트가 아니라 스크립트로 돌린 것입니다. 2026-11-01에 macOS 27.0.1의 git 2.54.0(Apple Git-157)으로 실행했습니다. 스크립트는 임시 폴더에 저장소를 새로 만들고 전역 설정을 무시하며, 커밋 시각을 고정해 해시가 실행마다 같습니다. 읽는 분의 해시는 다를 수 있습니다. 파일과 값은 가상의 예입니다. 다른 git 버전, 다른 운영체제, GUI 도구, git pull --rebase는 실행하지 않았습니다.
같은 충돌인데 위아래가 뒤집힌다
기준 커밋에서 timeout 한 줄을 main은 10으로, feature는 60으로 바꿉니다. 따라 해 보려면 빈 폴더에서 시작하십시오.
git init -b main repo
cd repo
echo 'timeout=30' > config.txt
git add config.txt
git commit -m 'base: timeout 30'
git switch -c feature
echo 'timeout=60' > config.txt
git commit -am 'feature: timeout 60'
git switch main
echo 'timeout=10' > config.txt
git commit -am 'main: timeout 10'
git switch feature
feature에서 git merge main을 실행하면 충돌 표시의 HEAD 쪽은 feature의 값 60이고, --ours를 고르면 파일은 60으로 남았습니다. 이름 그대로입니다. 저장소를 새로 만들어 git rebase main을 실행하면 같은 자리의 HEAD 쪽은 main의 10이고, feature의 값 60은 아래쪽으로 내려갔습니다.

충돌 중에는 번호로도 확인할 수 있습니다. git 문서에 따르면 --ours는 stage 2를, --theirs는 stage 3을 꺼냅니다. 아래 명령은 stage 2가 10, stage 3이 60이라고 보여 주었고, REBASE_HEAD는 지금 멈춘 feature 커밋을 가리켰습니다.
git log -1 --oneline REBASE_HEAD
git show :2:config.txt
git show :3:config.txt
이유는 rebase가 일하는 방식에 있습니다. git-rebase 문서는 rebase가 작업 브랜치의 커밋을 하나씩 upstream 위에 다시 올리는 일이어서, 충돌 때 ours는 upstream부터 지금까지 올린 결과이고 theirs는 작업 브랜치라고 적습니다. 두 쪽이 뒤바뀐다는 말도 그대로 있습니다. git-checkout 문서도 rebase와 git pull --rebase에서 ours와 theirs가 뒤바뀐 것처럼 보일 수 있다고 적습니다.
개발 노트
rebase에서는 ours가 작업 브랜치가 아니다
feature 브랜치에 있고 main과 충돌이 났을 때
git merge main
- HEAD와 ours: feature, 작업 브랜치
- theirs: main
git rebase main
- HEAD와 ours: main과 지금까지 올린 feature 커밋
- theirs: 지금 올리는 feature 커밋 하나(REBASE_HEAD)
rebase 도중과 끝난 뒤에 볼 것
git log --oneline main..feature- 고르기 전: 충돌 표시의 값과 REBASE_HEAD를 본다
- checkout --ours와 --theirs는 파일을 통째로 바꾼다
- 끝난 뒤: 커밋 수와 git diff main feature를 본다
ours와 theirs의 뜻은 git 문서의 설명이고, git 2.54.0(macOS 27.0.1)에서 2026-11-01에 실행해 같은 결과를 보았다.
--ours로 넘어가면 커밋이 조용히 사라질 수 있다
이 상태에서 스크립트는 feature의 값을 지켜 줄 것 같은 이름의 --ours를 고르고 git add, git rebase --continue를 실행했습니다. 파일은 main의 10이 되었고, 출력은 성공 한 줄뿐이었습니다. 그런데 feature의 기록에는 그 커밋이 없고 main과 같았습니다. --continue는 경고를 내지 않았습니다. 단서는 한 단계 앞에 있습니다. git add 직후 git status를 실행하면 nothing to commit, working tree clean이라고 나왔습니다.

파일이 HEAD와 같아져 올릴 변경이 남지 않았고, 그래서 커밋이 버려진 것으로 보입니다. 이 설명은 실행 결과를 보고 판단한 것입니다. git-rebase 문서의 --empty는 다시 올린 뒤 비게 된 커밋을 기본으로 버린다고 적지만, 그 설명의 괄호 안 이유는 이미 upstream에 있는 변경이고 충돌을 풀다 비게 된 경우를 따로 적지는 않습니다. 스크립트는 --empty=stop도 시도했습니다. --ours와 git add로 충돌을 풀고 --continue를 실행한 경우에는 git 2.54.0에서 멈추지 않고 똑같이 커밋이 빠졌습니다. 손으로 고르지 않는 -X ours와 함께 주면 같은 옵션이 The previous cherry-pick is now empty라는 문구와 함께 멈췄습니다.
git rebase -X ours main으로도 커밋이 빠졌습니다. 문서는 -X에서도 ours와 theirs가 뒤바뀐다고 적습니다. 이때는 dropping 172033b…로 시작하고 patch contents already upstream으로 끝나는 줄이 나왔습니다. main에 timeout=60이 없었으니, 이 문구만 보고 같은 변경이 이미 올라가 있다고 믿으면 안 됩니다.
확인과 복구는 이렇게 합니다. 첫 줄이 아무것도 출력하지 않으면 main에 없는 feature 커밋이 하나도 남지 않은 것입니다.
git log --oneline main..feature
git log -1 --oneline ORIG_HEAD
git log -1 --oneline feature@{1}
git reset --hard ORIG_HEAD
ORIG_HEAD와 feature@{1} 모두 이전 끝인 172033b를 가리켰고, reset 뒤 파일은 60으로 돌아왔습니다. 문서는 rebase 도중 git reset 같은 명령을 쓰면 끝날 때 ORIG_HEAD가 그 커밋을 가리킨다고 보장할 수 없고, 이전 끝은 현재 브랜치의 reflog로 찾을 수 있다고 적습니다. reset --hard는 커밋하지 않은 변경을 버리고 추적하지 않는 파일을 덮어쓸 수 있으므로 먼저 작업 트리를 확인하십시오. 이 명령은 rebase 전체를 되돌리기도 합니다. 추가로 돌린 스크립트에서는 rebase 뒤에 만든 커밋도, 앞선 멈춤에서 손으로 푼 충돌 결과도 브랜치에서 빠졌고, 새 커밋을 만든 뒤에는 feature@{1}이 이전 끝을 가리키지 않았습니다. 두 로그 줄이 모두 이전 끝을 보여 주고, 그 뒤로 커밋한 것이 없고, 앞선 멈춤을 손으로 풀지 않았을 때만 실행하십시오. 아니면 먼저 git reflog로 커밋을 찾으십시오. 이 실행들에서 둘 다 거기에 남아 있었습니다.
--theirs는 맞는 쪽이지만 파일을 통째로 고른다
그러면 rebase에서는 --theirs를 쓰면 될까요? 파일 전체의 충돌이 한 곳이고 다른 변경이 없을 때는 feature 커밋이 60으로 남았습니다. 하지만 main이 같은 파일의 다른 줄도 바꿨다면 다릅니다. main이 timeout=10과 함께 멀리 떨어진 줄을 retries=2로 바꾼 저장소에서 실행했습니다.
충돌 표시를 보면 충돌은 첫 줄뿐이고 retries=2는 이미 합쳐져 있었습니다. 여기서 --theirs를 고르자 파일이 feature 커밋 판으로 통째로 바뀌어 retries=1이 되었습니다. 한 줄만 바꾼 커밋이 두 줄을 바꾸는 커밋이 되었고, main의 변경을 말없이 되돌렸습니다. --continue의 출력에서 단서가 된 것은 2 insertions(+), 2 deletions(-) 한 줄이었습니다.
저장소를 같은 상태로 새로 만들어 git rebase -X theirs main을 실행하면 timeout=60에 retries=2가 남았습니다. 문서는 -X의 ours가 충돌한 부분만 그쪽으로 정하고 충돌하지 않는 다른 쪽 변경은 결과에 반영한다고 적고, theirs는 그 반대라고 적습니다. 이진 파일은 내용 전체를 고른 쪽에서 가져온다고도 적습니다. 다만 이 실행에서 -X는 멈추지 않고 충돌한 부분을 한쪽으로 정했으므로, 어떤 값이 버려졌는지 보려면 결과를 따로 봐야 합니다. 늘 멈추지 않는 것은 아닙니다. 따로 돌린 스크립트에서 main이 파일을 지우고 feature가 고친 수정/삭제 충돌은 -X theirs에서도 멈췄습니다.

두 번째 커밋부터 ours에는 feature의 작업도 들어 있다
rebase의 ours를 그냥 main이라고 외워도 틀릴 때가 있습니다. feature에 커밋을 하나 더 두어 60 다음 90으로 바꾸게 했습니다. 스크립트가 첫 번째 멈춤에서 충돌을 45로 풀고 계속하자 두 번째 커밋에서 다시 멈췄고, 이때 stage 2는 main의 10이 아니라 45였습니다. HEAD에는 main 위에 새 해시 b42c61e로 올라간 feature의 첫 커밋이 있었습니다.
이때 git rebase --abort를 실행하니 기록과 파일이 시작 전으로 돌아왔고, 45로 푼 결과도 함께 없어졌습니다. 헷갈리면 고르지 말고 그만두는 길도 있습니다.

rebase 충돌에서는 --ours와 --theirs라는 이름을 믿고 고르지 말고, 충돌 표시의 값과 REBASE_HEAD를 본 다음 남길 줄을 직접 고치십시오. 끝나면 git log --oneline main..feature의 커밋 수를 시작 전과 비교하십시오. 같은 변경이 이미 main에 있으면 줄어드는 것이 정상일 수 있으니, 줄어든 만큼 이유를 말할 수 있으면 됩니다. 커밋 수가 그대로여도 안심할 수는 없습니다. 위 --theirs 경우에는 하나 그대로인데 main의 변경이 되돌려졌고, 추가로 돌린 실행에서 다른 파일도 추가한 커밋은 하나 그대로인데 timeout 변경이 사라졌습니다. 그래서 git diff main feature도 함께 읽고 브랜치가 바꾸려던 내용과 맞는지 보십시오. 두 경우 모두 여기에서 드러났습니다. 이 권장은 위 실행과 문서에서 끌어낸 판단입니다.
이 기록에 대화를 더해 주세요.
궁금한 점, 다른 접근, 직접 해 본 결과를 나눠 주세요.
로그인 상태 확인 중…
댓글을 불러오는 중…