Git 미드레벨 기술면접
새 면접Q. Git의 객체 모델(Object Model)에서 blob, tree, commit, tag 객체의 역할과 관계를 설명하고, 'git add'와 'git commit' 명령어가 실행될 때 내부적으로 어떤 객체들이 생성되는지 설명해주세요.
blob 객체는 파일의 내용을 저장하고, tree 객체는 디렉토리 구조와 파일명을 저장하며 blob이나 다른 tree를 가리킵니다. commit 객체는 특정 시점의 tree를 가리키며 메타데이터(작성자, 날짜, 메시지, 부모 커밋)를 포함합니다. 'git add'는 작업 디렉토리의 파일을 blob 객체로 변환하여 .git/objects에 저장하고 인덱스에 등록하며, 'git commit'은 인덱스의 상태를 기반으로 tree 객체를 생성한 후 이를 가리키는 commit 객체를 생성합니다. 모든 객체는 SHA-1 해시로 식별되며 .git/objects 디렉토리에 불변(immutable) 방식으로 저장됩니다.
- • blob은 파일 내용, tree는 디렉토리 구조, commit은 스냅샷과 메타데이터를 저장
- • git add는 blob 객체 생성 및 스테이징, git commit은 tree와 commit 객체 생성
- • 모든 객체는 SHA-1 해시로 식별되며 불변성을 가짐
- • 객체 간 참조 관계로 전체 히스토리가 구성됨
Git이 SHA-1에서 SHA-256으로 전환하는 이유와, 이 전환 과정에서 발생할 수 있는 호환성 문제는 무엇인가요?
Q. 개발팀에서 실수로 민감한 정보(DB 패스워드)가 포함된 파일을 커밋하고 이미 원격 저장소에 푸시했으며, 여러 개발자가 이미 pull 받은 상황입니다. 히스토리를 완전히 정리하고 모든 팀원의 로컬 저장소까지 동기화하는 전체 프로세스를 설명해주세요.
먼저 git filter-branch나 BFG Repo-Cleaner를 사용하여 전체 히스토리에서 민감한 파일을 제거합니다. filter-branch의 경우 '--tree-filter' 또는 '--index-filter' 옵션으로 모든 커밋에서 해당 파일을 삭제하고, 작업 후 'git push --force'로 원격 저장소를 덮어씁니다. 모든 팀원에게 즉시 공지하여 로컬 작업을 백업하고, 'git fetch origin', 'git reset --hard origin/main'으로 강제 동기화하도록 안내합니다. 이미 노출된 패스워드는 즉시 변경해야 하며, 향후 재발 방지를 위해 pre-commit hook에 git-secrets나 truffleHog 같은 도구를 설정하고 .gitignore를 업데이트합니다.
- • git filter-branch 또는 BFG Repo-Cleaner로 전체 히스토리에서 파일 제거
- • force push로 원격 저장소 덮어쓰기 및 팀원 전체 공지
- • 이미 노출된 크레덴셜은 즉시 로테이션 필요
- • pre-commit hook과 git-secrets 등으로 재발 방지 체계 구축
- • reflog와 가비지 컬렉션 고려 필요
git filter-branch와 BFG Repo-Cleaner의 성능 차이는 어느 정도이며, 각각 어떤 상황에서 더 적합한가요?
Q. 대용량 Git 저장소에서 'git clone'과 'git fetch' 작업이 매우 느린 상황입니다. shallow clone, partial clone, sparse checkout의 개념과 차이점을 설명하고, 각각 어떤 시나리오에서 사용하면 효과적인지 설명해주세요.
shallow clone(--depth)은 최근 N개의 커밋만 가져와 히스토리를 제한하며 CI/CD에서 빌드만 필요한 경우 유용합니다. partial clone(--filter)은 Git 2.19+에서 지원하며 blob이나 tree 객체를 필요할 때만 다운로드하여 초기 클론 속도를 높이고, 전체 히스토리는 유지하면서 용량을 줄입니다. sparse checkout은 작업 디렉토리에 특정 경로의 파일만 체크아웃하여 모노레포에서 특정 서비스만 작업할 때 효과적입니다. shallow clone은 히스토리 접근이 제한되고, partial clone은 서버 지원이 필요하며, sparse checkout은 전체 객체는 다운로드하므로 각 상황에 맞게 선택해야 합니다.
- • shallow clone: 히스토리 깊이 제한, CI/CD에 적합
- • partial clone: 객체 필터링으로 필요시 다운로드, 전체 히스토리 유지
- • sparse checkout: 작업 디렉토리 파일만 선택, 모노레포에 유용
- • 각 방식의 트레이드오프를 이해하고 상황에 맞게 선택
모노레포 환경에서 이 세 가지 기법을 조합하여 사용한다면 어떤 조합이 가장 효과적일까요?
Q. 팀에서 'git rebase'와 'git merge'의 사용 규칙을 정립하려고 합니다. 각각의 동작 원리와 히스토리에 미치는 영향을 설명하고, feature 브랜치 작업 시와 공유 브랜치에서의 사용 가이드라인을 제시해주세요.
git merge는 두 브랜치의 변경사항을 통합하는 새로운 merge commit을 생성하여 히스토리를 보존하며, 브랜치 간 관계를 명확히 보여줍니다. git rebase는 커밋들을 다른 베이스 위로 재배치하여 선형 히스토리를 만들고 깔끔한 로그를 유지하지만 커밋 해시가 변경됩니다. feature 브랜치에서는 로컬 작업 정리를 위해 rebase를 사용하고, main 브랜치로 통합 시에는 merge를 사용하는 것이 안전합니다. 이미 push된 공유 브랜치에서는 절대 rebase를 사용하지 않아야 하며, 필요시 팀 전체 합의 하에 force push를 진행해야 합니다.
- • merge는 히스토리 보존과 브랜치 관계 명확화, rebase는 선형 히스토리 생성
- • feature 브랜치 로컬 작업은 rebase, main 통합은 merge 권장
- • 공유 브랜치에서 rebase 금지 원칙
- • interactive rebase로 커밋 정리 후 통합하면 깔끔한 히스토리 유지
- • 팀 컨벤션에 따라 일관된 전략 적용 필요
GitHub의 'Squash and merge'와 'Rebase and merge' 옵션의 차이점과 각각의 장단점은 무엇인가요?
Q. hotfix가 빈번하게 발생하는 프로덕션 환경에서, 개발 중인 기능들과 독립적으로 긴급 패치를 배포하고 관리하는 Git 워크플로우를 설계해주세요. 브랜치 전략, 버전 태깅, 패치 백포트 프로세스를 포함하여 설명해주세요.
main 브랜치는 항상 프로덕션 배포 가능 상태를 유지하고, develop 브랜치에서 차기 릴리스를 개발합니다. hotfix 발생 시 main에서 직접 'hotfix/issue-name' 브랜치를 생성하여 수정하고, 테스트 후 main으로 머지하며 즉시 버전 태그(v1.2.3)를 생성합니다. hotfix는 반드시 develop 브랜치에도 머지하여 차기 릴리스에 포함되도록 하며, cherry-pick으로 다른 지원 버전에 백포트합니다. release 브랜치는 QA를 위해 develop에서 분기하며, 이 시점 이후 새 기능은 다음 릴리스로 연기됩니다. 자동화된 CI/CD 파이프라인에서 태그 기반 배포를 트리거하고, 각 환경별 배포 상태를 추적합니다.
- • main(프로덕션), develop(개발), hotfix(긴급패치) 브랜치 분리
- • hotfix는 main에서 분기하여 수정 후 main과 develop 양쪽 머지
- • semantic versioning으로 태그 관리 및 자동 배포
- • cherry-pick으로 다중 버전 백포트
- • release 브랜치로 기능 동결 및 QA 수행
- • 자동화된 파이프라인으로 태그 기반 배포
여러 버전을 동시 지원하는 상황에서 특정 hotfix를 일부 버전에만 선택적으로 적용해야 한다면 어떻게 관리하시겠습니까?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!