Skip to content

Version-control

  • Published on
    저장소가 느려지는 이유는 하나가 아닙니다. 커밋 이력이 긴 것, 파일 수가 많은 것, 큰 바이너리가 들어 있는 것은 서로 다른 문제이고 처방도 다릅니다. 이 글은 먼저 원인을 구분하는 측정 명령부터 시작해, 얕은 클론과 부분 클론이 왜 대체재가 아니라 용도가 다른 도구인지, sparse-checkout과 파일 감시가 status를 어떻게 줄이는지, commit-graph가 로그와 병합 기준점 계산을 왜 그렇게 크게 바꾸는지 설명합니다. gc를 aggressive로 돌리라는 흔한 조언이 왜 대체로 손해인지, Git LFS를 지금 도입해도 어제 커밋한 바이너리는 왜 사라지지 않는지, 그리고 filter-repo로 정리할 때 치르는 대가가 무엇인지까지 정리했습니다.
  • Published on
    merge와 rebase의 차이는 그림이 아니라 커밋 해시로 봐야 정확합니다. 리베이스는 커밋을 옮기는 명령이 아니라 부모가 달라진 새 커밋을 만드는 명령이고, 해시가 바뀐다는 그 사실 하나가 공유 브랜치를 리베이스하지 말라는 황금률의 유일한 근거입니다. 이 글은 실제 커밋 해시와 reflog 출력으로 그 변화를 보여 주고, 머지 커밋이 소음이라는 통념을 first-parent 로그로 반박하고, 스쿼시 머지가 이분 탐색과 체리픽에서 무엇을 가져가는지, 리베이스 도중 같은 충돌이 반복되는 이유와 rerere가 그것을 어떻게 없애는지, 그리고 force-with-lease만으로는 왜 부족한지까지 다룹니다. 마지막에 팀 정책을 고르는 기준을 표로 정리했습니다.
  • Published on
    Git 명령을 외우면 매번 검색하게 되지만, 데이터 모델을 알면 명령의 동작이 추론됩니다. 이 글은 blob과 tree와 commit과 tag라는 네 가지 객체, 같은 내용이 언제나 같은 해시를 갖는 콘텐츠 주소 지정, 브랜치가 41바이트짜리 파일에 불과하다는 사실, 그리고 인덱스가 실제로 무엇을 담고 있는지를 cat-file과 ls-files로 직접 열어 보며 확인합니다. 이 모델을 알면 reset이 왜 포인터 이동인지, rebase가 왜 커밋을 옮기지 않고 새로 만드는지, cherry-pick이 왜 충돌하는지, detached HEAD가 무엇인지가 전부 하나의 그림에서 설명됩니다. 마지막으로 SHA-1 충돌 공격에 Git이 어떻게 대응했고 SHA-256 전환이 지금 어디까지 와 있는지 정리했습니다.
  • Published on
    되돌리기 명령을 외우면 매번 검색하게 되지만, 무엇을 되돌리려는지 먼저 분류하면 명령은 저절로 결정됩니다. 워킹 디렉터리, 스테이징, 마지막 커밋 메시지, 커밋 자체, 이미 푸시한 커밋, 삭제한 브랜치까지 여섯 가지 상황으로 나누고 각각의 정확한 명령과 위험도를 정리했습니다. reset의 soft와 mixed와 hard가 HEAD, 인덱스, 워킹 트리 중 무엇을 옮기는지 표로 보여 주고, 푸시된 이력에는 왜 revert가 유일한 답인지, 머지 커밋을 revert한 뒤 다시 머지하면 왜 아무것도 돌아오지 않는지 설명합니다. reflog의 만료 정책과 그것도 놓쳤을 때 fsck로 고아 커밋을 건져 내는 방법까지 실제 출력과 함께 다룹니다.
  • Published on
    무시 목록에 분명히 적었는데 파일이 계속 올라오는 이유는 대부분 하나입니다. 이미 추적 중인 파일에는 무시 규칙이 적용되지 않습니다. 이 글은 인덱스에서 빼는 정확한 명령과 그 명령이 동료의 작업 디렉터리에서 파일을 지운다는 부작용, 어느 규칙이 범인인지 Git에게 직접 물어보는 check-ignore 사용법과 추적 중인 파일에서는 아무것도 출력하지 않는 함정, 선행 슬래시와 후행 슬래시와 부정 패턴의 순서 의존성, 상위 디렉터리를 제외하면 그 안의 부정 패턴이 무력화되는 규칙, 무시 규칙의 우선순위 계층, 대소문자를 구분하지 않는 파일시스템이 만드는 유령 변경까지 실제 출력과 함께 정리했습니다. 마지막으로 이미 커밋된 시크릿에는 무시 목록이 아무 역할도 하지 못한다는 점과 그때의 올바른 순서를 다룹니다.
  • Published on
    Git 2.54(2026-04-20)에 git history라는 새 명령어가 실험적으로 들어왔고, 2.55(2026-06-29)에서 fixup 서브커맨드가 추가됐습니다. reword/split/fixup 세 가지 흔한 history 재작성 작업을 인터랙티브 rebase 없이 명령 한 줄로 처리하고, 대상 커밋의 자손 브랜치들을 원자적 ref 트랜잭션으로 한꺼번에 갱신합니다. 메인테이너 Patrick Steinhardt는 커밋 메시지에서 이 기능의 동기로 Jujutsu 같은 경쟁 VCS에서 스택 브랜치 사용이 흔해졌다는 점을 직접 지목합니다. 다만 이건 아직 실험입니다 — 머지 커밋이 있는 history에서는 동작하지 않고, 충돌이 날 상황이면 설계상 그냥 중단하며, 훅을 전혀 실행하지 않습니다. 이 글은 실제로 들어온 것, 밑바닥이 sequencer가 아니라 git replay 위에 지어졌다는 사실, fixup의 세 갈래 병합 방향, 그리고 이 한계들이 풀리려면 왜 first-class conflicts가 필요한지를 1차 출처로 정리합니다.
  • Published on
    Git을 매일 쓰면서도 내부가 어떻게 생겼는지는 모르는 경우가 많습니다. blob·tree·commit·tag로 이루어진 객체 모델, SHA 해시로 내용을 주소화하는 방식, 커밋 DAG, 브랜치는 그냥 포인터라는 사실, .git 디렉터리의 실제 모습, 같은 내용이 한 번만 저장되는 이유, 그리고 팩파일까지. Git의 진짜 데이터 모델을 파헤칩니다.
  • Published on
    매일 사용하지만 대부분 개발자가 블랙박스로 여기는 도구, Git. 이 글은 Git의 내부를 처음부터 해부합니다. Content-addressable 파일시스템으로서의 본질, blob/tree/commit/tag 객체 모델, SHA-1 해시 체인, 느슨한 객체(loose object)와 packfile, 델타 압축, refs와 packed-refs, index(스테이징 에어리어), ort 알고리즘으로 교체된 merge 내부, rebase 메카닉, reflog, 오브젝트 GC, 부분 클론과 sparse checkout, 그리고 push/fetch 프로토콜까지 — Git을 마법이 아닌 엔지니어링으로 이해하고 싶은 엔지니어를 위한 종합 가이드입니다.
  • Published on
    매일 쓰는 git이지만 .git 디렉터리 안을 제대로 들여다본 적 없다면. Blob/Tree/Commit 객체부터 packfile delta 압축, reflog로 되살리기, rebase가 실제로 하는 일, merge 알고리즘(3-way, recursive, ort), 그리고 sha1 → sha256 전환까지 — Git의 그래프 데이터베이스로서의 본질을 10,000자로 파헤칩니다.