Git 시니어 기술면접
새 면접Q. 여러 팀이 독립적으로 개발하는 마이크로서비스 아키텍처 환경에서 모노레포 전략과 멀티레포 전략의 트레이드오프를 분석해주세요. 각 전략에서 의존성 관리, 버전 관리, CI/CD 파이프라인 구성, 코드 공유 방식이 어떻게 달라지는지 설명하고, 두 전략을 하이브리드로 결합하는 방안을 제시해주세요.
모노레포는 단일 저장소에서 모든 서비스를 관리하여 atomic commit과 통합 리팩토링이 가능하지만 저장소 크기와 빌드 시간이 증가합니다. 멀티레포는 팀 자율성과 독립적 배포가 용이하지만 공통 라이브러리 버전 관리와 크로스 서비스 변경이 복잡합니다. 하이브리드 접근으로 핵심 공통 코드는 모노레포로 관리하고 서비스별 저장소는 분리하되, Git submodule이나 subtree를 활용해 연결하거나, 공통 라이브러리를 패키지 저장소로 배포하는 방식을 고려할 수 있습니다. CI/CD는 모노레포에서 변경 감지 기반 선택적 빌드(affected projects)를 구현하고, 멀티레포에서는 의존성 그래프 기반 순차 배포를 자동화해야 합니다.
- • 모노레포: atomic commit, 통합 리팩토링 가능, 저장소 크기/빌드 시간 증가
- • 멀티레포: 팀 자율성, 독립 배포, 공통 코드 버전 관리 복잡
- • 하이브리드: 핵심 공통 코드 모노레포 + 서비스별 분리, submodule/subtree 활용
- • CI/CD: 모노레포는 변경 감지 기반 빌드, 멀티레포는 의존성 그래프 기반 배포
Google의 Bazel이나 Facebook의 Buck 같은 빌드 시스템이 모노레포 환경에서 어떻게 증분 빌드와 캐싱을 통해 성능 문제를 해결하는지 설명해주세요.
Q. Git의 reference 저장 방식이 loose reference에서 packed-refs 파일로 변환되는 과정과 이유를 설명해주세요. 특히 수천 개의 브랜치와 태그가 있는 저장소에서 ref lookup 성능을 최적화하기 위한 packed-refs의 내부 구조(정렬 방식, 바이너리 서치)와, loose refs와 packed-refs가 공존할 때의 우선순위 처리 메커니즘을 설명해주세요.
Git은 기본적으로 각 reference를 .git/refs/ 디렉토리에 개별 파일로 저장하지만(loose refs), 수천 개의 ref가 생기면 파일 시스템 성능이 저하됩니다. git gc나 git pack-refs 명령으로 이들을 .git/packed-refs 단일 파일로 통합하는데, 이 파일은 ref 이름으로 알파벳 순 정렬되어 바이너리 서치가 가능합니다. Ref lookup 시 Git은 먼저 loose refs를 확인하고 없으면 packed-refs를 검색하므로, loose refs가 항상 우선합니다. 새로운 ref 생성이나 업데이트는 loose 형태로 먼저 기록되고, 주기적으로 pack됩니다. 이 방식으로 읽기 성능(O(log n))과 쓰기 단순성을 동시에 확보합니다.
- • Loose refs: 개별 파일, 쓰기 단순, 많아지면 파일시스템 성능 저하
- • Packed-refs: 단일 파일, 알파벳 정렬, 바이너리 서치로 O(log n) lookup
- • 우선순위: loose refs 먼저 확인 후 packed-refs 검색
- • 업데이트: 항상 loose로 기록 후 주기적 packing으로 최적화
Git 2.0 이후 도입된 reftable 형식이 기존 packed-refs 방식의 어떤 한계를 개선했는지, 특히 트랜잭션 처리와 동시성 측면에서 설명해주세요.
Q. Git의 다양한 병합 전략(recursive, octopus, ours, subtree)의 동작 원리와 사용 시나리오를 비교 설명해주세요. 특히 recursive 전략에서 rename detection과 recursive merge base 찾기가 어떻게 작동하는지, 그리고 3개 이상의 브랜치를 동시에 병합할 때 octopus 전략의 제약사항을 설명해주세요.
Recursive 전략은 가장 일반적으로 사용되며, 두 브랜치의 공통 조상을 찾아 3-way merge를 수행하고, 공통 조상이 여러 개면 재귀적으로 병합하여 가상의 merge base를 생성합니다. Rename detection을 통해 파일 이동도 추적하여 충돌을 최소화합니다. Octopus는 3개 이상의 브랜치를 한 번에 병합하지만 충돌이 발생하면 실패하므로 자동 병합 가능한 경우에만 사용합니다. Ours는 현재 브랜치의 내용을 그대로 유지하면서 병합 히스토리만 기록하고, Subtree는 프로젝트를 서브디렉토리로 병합할 때 경로 조정을 자동으로 처리합니다.
- • Recursive: 3-way merge, 재귀적 merge base 생성, rename detection
- • Octopus: 3개 이상 브랜치 동시 병합, 충돌 시 실패
- • Ours: 현재 내용 유지, 히스토리만 병합
- • Subtree: 서브디렉토리 병합 시 경로 자동 조정
Criss-cross merge 상황에서 recursive 전략이 여러 merge base를 어떻게 처리하며, 이 과정에서 발생할 수 있는 성능 문제와 해결 방안을 설명해주세요.
Q. 대규모 저장소에서 git log와 git blame의 성능을 최적화하기 위해 Git이 사용하는 commit-graph 파일의 구조와 동작 원리를 설명해주세요. Commit-graph가 저장하는 정보(parent relationships, generation numbers, commit date)와 이것이 reachability 검사와 ancestry 쿼리를 어떻게 가속화하는지, 그리고 incremental update 시 여러 commit-graph 파일을 체인으로 연결하는 방식을 설명해주세요.
Commit-graph는 커밋 객체의 메타데이터를 이진 형식으로 사전 계산하여 .git/objects/info/commit-graph에 저장합니다. 각 커밋의 parent 포인터, generation number(루트로부터의 거리), commit date를 인덱싱하여 O(1)로 접근 가능하게 만듭니다. Generation number를 활용하면 reachability 검사 시 불필요한 커밋 탐색을 조기 종료할 수 있어 git log --graph나 merge-base 계산이 크게 빨라집니다. Incremental update 시 새로운 커밋들을 별도의 commit-graph 파일로 생성하고 base 그래프를 참조하는 체인 구조로 연결하여, 전체 재계산 없이 점진적으로 업데이트할 수 있습니다. Git 2.24부터 기본 활성화되었습니다.
- • Commit-graph: 커밋 메타데이터를 이진 형식으로 사전 계산 및 인덱싱
- • Generation number: 루트로부터 거리, reachability 검사 최적화
- • O(1) 메타데이터 접근으로 log, blame, merge-base 성능 향상
- • Incremental update: 체인 구조로 새 커밋 추가, 전체 재계산 불필요
Bloom filter를 활용한 changed-path filter가 commit-graph와 결합되어 git log -- <path> 쿼리를 어떻게 최적화하는지 설명해주세요.
Q. Git의 분산 특성을 활용하여 인터넷 연결이 제한적인 환경(예: 해외 지사, 오프라인 개발)에서 효율적으로 협업하는 워크플로우를 설계해주세요. Bundle 파일을 활용한 오프라인 저장소 동기화, 로컬 bare repository를 통한 팀 내 공유, 그리고 중앙 서버와의 주기적 동기화 전략을 포함하여 설명해주세요.
Git bundle을 사용하면 커밋 범위를 단일 파일로 내보내 이메일이나 USB로 전송할 수 있습니다. git bundle create로 특정 브랜치나 커밋 범위를 번들링하고, 수신 측에서 git bundle verify로 검증 후 git fetch나 git pull로 적용합니다. 팀 내에서는 로컬 네트워크에 bare repository를 설정하여 임시 중앙 저장소로 활용하고, 주기적으로 공식 중앙 서버와 동기화합니다. 각 개발자는 로컬 bare repo를 origin으로 설정하고 upstream을 중앙 서버로 설정하여 dual remote 구조를 유지합니다. 네트워크 복구 시 git push upstream --all로 일괄 동기화하며, 충돌은 로컬에서 미리 해결합니다.
- • Git bundle: 커밋을 파일로 내보내 오프라인 전송, verify 후 fetch/pull
- • 로컬 bare repository: 팀 내 임시 중앙 저장소로 활용
- • Dual remote: origin(로컬), upstream(중앙) 구조로 점진적 동기화
- • 주기적 동기화: 네트워크 복구 시 일괄 push, 로컬 충돌 해결
Git의 alternates 메커니즘을 활용하여 여러 로컬 저장소가 객체 저장소를 공유하도록 설정하면 어떤 이점이 있으며, 이 방식의 위험성과 관리 방안은 무엇인가요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!