BlueByte
unrelated historiesFixed

git: fatal: refusing to merge unrelated histories

작성 Haneul Seo2026년 8월 24일 업데이트5 min

안녕하세요, BlueByte입니다. pull이 방금 "refusing to merge unrelated histories"로 멈췄다면, 깨진 게 아닙니다 — git이 무관한 두 프로젝트를 실수로 엮지 않게 막아주는 것입니다. 오늘은 두 쪽이 정말 같은 프로젝트인지 확인한 뒤, 그것을 허용하는 플래그 하나를 켜는 순서로 가보겠습니다.

이 메시지가 뜻하는 것

pull이나 merge가 이렇게 멈춥니다:

fatal: refusing to merge unrelated histories

두 쪽이 공통 조상을 공유하지 않습니다. 무관한 히스토리를 합치는 건 대개 실수라 git이 거부합니다 — 하지만 정말 원하는 경우엔 플래그 하나로 허용됩니다. 깨진 게 아니라 안전장치입니다.

두 히스토리에 공통 커밋이 없는 이유

Git 2.9부터 git merge와 git pull은 공통 커밋이 없는 두 히스토리 결합을 거부합니다. 알아볼 수 있는 몇 상황:

  • 로컬 폴더에 git init 후 커밋했는데, 이미 자체 초기 커밋이 있는 리모트를 연결. 두 초기 커밋이 무관.
  • 별개 저장소 둘을 하나로 병합.
  • --orphan으로 브랜치를 강제 생성한 뒤 다시 병합하려 함.
  • 저장소를 처음부터 다시 만들고(.git 삭제 후 git init) 옛 리모트를 pull — 이제 무관해 보임.

양쪽이 같은 프로젝트인지 먼저 확인

병합을 눈감고 허용하지 말고, 양쪽 로그를 보고 합치려는 그 프로젝트가 맞는지 확인하세요:

git log --oneline -5 HEAD
git log --oneline -5 origin/main

두 로그가 명백히 같은 프로젝트가 두 번 시작된 거면 병합해도 안전합니다. origin/main이 완전히 다른 프로젝트면 멈추세요 — 엉뚱한 리모트를 병합하려는 것입니다. git merge-base HEAD origin/main으로 공유 커밋이 정말 없는지도 확인할 수 있습니다(무관하면 아무것도 안 찍힘).

확신이 서면 병합을 허용하기

히스토리가 합쳐질 게 맞다고 확인했으면 명시적으로 허용:

git pull origin main --allow-unrelated-histories

이미 fetch했다면:

git merge origin/main --allow-unrelated-histories

충돌을 평소처럼 해결하고 커밋합니다. 두 히스토리가 병합 커밋 하나에서 이어집니다.

실제 사례: 리모트에 있던 README

git init으로 로컬 프로젝트를 만들고 세 커밋을 한 뒤, 호스트에 빈 저장소를 만들었는데 — 생성 시 README가 추가되며 자체 초기 커밋이 생겼습니다. git pull origin main이 "refusing to merge unrelated histories"로 실패합니다. 양쪽 git log가 같은 프로젝트가 두 번 시작된 것을 보여주고 git merge-base가 아무것도 안 찍어 공유 커밋 없음을 확인합니다. git pull origin main --allow-unrelated-histories를 실행하고 사소한 README 충돌을 해결한 뒤 커밋합니다. 그래프가 이제 세 커밋을 호스트의 README 커밋에 잇는 병합 커밋 하나를 보여줍니다.

히스토리가 실제로 이어졌는지 확인

두 줄기가 만났고 파일이 다 있는지 확인:

git log --oneline --graph -8

두 히스토리가 만나는 병합 커밋 하나가 보이고 그 아래로 양쪽 커밋이 모두 도달 가능해야 합니다.

다시 겪지 않으려면

로컬 폴더가 기존 리모트를 추적하게 하려면 git init + 리모트 추가 대신 리모트를 먼저 clone하고 파일을 복사해 넣으세요 — 그러면 처음부터 하나의 공유 히스토리라 이 문제가 안 생깁니다. 기존 로컬 히스토리를 push할 거면 리모트 저장소를 비어 있게(README 없이) 만드세요.

병합 충돌과의 구분

이건 병합 충돌이 아닙니다 — 충돌은 병합이 시작된 뒤 특정 라인에서 생깁니다. refusing to merge unrelated histories는 diff할 공통 베이스가 없어 병합이 아예 시작조차 안 되게 막는 것입니다. 허용하고 나면 평범한 충돌 해결이 그 뒤를 이어받습니다.

관련 질문

--allow-unrelated-histories는 위험한가요?

위험하진 않지만 안전장치를 없애는 것입니다. 양쪽이 합치려는 그 프로젝트가 맞는지 확인한 뒤에만 쓰세요.

새 저장소에서 왜 이게 시작됐나요?

git init 후 로컬 커밋을 했는데, 그 뒤 이미 자체 초기 커밋이 있는 리모트를 추가한 것입니다. 두 초기 커밋이 무관합니다.

리모트의 히스토리만 원하고 로컬 커밋은 필요 없습니다.

리모트를 새로 clone하고 작업 파일을 복사해 넣으세요. 나중에 풀어야 할 무관-히스토리 병합보다 깔끔합니다.

병합 커밋을 피할 수 없나요?

무관한 히스토리를 이을 땐 없습니다 — 병합 커밋이 두 루트를 묶는 방법입니다. rebase는 내 히스토리에 없는 베이스 위로 재생할 수 없습니다.

