- Published on
Git 완전 정복: 주니어부터 시니어까지, 실무에서 바로 쓰는 Git 고급 워크플로우
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며
- 1. Git 내부 구조 이해 — Objects, DAG, 그리고 .git 디렉토리
- 2. 브랜칭 전략 비교 — 팀에 맞는 워크플로우 선택하기
- 3. 리베이스 마스터 클래스
- 4. 실무 시나리오 20개 — 문제 발생 시 해결법
- 시나리오 1: 커밋 메시지를 잘못 작성했을 때
- 시나리오 2: 잘못된 브랜치에 커밋했을 때
- 시나리오 3: 푸시 후 되돌리기 — revert vs reset
- 시나리오 4: 머지 충돌 해결 전략
- 시나리오 5: 특정 커밋으로 버그 추적 — git bisect
- 시나리오 6: 대용량 파일을 실수로 커밋했을 때
- 시나리오 7: 파일의 일부만 스테이징 — git add -p
- 시나리오 8: 작업 중 긴급 핫픽스 — stash + worktree
- 시나리오 9: 여러 커밋을 하나로 합치기
- 시나리오 10: 서브모듈 관리
- 시나리오 11: 삭제된 브랜치 복구
- 시나리오 12: 특정 파일만 다른 브랜치에서 가져오기
- 시나리오 13: 커밋 날짜 변경
- 시나리오 14: Git blame으로 코드 추적
- 시나리오 15: git log 고급 활용
- 시나리오 16: 원격 저장소 관리
- 시나리오 17: Git 태그로 릴리스 관리
- 시나리오 18: Git hooks로 자동화
- 시나리오 19: 패치 파일 생성 및 적용
- 시나리오 20: git reflog — 최후의 보루
- 5. Conventional Commits + Semantic Versioning
- 6. GitHub Actions CI/CD
- 7. Monorepo 전략
- 8. Git 성능 최적화
- 9. AI + Git (2025~2026)
- 실력 점검 퀴즈
- 참고 자료
- 마무리
들어가며
Git은 모든 개발자의 일상 도구입니다. 하지만 대부분의 개발자가 git add, git commit, git push 정도만 사용하고, Git이 제공하는 강력한 기능의 10%도 활용하지 못합니다. 이 가이드는 주니어 개발자부터 시니어 개발자까지, Git의 내부 구조부터 실무에서 즉시 적용 가능한 고급 워크플로우를 총정리합니다.
코드 리뷰에서 "이 커밋 히스토리 좀 정리해주세요"라는 피드백을 받은 적이 있나요? 머지 충돌이 나면 당황한 적은요? 이 글을 끝까지 읽으면 그런 상황에서 자신 있게 대처할 수 있습니다.
1. Git 내부 구조 이해 — Objects, DAG, 그리고 .git 디렉토리
Git을 진정으로 마스터하려면 내부 동작 원리를 이해해야 합니다. Git은 단순한 버전 관리 도구가 아니라, content-addressable 파일 시스템 위에 구축된 정교한 시스템입니다.
1.1 Git의 4가지 객체 (Objects)
Git 내부에는 4가지 핵심 객체가 존재합니다.
Blob (Binary Large Object): 파일의 내용을 저장합니다. 파일 이름이나 경로는 포함하지 않고, 순수한 파일 내용만 담습니다.
# 파일 내용의 해시값 확인
echo "Hello, Git!" | git hash-object --stdin
# 결과: 예시 af5626b4a114abcb82d63db7c8082c3c4756e51b
# 실제 저장된 객체 타입 확인
git cat-file -t af5626b
# 결과: blob
# 내용 확인
git cat-file -p af5626b
# 결과: Hello, Git!
Tree: 디렉토리 구조를 나타냅니다. Blob과 다른 Tree를 참조하여 파일 시스템의 스냅샷을 구성합니다.
# 최신 커밋의 트리 확인
git cat-file -p HEAD^{tree}
# 100644 blob a906cb2a4a904a15... README.md
# 040000 tree 99f1a6d12cb4b6f1... src
# 100644 blob 47c6340d6459e058... package.json
Commit: 특정 시점의 스냅샷입니다. Tree 객체를 가리키며, 작성자, 커밋 메시지, 부모 커밋 정보를 포함합니다.
# 커밋 내부 구조 확인
git cat-file -p HEAD
# tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0
# parent 8bd3ad5e1234567890abcdef1234567890abcdef
# author John Doe <john@example.com> 1711100000 +0900
# committer John Doe <john@example.com> 1711100000 +0900
#
# feat: add user authentication
Tag: 특정 커밋에 이름을 붙이는 객체입니다. 릴리스 버전 관리에 사용됩니다.
# 어노테이티드 태그 생성
git tag -a v1.0.0 -m "Release version 1.0.0"
# 태그 객체 확인
git cat-file -p v1.0.0
1.2 SHA-1 해싱과 콘텐츠 주소 지정
Git은 모든 객체를 SHA-1 해시로 식별합니다. 동일한 내용은 항상 동일한 해시를 생성하므로, 중복 저장이 자연스럽게 방지됩니다.
# 동일한 내용 = 동일한 해시
echo "same content" | git hash-object --stdin
echo "same content" | git hash-object --stdin
# 두 결과가 완전히 동일합니다
이것이 의미하는 바는 중요합니다. 100개의 브랜치에서 같은 파일을 가지고 있더라도, Git은 그 파일을 단 한 번만 저장합니다.
1.3 DAG (Directed Acyclic Graph) — 커밋 그래프
Git의 커밋 히스토리는 DAG(방향 비순환 그래프) 구조입니다. 각 커밋은 부모 커밋을 가리키며, 순환이 없습니다.
A---B---C---D (main)
\
E---F---G (feature)
\
H---I (hotfix)
이 구조를 이해하면 merge, rebase, cherry-pick이 실제로 무엇을 하는지 직관적으로 알 수 있습니다.
# 그래프 형태로 로그 보기
git log --oneline --graph --all --decorate
# 더 깔끔한 출력
git log --oneline --graph --all --format="%h %s (%ar)"
1.4 .git 디렉토리 해부
.git/
HEAD # 현재 브랜치를 가리키는 포인터
config # 저장소별 설정
refs/
heads/ # 로컬 브랜치들 (각 파일 = 커밋 해시)
tags/ # 태그들
remotes/ # 원격 브랜치 추적
objects/ # 모든 Git 객체 (blob, tree, commit, tag)
pack/ # 압축된 객체 팩 파일
hooks/ # Git 훅 스크립트
index # 스테이징 영역 (바이너리)
# HEAD가 가리키는 곳 확인
cat .git/HEAD
# ref: refs/heads/main
# main 브랜치가 가리키는 커밋
cat .git/refs/heads/main
# a1b2c3d4e5f6...
# 객체 저장소 크기 확인
git count-objects -vH
2. 브랜칭 전략 비교 — 팀에 맞는 워크플로우 선택하기
2.1 Git Flow
2010년 Vincent Driessen이 제안한 전통적인 브랜칭 모델입니다.
main ─────────────────────────────── (프로덕션)
│
└── develop ────────────────────── (개발 통합)
│ │
│ feature/login ────────── (기능 개발)
│
└── release/1.0 ──────────── (릴리스 준비)
│
└── hotfix/bug-123 ──── (긴급 수정)
장점: 명확한 릴리스 관리, 프로덕션 안정성 보장 단점: 브랜치가 많아 복잡, 머지 충돌 빈번, CI/CD와 어울리지 않음
# Git Flow 초기화 (git-flow 확장)
git flow init
# 기능 개발 시작
git flow feature start user-auth
# 기능 개발 완료
git flow feature finish user-auth
2.2 GitHub Flow
GitHub에서 사용하는 단순한 브랜칭 모델입니다.
main ────────────────────────────────
│ │
└── feature ───┘ (PR + 머지)
규칙: main은 항상 배포 가능 상태. 기능 브랜치에서 작업 후 PR을 통해 머지.
# 1. 브랜치 생성
git checkout -b feature/add-search
# 2. 작업 및 커밋
git add .
git commit -m "feat: add search functionality"
# 3. 푸시
git push -u origin feature/add-search
# 4. PR 생성 (GitHub CLI)
gh pr create --title "Add search functionality" --body "..."
# 5. 리뷰 후 머지
gh pr merge --squash
2.3 Trunk-Based Development (트렁크 기반 개발)
Google, Meta 등 대규모 팀에서 사용하는 방식입니다. 모든 개발자가 main(trunk)에 직접 또는 매우 짧은 수명의 브랜치를 통해 자주 통합합니다.
main ──A──B──C──D──E──F──G──H──I──
\─/ \─/
(1-2일) (1-2일)
핵심 원칙:
- 브랜치 수명은 최대 1~2일
- 하루에 여러 번 main에 통합
- Feature Flag로 미완성 기능 관리
- 강력한 CI/CD 파이프라인 필수
2.4 전략 비교표
| 항목 | Git Flow | GitHub Flow | Trunk-Based |
|---|---|---|---|
| 복잡도 | 높음 | 낮음 | 중간 |
| 브랜치 수명 | 길다 (주~월) | 중간 (일~주) | 짧다 (시간~일) |
| 릴리스 주기 | 정기 릴리스 | 수시 배포 | 지속 배포 |
| 팀 규모 | 10명 이상 | 2~15명 | 제한 없음 |
| CI/CD 의존도 | 낮음 | 중간 | 높음 |
| 추천 상황 | 모바일 앱, 패키지 | SaaS, 웹앱 | 대규모 조직 |
2.5 브랜치 명명 규칙
# 기능 개발
feature/JIRA-123-add-login
feature/user-profile-page
# 버그 수정
bugfix/JIRA-456-fix-null-pointer
fix/login-redirect-loop
# 핫픽스
hotfix/security-patch-xss
hotfix/v1.2.1
# 릴리스
release/1.0.0
release/2026-q1
# 실험/개인
experiment/new-search-algo
chore/update-dependencies
3. 리베이스 마스터 클래스
3.1 Rebase vs Merge — 언제 무엇을 쓸까
Merge: 두 브랜치의 히스토리를 보존하면서 합칩니다.
git checkout main
git merge feature/login
# 머지 커밋이 생성됨
A---B---C---D---M (main, 머지 커밋 M)
\ /
E---F---G (feature)
Rebase: 커밋을 다른 베이스 위에 재적용합니다.
git checkout feature/login
git rebase main
# feature의 커밋이 main 위에 재적용됨
A---B---C---D (main)
\
E'---F'---G' (feature, 재적용됨)
3.2 Interactive Rebase (대화형 리베이스) 완전 가이드
# 최근 5개 커밋을 대화형으로 편집
git rebase -i HEAD~5
에디터가 열리면 다음과 같은 화면이 나타납니다.
pick a1b2c3d feat: add user model
pick d4e5f6g fix: typo in user model
pick h7i8j9k feat: add user controller
pick l0m1n2o WIP: debugging
pick p3q4r5s feat: add user routes
사용 가능한 명령어:
| 명령 | 약자 | 설명 |
|---|---|---|
| pick | p | 커밋을 그대로 사용 |
| reword | r | 커밋 메시지만 변경 |
| edit | e | 커밋을 수정 (파일 변경 가능) |
| squash | s | 이전 커밋과 합치고 메시지 편집 |
| fixup | f | 이전 커밋과 합치고 메시지 버림 |
| drop | d | 커밋 삭제 |
실전 예시 — 지저분한 히스토리 정리:
pick a1b2c3d feat: add user model
fixup d4e5f6g fix: typo in user model
pick h7i8j9k feat: add user controller
drop l0m1n2o WIP: debugging
pick p3q4r5s feat: add user routes
결과: 5개 커밋이 깔끔한 3개 커밋으로 정리됩니다.
3.3 Autosquash 워크플로우
fixup! 접두사를 사용하면 자동으로 정리됩니다.
# 원래 커밋
git commit -m "feat: add user model"
# 나중에 수정이 필요할 때
git commit --fixup HEAD
# 또는 특정 커밋 지정
git commit --fixup a1b2c3d
# 자동으로 정리
git rebase -i --autosquash main
3.4 리베이스의 황금 규칙
절대 공유된 브랜치(main, develop)를 리베이스하지 마세요. 리베이스는 커밋 해시를 변경하므로, 다른 사람들의 로컬 저장소와 충돌이 발생합니다.
# 안전한 리베이스 (개인 feature 브랜치)
git checkout feature/my-task
git rebase main
# 위험한 리베이스 (절대 하지 마세요)
git checkout main
git rebase feature/something # 금지!
4. 실무 시나리오 20개 — 문제 발생 시 해결법
시나리오 1: 커밋 메시지를 잘못 작성했을 때
# 방금 한 커밋의 메시지 수정 (아직 푸시 안 함)
git commit --amend -m "feat: add user authentication"
# 에디터에서 메시지 수정
git commit --amend
시나리오 2: 잘못된 브랜치에 커밋했을 때
# 상황: main에 커밋해야 할 것을 feature 브랜치에 했다
# 방법 1: cherry-pick
git checkout main
git cherry-pick abc1234
git checkout feature/wrong-branch
git reset --hard HEAD~1
# 방법 2: stash 활용
git reset --soft HEAD~1
git stash
git checkout correct-branch
git stash pop
git commit -m "correct commit message"
시나리오 3: 푸시 후 되돌리기 — revert vs reset
# 안전한 방법: revert (새 커밋으로 되돌림, 히스토리 보존)
git revert abc1234
git push
# 위험한 방법: reset + force push (히스토리 변경)
git reset --hard HEAD~1
git push --force-with-lease
# force-with-lease는 다른 사람의 커밋을 덮어쓰지 않도록 보호
revert vs reset 비교:
| 항목 | revert | reset |
|---|---|---|
| 히스토리 | 보존 (새 커밋 추가) | 변경 (커밋 삭제) |
| 안전성 | 안전 | 위험 |
| 공유 브랜치 | 사용 가능 | 사용 금지 |
| 되돌리기 | revert의 revert 가능 | reflog으로만 복구 |
시나리오 4: 머지 충돌 해결 전략
# 충돌 발생 시
git merge feature/login
# CONFLICT (content): Merge conflict in src/auth.js
# 충돌 파일 확인
git status
# 충돌 마커 구조
# <<<<<<< HEAD
# 현재 브랜치의 코드
# =======
# 머지하려는 브랜치의 코드
# >>>>>>> feature/login
# 수동 해결 후
git add src/auth.js
git commit -m "resolve merge conflict in auth module"
머지 충돌 최소화 전략:
# 1. main을 자주 가져와서 동기화
git fetch origin
git rebase origin/main
# 2. 작은 단위로 자주 커밋하고 머지
# 3. 팀 내 파일 소유권 명확히 하기 (CODEOWNERS)
# 4. 머지 도구 설정
git config --global merge.tool vimdiff
git mergetool
시나리오 5: 특정 커밋으로 버그 추적 — git bisect
# bisect 시작
git bisect start
# 현재(버그 있음)를 bad로 표시
git bisect bad
# 버그 없던 커밋을 good으로 표시
git bisect good v1.0.0
# Git이 중간 커밋을 체크아웃 — 테스트 후 판단
git bisect good # 또는 git bisect bad
# 반복하면 버그를 유발한 정확한 커밋을 찾음
# 결과: abc1234 is the first bad commit
# bisect 종료
git bisect reset
자동 bisect (테스트 스크립트 활용):
# 테스트 스크립트가 실패하면 bad, 성공하면 good
git bisect start HEAD v1.0.0
git bisect run npm test
# 자동으로 버그 커밋을 찾아줍니다!
시나리오 6: 대용량 파일을 실수로 커밋했을 때
# 방법 1: git-filter-repo (추천)
pip install git-filter-repo
git filter-repo --path large-file.zip --invert-paths
# 방법 2: BFG Repo-Cleaner
java -jar bfg.jar --delete-files large-file.zip
git reflog expire --expire=now --all
git gc --prune=now --aggressive
# 예방: .gitignore 설정
echo "*.zip" >> .gitignore
echo "*.tar.gz" >> .gitignore
echo "node_modules/" >> .gitignore
시나리오 7: 파일의 일부만 스테이징 — git add -p
# 파일의 변경사항을 hunk 단위로 선택적 스테이징
git add -p src/utils.js
# 각 hunk에 대해:
# y - 이 hunk 스테이징
# n - 이 hunk 건너뛰기
# s - 더 작은 hunk로 분할
# e - 수동으로 편집
# q - 종료
시나리오 8: 작업 중 긴급 핫픽스 — stash + worktree
# 방법 1: stash
git stash push -m "WIP: feature work"
git checkout main
git checkout -b hotfix/critical-bug
# 핫픽스 작업...
git checkout feature/my-work
git stash pop
# 방법 2: worktree (더 나은 방법!)
git worktree add ../hotfix-workspace main
cd ../hotfix-workspace
git checkout -b hotfix/critical-bug
# 핫픽스 작업...
cd ../main-workspace
git worktree remove ../hotfix-workspace
시나리오 9: 여러 커밋을 하나로 합치기
# 방법 1: interactive rebase
git rebase -i HEAD~4
# 첫 번째를 pick, 나머지를 squash로 변경
# 방법 2: soft reset
git reset --soft HEAD~4
git commit -m "feat: complete user authentication"
# 방법 3: merge --squash
git checkout main
git merge --squash feature/user-auth
git commit -m "feat: add user authentication system"
시나리오 10: 서브모듈 관리
# 서브모듈 추가
git submodule add https://github.com/org/shared-lib.git libs/shared
# 클론 시 서브모듈 포함
git clone --recurse-submodules https://github.com/org/project.git
# 서브모듈 업데이트
git submodule update --remote --merge
# 모든 서브모듈에 명령 실행
git submodule foreach 'git checkout main && git pull'
시나리오 11: 삭제된 브랜치 복구
# reflog에서 삭제된 브랜치의 마지막 커밋 찾기
git reflog
# abc1234 HEAD@{5}: checkout: moving from deleted-branch to main
# 브랜치 복구
git checkout -b recovered-branch abc1234
시나리오 12: 특정 파일만 다른 브랜치에서 가져오기
# main 브랜치의 특정 파일을 현재 브랜치로 가져오기
git checkout main -- src/config.js
# 특정 커밋의 파일 가져오기
git checkout abc1234 -- src/config.js
시나리오 13: 커밋 날짜 변경
# 마지막 커밋의 날짜를 현재 시간으로 변경
GIT_COMMITTER_DATE="$(date)" git commit --amend --date="$(date)"
# 특정 날짜로 변경 (리베이스 중)
GIT_COMMITTER_DATE="2026-03-22T10:00:00" git commit --amend --date="2026-03-22T10:00:00"
시나리오 14: Git blame으로 코드 추적
# 파일의 각 줄을 누가 마지막으로 수정했는지 확인
git blame src/auth.js
# 특정 줄 범위만 확인
git blame -L 10,20 src/auth.js
# 공백 변경 무시
git blame -w src/auth.js
# 코드 이동도 추적
git blame -M src/auth.js
git blame -C src/auth.js
시나리오 15: git log 고급 활용
# 특정 파일의 변경 이력
git log --follow -p -- src/auth.js
# 특정 문자열이 추가/삭제된 커밋 찾기 (pickaxe)
git log -S "API_KEY" --oneline
# 특정 저자의 커밋만
git log --author="John" --oneline --since="2026-01-01"
# 통계 정보 포함
git log --stat --oneline -10
# 커밋 간 diff
git log -p --oneline -3
시나리오 16: 원격 저장소 관리
# 여러 원격 저장소 추가
git remote add upstream https://github.com/original/repo.git
git remote add deploy git@deploy-server:app.git
# upstream 동기화 (포크 프로젝트)
git fetch upstream
git rebase upstream/main
# 원격 브랜치 정리
git remote prune origin
git fetch --prune
시나리오 17: Git 태그로 릴리스 관리
# 어노테이티드 태그 생성
git tag -a v2.0.0 -m "Release 2.0.0: new payment system"
# 특정 커밋에 태그
git tag -a v1.5.0 abc1234 -m "Hotfix release"
# 태그 푸시
git push origin v2.0.0
git push origin --tags
# 태그 삭제
git tag -d v2.0.0-beta
git push origin --delete v2.0.0-beta
시나리오 18: Git hooks로 자동화
# .husky/pre-commit
#!/bin/sh
npx lint-staged
# .husky/commit-msg
#!/bin/sh
npx commitlint --edit "$1"
# .husky/pre-push
#!/bin/sh
npm test
시나리오 19: 패치 파일 생성 및 적용
# 패치 생성
git diff > my-changes.patch
git format-patch -3 # 최근 3개 커밋을 패치 파일로
# 패치 적용
git apply my-changes.patch
git am *.patch # format-patch로 생성된 패치 적용
시나리오 20: git reflog — 최후의 보루
# reflog 확인 (HEAD의 이동 기록)
git reflog
# 실수로 reset --hard 한 경우 복구
git reflog
# abc1234 HEAD@{2}: commit: important work
git reset --hard abc1234
# 실수로 삭제한 stash 복구
git fsck --unreachable | grep commit
git stash apply abc1234
5. Conventional Commits + Semantic Versioning
5.1 Conventional Commits 형식
type(scope): description
[optional body]
[optional footer(s)]
타입 목록:
| 타입 | 설명 | 예시 |
|---|---|---|
| feat | 새로운 기능 | feat: add login page |
| fix | 버그 수정 | fix: resolve null pointer in auth |
| docs | 문서 변경 | docs: update API documentation |
| style | 코드 스타일 (포맷팅 등) | style: fix indentation |
| refactor | 리팩토링 | refactor: extract auth middleware |
| perf | 성능 개선 | perf: optimize database queries |
| test | 테스트 추가/수정 | test: add unit tests for auth |
| build | 빌드 시스템 변경 | build: update webpack config |
| ci | CI 설정 변경 | ci: add GitHub Actions workflow |
| chore | 기타 잡무 | chore: update dependencies |
Breaking Change 표기:
feat(api)!: change authentication endpoint
BREAKING CHANGE: /auth/login is now /api/v2/auth/login
5.2 Commitlint + Husky 설정
# 패키지 설치
npm install -D @commitlint/cli @commitlint/config-conventional husky
# commitlint 설정
echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
# Husky 초기화
npx husky init
echo 'npx commitlint --edit "$1"' > .husky/commit-msg
5.3 자동 Changelog 생성
# conventional-changelog 설치
npm install -D conventional-changelog-cli
# CHANGELOG.md 생성
npx conventional-changelog -p angular -i CHANGELOG.md -s
# package.json에 스크립트 추가
{
"scripts": {
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
"release": "standard-version"
}
}
5.4 Semantic Release — 완전 자동화
npm install -D semantic-release
{
"release": {
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
"@semantic-release/npm",
"@semantic-release/github",
"@semantic-release/git"
]
}
}
커밋 타입에 따라 자동으로 버전이 결정됩니다:
fix:-> PATCH (1.0.0 -> 1.0.1)feat:-> MINOR (1.0.0 -> 1.1.0)BREAKING CHANGE-> MAJOR (1.0.0 -> 2.0.0)
6. GitHub Actions CI/CD
6.1 기본 워크플로우
name: CI Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run build
6.2 PR 자동 검사 워크플로우
name: PR Checks
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
lint-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- name: Lint
run: npm run lint
- name: Type Check
run: npx tsc --noEmit
- name: Unit Tests
run: npm test -- --coverage
- name: Build
run: npm run build
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
file: ./coverage/lcov.info
6.3 자동 라벨링
name: Auto Label
on:
pull_request:
types: [opened, edited]
jobs:
label:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
# .github/labeler.yml
frontend:
- changed-files:
- any-glob-to-any-file: 'src/components/**'
backend:
- changed-files:
- any-glob-to-any-file: 'src/api/**'
documentation:
- changed-files:
- any-glob-to-any-file: 'docs/**'
tests:
- changed-files:
- any-glob-to-any-file: '**/*.test.*'
6.4 Dependabot 설정
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'weekly'
day: 'monday'
open-pull-requests-limit: 10
labels:
- 'dependencies'
groups:
dev-dependencies:
dependency-type: 'development'
production-dependencies:
dependency-type: 'production'
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'weekly'
6.5 배포 워크플로우
name: Deploy
on:
push:
tags:
- 'v*'
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm run build
- name: Deploy to Production
run: |
echo "Deploying version $GITHUB_REF_NAME"
# 실제 배포 명령어
7. Monorepo 전략
7.1 Monorepo vs Multirepo
| 항목 | Monorepo | Multirepo |
|---|---|---|
| 코드 공유 | 쉬움 | 패키지 발행 필요 |
| 의존성 관리 | 통합 관리 | 개별 관리 |
| CI/CD | 복잡 (선택적 빌드) | 단순 (저장소별) |
| 코드 리뷰 | 전체 맥락 파악 가능 | 저장소별로 분산 |
| 권한 관리 | 복잡 | 저장소별 설정 |
| 대표 사례 | Google, Meta, Microsoft | Netflix, Spotify |
7.2 도구 비교 — Nx vs Turborepo vs Lerna
# Nx 초기화
npx create-nx-workspace@latest my-workspace
# Turborepo 초기화
npx create-turbo@latest
# 프로젝트 구조 예시
my-monorepo/
apps/
web/ # Next.js 웹앱
mobile/ # React Native 앱
api/ # Express API 서버
packages/
ui/ # 공유 UI 컴포넌트
utils/ # 공유 유틸리티
config/ # 공유 설정
turbo.json
package.json
7.3 CODEOWNERS 설정
# .github/CODEOWNERS
# 전체 프로젝트 기본 리뷰어
* @team-lead
# 프론트엔드
/apps/web/ @frontend-team
/packages/ui/ @frontend-team
# 백엔드
/apps/api/ @backend-team
/packages/utils/ @backend-team
# DevOps
/.github/ @devops-team
/docker/ @devops-team
*.yml @devops-team
7.4 선택적 빌드와 테스트
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"test": {
"dependsOn": ["build"]
},
"lint": {}
}
}
# 변경된 패키지만 빌드
npx turbo run build --filter=...[HEAD^1]
# 특정 앱만 빌드
npx turbo run build --filter=web
# 의존성 포함 빌드
npx turbo run build --filter=web...
8. Git 성능 최적화
8.1 Shallow Clone (얕은 클론)
# 최근 1개 커밋만 클론 (CI/CD에서 유용)
git clone --depth 1 https://github.com/org/repo.git
# 나중에 전체 히스토리가 필요하면
git fetch --unshallow
8.2 Partial Clone (부분 클론)
# Blob 없이 클론 (필요할 때 다운로드)
git clone --filter=blob:none https://github.com/org/repo.git
# Tree도 제외 (가장 빠른 클론)
git clone --filter=tree:0 https://github.com/org/repo.git
8.3 Sparse Checkout (희소 체크아웃)
# sparse checkout 활성화
git sparse-checkout init --cone
# 특정 디렉토리만 체크아웃
git sparse-checkout set apps/web packages/ui
# 디렉토리 추가
git sparse-checkout add apps/api
# 설정 확인
git sparse-checkout list
8.4 Git LFS (Large File Storage)
# Git LFS 설치 및 초기화
git lfs install
# 대용량 파일 추적
git lfs track "*.psd"
git lfs track "*.zip"
git lfs track "assets/videos/*"
# .gitattributes 확인
cat .gitattributes
# *.psd filter=lfs diff=lfs merge=lfs -text
# LFS 상태 확인
git lfs ls-files
git lfs status
8.5 Git Maintenance (자동 유지보수)
# 자동 유지보수 활성화
git maintenance start
# 수동으로 가비지 컬렉션
git gc --aggressive
# 객체 압축 상태 확인
git count-objects -vH
# 불필요한 참조 정리
git remote prune origin
git reflog expire --expire=30.days
8.6 Scalar — 대규모 저장소 관리 (Microsoft)
# Scalar 설치 (Git 2.38+에 포함)
scalar register
# 또는 새로 클론
scalar clone https://github.com/org/massive-repo.git
# Scalar가 자동으로 설정하는 것들:
# - Partial clone
# - Sparse checkout
# - Background maintenance
# - Filesystem monitor
# - Commit graph
9. AI + Git (2025~2026)
9.1 AI 커밋 메시지 생성
# Claude Code에서 자동 커밋 메시지 생성
claude commit
# GitHub Copilot CLI
gh copilot suggest "write a commit message for these changes"
# aicommits 도구
npm install -g aicommits
aicommits
9.2 AI 코드 리뷰
GitHub Copilot for Pull Requests는 PR을 자동으로 분석하여 리뷰 코멘트를 생성합니다. 코드의 잠재적 버그, 성능 이슈, 보안 취약점을 찾아줍니다.
# GitHub Copilot 자동 리뷰 활성화 (저장소 설정에서)
# Settings > Code review > Copilot code review > Enable
9.3 Claude Code와 Git 워크플로우
Claude Code는 Git 작업을 직접 도와줍니다.
# 변경사항 리뷰 요청
claude "review my staged changes"
# 커밋 메시지 작성
claude "write a conventional commit message for my changes"
# PR 설명 생성
claude "write a PR description for the current branch"
# 머지 충돌 해결
claude "help me resolve the merge conflicts in src/auth.js"
9.4 자동 PR 설명 생성
name: Auto PR Description
on:
pull_request:
types: [opened]
jobs:
describe:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate PR description
uses: anthropics/claude-code-action@v1
with:
prompt: |
Analyze the diff of this PR and generate a clear description
including what changed, why, and any risks.
실력 점검 퀴즈
퀴즈 1: Git 객체
Q: git에서 파일 이름은 어떤 객체에 저장될까요? Blob일까요, Tree일까요?
A: Tree 객체에 저장됩니다.
Blob은 파일의 순수 내용만 저장하며, 파일 이름과 경로 정보는 Tree 객체가 관리합니다. 이 설계 덕분에 파일 이름이 바뀌어도 내용이 같으면 같은 Blob을 재사용할 수 있습니다.
# Tree 객체에서 파일 이름 확인
git cat-file -p HEAD^{tree}
# 100644 blob a906cb... README.md <-- 파일 이름은 Tree에!
퀴즈 2: Rebase 안전성
Q: 다음 중 안전한 리베이스 작업은? (A: main에서 feature 리베이스, B: feature에서 main 리베이스, C: 둘 다 안전)
A: B가 안전합니다.
리베이스의 황금 규칙은 "공유된 브랜치를 리베이스하지 마라"입니다. main은 공유 브랜치이므로 main 위에서 리베이스하면 안 됩니다. 반면 feature는 개인 브랜치이므로 main의 최신 커밋 위에 feature의 커밋을 재적용하는 것은 안전합니다.
퀴즈 3: Reset 모드
Q: git reset의 세 가지 모드(--soft, --mixed, --hard)의 차이점은 무엇일까요?
A:
--soft: HEAD만 이동. 스테이징 영역과 작업 디렉토리는 그대로. 커밋만 취소하고 싶을 때.--mixed(기본값): HEAD 이동 + 스테이징 영역 초기화. 작업 디렉토리는 그대로. 커밋과 스테이징을 취소할 때.--hard: HEAD 이동 + 스테이징 영역 + 작업 디렉토리 모두 초기화. 모든 변경사항 버릴 때. (위험!)
# 예시: 최근 3개 커밋을 취소하되 코드는 유지
git reset --soft HEAD~3
# 이제 변경사항이 스테이징된 상태로 남아있음
퀴즈 4: Cherry-pick 충돌
Q: cherry-pick 중 충돌이 발생하면 어떻게 해결하나요?
A: merge 충돌과 동일한 방식으로 해결합니다.
git cherry-pick abc1234
# CONFLICT 발생
# 1. 충돌 파일 수정
# 2. 스테이징
git add resolved-file.js
# 3. cherry-pick 계속
git cherry-pick --continue
# 또는 cherry-pick 취소
git cherry-pick --abort
퀴즈 5: Monorepo에서의 선택적 CI
Q: Monorepo에서 프론트엔드 코드만 변경했을 때, 백엔드 테스트도 돌려야 할까요?
A: 의존성에 따라 다릅니다.
프론트엔드가 백엔드 패키지에 의존하지 않는다면, 백엔드 테스트를 돌릴 필요가 없습니다. 이것이 Nx나 Turborepo 같은 도구가 제공하는 "영향 분석(affected analysis)"의 핵심입니다.
# Nx: 변경에 영향받는 프로젝트만 테스트
npx nx affected --target=test
# Turborepo: 변경된 패키지와 의존 패키지만 빌드
npx turbo run build --filter=...[HEAD^1]
하지만 공유 패키지(utils, config 등)가 변경되었다면, 그 패키지에 의존하는 모든 프로젝트의 테스트를 돌려야 합니다.
참고 자료
공식 문서
- Git 공식 문서 — 가장 정확한 레퍼런스
- GitHub Docs — GitHub 기능 가이드
- Pro Git Book (한국어) — 무료 온라인 서적
브랜칭 전략
- Trunk Based Development — TBD 공식 사이트
- GitHub Flow Guide
- A successful Git branching model — Git Flow 원문
CI/CD
- GitHub Actions 공식 문서
- Semantic Release — 자동 버전 관리
- Conventional Commits — 커밋 규약
Monorepo
- Nx 공식 문서
- Turborepo 공식 문서
- Monorepo Tools — 도구 비교
성능
- Git LFS — 대용량 파일 관리
- Scalar — 대규모 저장소
- git-filter-repo — 히스토리 정리
심화
- Oh Shit, Git!?! — Git 실수 복구 가이드
- Learn Git Branching — 시각적 Git 학습
- Git Internals (PDF) — Git 내부 구조
마무리
Git은 단순한 도구가 아니라 개발 문화를 형성하는 핵심 인프라입니다. 깔끔한 커밋 히스토리는 팀의 협업 능력을 반영하고, 효과적인 브랜칭 전략은 배포 안정성을 결정합니다.
이 글에서 다룬 내용을 한 번에 모두 익힐 필요는 없습니다. 먼저 일상적으로 사용하는 명령어의 동작 원리를 이해하고, 점차 고급 기법을 적용해 보세요. 특히 interactive rebase와 bisect는 한번 익히면 생산성이 크게 올라가는 도구입니다.
기억하세요: 좋은 커밋 히스토리는 미래의 자신과 동료에게 보내는 편지입니다. 오늘부터 Conventional Commits를 시작해 보는 것은 어떨까요?