Git 저장소를 이해할 때는 논리적 객체 모델과 디스크에 저장되는 형식을 나눠 보세요. Git은 내용으로 객체 ID를 정하고, 커밋은 트리를 가리킵니다. 하지만 각 객체가 항상 독립 파일로 남거나 전체 이력이 모든 clone에 내려오는 것은 아닙니다.

객체 ID와 네 가지 객체

Git 객체 ID는 파일 내용만 해시한 값이 아닙니다. 객체 종류와 길이를 포함한 헤더, 구분자, 내용이 해시 입력이 됩니다. 저장소가 SHA-1 형식인지 SHA-256 형식인지에 따라 ID 형식도 다릅니다. 따라서 “항상 40자리 SHA-1”이라고 일반화하지 마세요.

객체논리적으로 담는 내용파일 이름과의 관계
blob파일의 바이트 내용파일명·경로는 담지 않음
tree항목 이름, 모드, 객체 종류와 ID디렉터리 계층을 구성
commit루트 tree, 부모 commit(들), 작성자·커미터, 메시지특정 프로젝트 상태와 이력을 연결
annotated tag대상 객체, 태그 정보와 선택적 서명lightweight tag는 별도 tag 객체 없이 ref로 동작

같은 저장소에서 내용이 같고 객체 헤더도 같으면 같은 논리적 blob ID를 얻을 수 있습니다. 그래서 트리의 여러 경로가 같은 blob을 참조할 수 있습니다. 이는 논리 객체의 중복을 피할 수 있다는 뜻이지, 모든 저장 형식에서 디스크 블록 수가 정확히 하나라고 보장한다는 뜻은 아닙니다.

작은 변경을 논리 모델과 디스크에서 구분하기

예를 들어 큰 파일의 한 바이트를 바꾸면 내용이 달라져 새로운 blob ID가 생깁니다. 변경된 파일을 가리키는 tree와 새 commit도 필요할 수 있습니다. 변경하지 않은 다른 파일의 blob은 기존 객체를 계속 참조할 수 있고, 내용이 같은 tree도 재사용될 수 있습니다.

이 설명은 객체 그래프의 논리적 관점입니다. 느슨한 객체는 객체별 파일로 저장될 수 있지만, Git은 여러 객체를 packfile에 모으고 유사 객체를 delta 압축할 수 있습니다. 따라서 “한 바이트 수정 때마다 전체 대용량 파일이 디스크에 새 통째 사본으로 남는다”는 결론은 맞지 않습니다. 반대로 delta 압축이 모든 파일에서 같은 절감률을 보장하지도 않습니다. 실제 크기는 객체 내용, pack 구성, 압축, 유지되는 이력에 좌우됩니다.

브랜치와 태그는 이름이 가리키는 대상

브랜치는 특정 commit을 가리키는 이동 가능한 참조입니다. 이를 이해하는 데 “브랜치는 포인터”라는 비유는 유용하지만, .git/refs/heads/에 항상 41바이트 파일이 있다는 식의 설명은 저장 형식으로 일반화할 수 없습니다. loose ref 대신 packed-refs에 모일 수 있고, 저장소 설정과 ref backend에 따라서도 표현이 다릅니다. 또한 브랜치와 태그는 같은 종류의 이름이 아닙니다. annotated tag는 별도 객체를 만들 수 있고 lightweight tag는 ref만 둡니다.

저장소에서 직접 확인하려면 다음 명령을 쓸 수 있습니다.

git cat-file -t HEAD
git cat-file -p HEAD
git cat-file -p 'HEAD^{tree}'
git show-ref --head

첫 두 명령은 현재 HEAD가 가리키는 객체의 종류와 내용을 보여 줍니다. tree 명령은 해당 commit의 최상위 항목을 보여 줍니다. 마지막 명령은 현재 알려진 ref를 나열합니다. 실제 결과는 현재 저장소 상태에 따라 달라집니다. 이 안내서에서는 해당 명령을 실행하거나 결과를 측정하지 않았습니다.

Clone이 항상 전체 이력을 받는 것은 아니다

일반적인 clone은 선택한 원격 ref의 이력을 가져오지만, “모든 clone은 전체 객체 이력을 내려받는다”는 절대 규칙은 아닙니다. --depth는 얕은 이력을 만들고 --filter=blob:none 같은 partial-clone 필터는 필요할 때까지 일부 blob 전송을 미룰 수 있습니다. 원격 서버의 지원과 요청한 ref·필터에 따라 실제 전송 범위가 달라집니다.

대용량 자산을 관리할 때는 먼저 관측 가능한 문제를 구분하세요. clone 전송량이 큰지, 작업 디렉터리 크기가 큰지, 전체 이력의 저장 공간이 큰지, 특정 파일의 버전이 많이 남았는지는 서로 다른 문제입니다. shallow/partial clone은 내려받는 범위를 조절하는 선택지이고, Git LFS는 대용량 파일 내용을 별도 저장소 경로로 다루는 방식입니다. 어느 쪽이 적합한지는 이력 접근 요구, 서버 지원, 팀의 복구·백업 절차를 확인해 결정하세요.

확인한 근거와 범위

Git 내부 객체 모델, packfile과 delta, ref 저장 위치, shallow/partial clone, SHA-256 형식은 Git Internals의 객체 설명, Packfiles, [git clone 문서](https://git-scm.com/docs/git-clone), 저장소 레이아웃, 해시 알고리즘 전환 문서와 대조했습니다. 명령 예시는 독자가 로컬 저장소에서 구조를 확인하기 위한 것이며, 이 글에서 실행한 결과가 아닙니다.