히스토리가 정말 무관한지 어떻게 확인하나요?

git merge-base HEAD origin/main을 실행하세요. 공유 조상이 있으면 커밋 해시를, 정말 무관하면 아무것도 안 찍습니다.

참고 자료

Haneul Seo

Infrastructure engineer · 10+ years running Linux fleets

같은 카테고리 다른 글

detected dubious ownershipFixed

Git: fatal: detected dubious ownership in repository

Git 2.35.2의 CVE-2022-24765 수정 이후, Git은 작업 트리나 .git 디렉터리의 소유자가 명령을 실행한 사용자와 다르면 저장소를 읽지 않습니다. 컨테이너, CI 작업, sudo 세션, 공유 드라이브에서 주로 나타납니다. 저장소가 내 것이어야 한다면 소유권을 바로잡고, 아니라면 global 설정의 safe.directory에 정확한 경로를 추가하세요 — Git은 이 설정을 저장소 자신의 설정에서는 무시합니다.

Git
failed calling webhookFixed

Kubernetes: Internal error occurred: failed calling webhook

admission webhook이 쓰기 요청 앞에 서 있는데 API server가 응답을 받지 못했고, 기본값인 failurePolicy: Fail이 그 침묵을 거부로 바꾼 것입니다. 메시지 끝부분이 곧 진단입니다 — context deadline exceeded는 호출이 도달하지 못한 것, no endpoints available은 떠 있는 게 없는 것, x509 줄은 API server가 webhook 인증서를 신뢰하지 않는 것입니다. 원인마다 해결이 다르고, 어느 것도 매니페스트 문제가 아닙니다.

Kubernetes
1205Fixed

MySQL: ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

다른 트랜잭션이 쥐고 있는 행 잠금을 innodb_lock_wait_timeout 만큼 기다리다 포기한 것입니다. sys.innodb_lock_waits 가 막고 있는 세션을 지목하고 KILL 문까지 만들어 주며, blocking_query 가 NULL 이면 블로커가 열린 트랜잭션 위에서 놀고 있다는 뜻입니다. 재시도 로직이 가장 자주 틀리는 지점은 따로 있습니다. 기본값에서는 타임아웃된 문장 하나만 롤백되므로, 트랜잭션은 그대로 열린 채 앞서 잡은 잠금을 전부 쥐고 있습니다.

MySQL
MISCONFFixed

Redis: MISCONF Redis is configured to save RDB snapshots, but it's currently unable to persist to disk

읽기는 되는데 모든 쓰기가 거부됩니다. 마지막 백그라운드 저장이 실패했고 stop-writes-on-bgsave-error 기본값이 yes 이기 때문입니다. 진짜 원인은 로그에 적혀 있습니다 — 디스크 공간 부족, redis 사용자가 쓸 수 없는 dir, rename 시점의 read-only 마운트, 또는 fork 가 Cannot allocate memory 로 실패하는 경우입니다. 원인을 고치고 BGSAVE 한 번만 돌리면 재시작 없이 쓰기가 돌아옵니다. rdb_last_bgsave_status 가 err 에서 ok 로 바뀝니다. stop-writes-on-bgsave-error no 는 쓰기를 즉시 되살리지만 스냅샷은 여전히 실패한 상태로 두므로, 해결이 아니라 의도한 맞교환으로 다뤄야 합니다.

Redis
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memoryFixed

Node.js: FATAL ERROR: Reached heap limit — JavaScript heap out of memory (종료 코드 134)

V8 힙에는 시스템 메모리와 Node 릴리스에서 유도되는 자기만의 천장이 있고, 가진 RAM 보다 훨씬 낮은 경우가 흔합니다. 빌드나 서버가 거기 닿으면 V8 은 FATAL ERROR: Reached heap limit 과 종료 코드 134 로 스스로 중단합니다. v8.getHeapStatistics().heap_size_limit 으로 실제 한도를 읽은 뒤, 큰 작업은 --max-old-space-size(MiB)나 NODE_OPTIONS 로 올리고, 컨테이너 안에서는 cgroup 한도보다 낮게 잡고, 오래 도는 프로세스의 누수는 --heapsnapshot-near-heap-limit 으로 잡으세요. FATAL ERROR 줄 없이 137 로 끝나면 컨테이너 kill 이지 이 오류가 아닙니다.

Node.js
exec /docker-entrypoint.sh: exec format errorFixed

Docker: 컨테이너 시작 직후 "exec format error" — 플랫폼이 다른 이미지, 에뮬레이터 없음, 셔뱅 없는 스크립트

컨테이너가 첫 명령에서 exec format error 로 끝납니다. 커널의 ENOEXEC, 즉 파일은 있지만 여기서는 실행할 수 없다는 뜻입니다. 실제로는 한 CPU 아키텍처에서 빌드한 이미지(Apple 실리콘 Mac은 linux/arm64 를 만듭니다)를 binfmt_misc 에 QEMU 핸들러가 없는 다른 아키텍처(x86_64 서버)에서 돌리거나, 엔트리포인트 스크립트의 첫 줄이 셔뱅이 아닌 경우입니다. uname -m, docker image inspect, ls /proc/sys/fs/binfmt_misc 로 원인을 가르고, docker buildx build --platform 을 명시(또는 두 플랫폼 매니페스트 목록 발행)하거나, 에뮬레이션이 목적이면 QEMU 등록과 --platform, 스크립트라면 #!/bin/sh 한 줄로 해결합니다.

Docker