..

when should switch working clone to bare clone

Overview


Git 저장소를 다룰 때 우리는 습관적으로 git clone 결과를 작업 디렉터리까지 포함한 형태로 받아온다. 이 방식은 익숙하고 직관적이다. 클론이 끝나면 곧바로 소스 파일을 열어볼 수 있고, 수정도 가능하며, 빌드나 테스트도 바로 수행할 수 있다.

그런데 모든 작업이 정말 working tree를 필요로 하는 것은 아니다. 어떤 작업은 실제 소스 파일을 한 줄도 읽지 않고, 오직 Git metadata만으로 끝난다. 예를 들어 변경 이력 비교, ref 조회, fetch, commit graph 탐색 같은 작업은 .git 내부 정보만으로도 충분히 수행할 수 있다.

이 지점에서 자연스럽게 질문이 생긴다.

“working clone이 아니라 bare clone으로 바꾸면 비용을 더 줄일 수 있지 않을까?”

이번 글은 이 질문에 대해 정리한 초안이다. 핵심은 단순히 bare clone이 더 빠르다 라는 결론을 내리는 것이 아니라, 어떤 경우에는 bare clone이 맞고 어떤 경우에는 여전히 working clone이 필요하다는 점을 경계선 중심으로 설명하는 데 있다.

차이점?


Working Clone과 Bare Clone은 무엇이 다를까?

working clone 은 우리가 가장 익숙하게 사용하는 형태의 클론이다. Git object database와 refs 정보가 .git 디렉터리 안에 저장되고, 동시에 현재 브랜치 기준의 실제 파일들도 working tree에 풀린다. 즉, Git 내부 데이터와 사람이 보는 소스 트리가 함께 생성된다.

반면 bare clone 은 working tree가 없다. 저장소 자체가 곧 Git metadata 저장소이며, 일반적으로 ref, object, pack file 중심의 구조만 남는다. 그래서 bare 저장소를 열어보면 Java 파일, YAML 파일, Gradle 파일이 보이지 않는다. 대신 HEAD, config, packed-refs, objects/pack/*.pack, objects/pack/*.idx 같은 Git 내부 파일 위주로 구성된다.

이 차이는 단순한 저장 형태의 차이가 아니라 비용 구조의 차이이기도 하다. working clone은 fetch 이후 checkout 단계까지 수행해야 하므로 파일 생성, 디렉터리 생성, metadata 기록, 권한 반영 등 추가 파일시스템 작업이 따라온다. bare clone은 이 checkout 단계를 생략하므로 생성 파일 수와 디스크 사용량을 눈에 띄게 줄일 수 있다.

Why?


왜 Bare Clone이 더 가벼워 보일까?

실제로 성능 테스트를 수행해보면 working clone과 bare clone의 결과는 꽤 다르게 보인다. 예를 들어 한 테스트에서는 working clone 결과가 약 2781개의 일반 파일과 160 MiB 수준의 디렉터리 크기로 측정되었고, bare clone 결과는 약 6개의 일반 파일과 66 MiB 수준으로 측정되었다.

이 수치만 보면 bare clone이 압도적으로 가볍다고 느껴진다. 실제로도 디스크 점유량과 생성 파일 수 관점에서는 그 해석이 크게 틀리지 않다. 다만 여기서 오해하면 안 되는 부분이 있다.

bare 저장소의 파일 수가 작게 보이는 이유는 “저장소 데이터가 거의 없다”는 뜻이 아니라, Git 객체가 pack file 중심으로 묶여 있고 working tree가 생성되지 않았기 때문이다. 즉, 소스 파일 수천 개가 사라진 것이 아니라 체크아웃되지 않은 상태로 .pack 내부에 압축되어 보관된 것이다.

그래서 bare clone의 비용 절감은 주로 아래 두 축에서 발생한다.

첫째, checkout 대상 파일을 만들지 않으므로 일반 파일 수가 극적으로 줄어든다. 둘째, working tree를 유지하기 위한 추가 파일시스템 I/O가 줄어든다.

이 두 가지는 특히 저장소 파일 수가 많거나, 동일한 작업을 반복 수행하거나, 디스크 I/O가 병목인 환경에서 의미를 가진다.

너무 많은 기대


필자의 경우 “working clone은 파일을 엄청 많이 만들기 때문에 bare clone보다 훨씬 느릴 것”이라고 예상했다. 그러나 이 직관은 절반만 맞다.

실제 clone 시간은 checkout 비용만으로 결정되지 않는다. clone 전체 시간에는 원격 서버와의 통신, 인증, refs 광고, 객체 협상, pack 생성, pack 다운로드, object database 기록, 그리고 마지막 checkout까지 여러 단계가 함께 포함된다.

이 말은 곧, working clone이 추가적인 파일시스템 비용을 가지는 것은 맞지만, 전체 시간에서 그 비중이 항상 압도적이지는 않다는 뜻이다. 네트워크 상태가 지배적이거나, 서버 측 pack 생성 시간이 큰 경우, 또는 로컬 디스크가 충분히 빠른 경우에는 working clone과 bare clone의 시간 차이가 생각보다 작게 나타날 수 있다.

즉, 파일 수 차이시간 차이 는 같은 방향으로 움직일 가능성은 높지만, 항상 같은 비율로 벌어지지는 않는다. 실무에서 bare clone의 가치를 설명할 때도 시간만 강조하기보다, 디스크 사용량 감소와 checkout 제거라는 구조적 차이를 함께 설명하는 편이 더 설득력이 있다.

Bare Clone 가능한 경우


여기서 가장 중요한 결론이 나온다. bare clone이 더 가벼워 보인다고 해서 모든 clone 경로를 bare로 통일하는 것은 좋은 전략이 아니다.

기준은 단순하다. 그 작업이 working tree를 실제로 필요로 하는가를 먼저 봐야 한다.

예를 들어 다음과 같은 작업은 bare clone과 잘 맞는다.

ref 조회나 브랜치 상태 비교처럼 Git metadata만 읽는 작업이 그렇다. 또는 fetch 이후 commit graph를 비교하거나, 특정 브랜치 간 변경 파일 목록을 산출하는 작업도 candidate가 될 수 있다. 이 경우 애초에 Java 소스 파일이나 YAML 파일을 실제 경로에서 열지 않기 때문에, working tree를 만드는 행위 자체가 비용만 추가할 수 있다.

반대로 다음과 같은 작업은 bare clone으로 바꾸기 어렵다.

소스 파일을 실제 경로로 읽어야 하는 정적 분석 작업이 그렇다. 빌드 도구를 실행해야 하는 테스트 경로도 마찬가지다. 클론한 디렉터리 안에서 압축을 풀거나 파일을 수정한 뒤 commit/push 하는 흐름 역시 working tree가 반드시 필요하다.

결국 bare clone은 “더 좋은 clone”이라기보다 “특정 작업에 더 적합한 clone”이다. 모든 곳에 적용하는 범용 최적화가 아니라, metadata 중심 작업을 분리해 적용하는 선택적 최적화에 가깝다.

Conclusion


bare clone은 working tree를 만들지 않기 때문에 생성 파일 수를 극적으로 줄일 수 있고, 디스크 사용량과 checkout 비용도 함께 낮출 수 있다. 하지만 모든 행위에 대해 적용 가능한 절대 해법이 아니라, 어떤 행위를 수행하는지에 따라 clone 방식이 결정되어야 한다.