들어가며
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 객체
**A: Tree 객체에 저장됩니다.**
Blob은 파일의 순수 내용만 저장하며, 파일 이름과 경로 정보는 Tree 객체가 관리합니다. 이 설계 덕분에 파일 이름이 바뀌어도 내용이 같으면 같은 Blob을 재사용할 수 있습니다.
Tree 객체에서 파일 이름 확인
git cat-file -p HEAD^{tree}
100644 blob a906cb... README.md <-- 파일 이름은 Tree에!
퀴즈 2: Rebase 안전성
**A: B가 안전합니다.**
리베이스의 황금 규칙은 "공유된 브랜치를 리베이스하지 마라"입니다. main은 공유 브랜치이므로 main 위에서 리베이스하면 안 됩니다. 반면 feature는 개인 브랜치이므로 main의 최신 커밋 위에 feature의 커밋을 재적용하는 것은 안전합니다.
퀴즈 3: Reset 모드
**A:**
- `--soft`: HEAD만 이동. 스테이징 영역과 작업 디렉토리는 그대로. 커밋만 취소하고 싶을 때.
- `--mixed` (기본값): HEAD 이동 + 스테이징 영역 초기화. 작업 디렉토리는 그대로. 커밋과 스테이징을 취소할 때.
- `--hard`: HEAD 이동 + 스테이징 영역 + 작업 디렉토리 모두 초기화. 모든 변경사항 버릴 때. (위험!)
예시: 최근 3개 커밋을 취소하되 코드는 유지
git reset --soft HEAD~3
이제 변경사항이 스테이징된 상태로 남아있음
퀴즈 4: 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
**A: 의존성에 따라 다릅니다.**
프론트엔드가 백엔드 패키지에 의존하지 않는다면, 백엔드 테스트를 돌릴 필요가 없습니다. 이것이 Nx나 Turborepo 같은 도구가 제공하는 "영향 분석(affected analysis)"의 핵심입니다.
Nx: 변경에 영향받는 프로젝트만 테스트
npx nx affected --target=test
Turborepo: 변경된 패키지와 의존 패키지만 빌드
npx turbo run build --filter=...[HEAD^1]
하지만 공유 패키지(utils, config 등)가 변경되었다면, 그 패키지에 의존하는 모든 프로젝트의 테스트를 돌려야 합니다.
참고 자료
공식 문서
1. [Git 공식 문서](https://git-scm.com/doc) — 가장 정확한 레퍼런스
2. [GitHub Docs](https://docs.github.com) — GitHub 기능 가이드
3. [Pro Git Book (한국어)](https://git-scm.com/book/ko/v2) — 무료 온라인 서적
브랜칭 전략
4. [Trunk Based Development](https://trunkbaseddevelopment.com/) — TBD 공식 사이트
5. [GitHub Flow Guide](https://docs.github.com/en/get-started/using-github/github-flow)
6. [A successful Git branching model](https://nvie.com/posts/a-successful-git-branching-model/) — Git Flow 원문
CI/CD
7. [GitHub Actions 공식 문서](https://docs.github.com/en/actions)
8. [Semantic Release](https://semantic-release.gitbook.io/) — 자동 버전 관리
9. [Conventional Commits](https://www.conventionalcommits.org/) — 커밋 규약
Monorepo
10. [Nx 공식 문서](https://nx.dev/)
11. [Turborepo 공식 문서](https://turbo.build/repo)
12. [Monorepo Tools](https://monorepo.tools/) — 도구 비교
성능
13. [Git LFS](https://git-lfs.com/) — 대용량 파일 관리
14. [Scalar](https://github.com/microsoft/scalar) — 대규모 저장소
15. [git-filter-repo](https://github.com/newren/git-filter-repo) — 히스토리 정리
심화
16. [Oh Shit, Git!?!](https://ohshitgit.com/) — Git 실수 복구 가이드
17. [Learn Git Branching](https://learngitbranching.js.org/) — 시각적 Git 학습
18. [Git Internals (PDF)](https://github.com/pluralsight/git-internals-pdf) — Git 내부 구조
마무리
Git은 단순한 도구가 아니라 개발 문화를 형성하는 핵심 인프라입니다. 깔끔한 커밋 히스토리는 팀의 협업 능력을 반영하고, 효과적인 브랜칭 전략은 배포 안정성을 결정합니다.
이 글에서 다룬 내용을 한 번에 모두 익힐 필요는 없습니다. 먼저 일상적으로 사용하는 명령어의 동작 원리를 이해하고, 점차 고급 기법을 적용해 보세요. 특히 interactive rebase와 bisect는 한번 익히면 생산성이 크게 올라가는 도구입니다.
기억하세요: **좋은 커밋 히스토리는 미래의 자신과 동료에게 보내는 편지입니다.** 오늘부터 Conventional Commits를 시작해 보는 것은 어떨까요?
현재 단락 (1/543)
Git은 모든 개발자의 일상 도구입니다. 하지만 대부분의 개발자가 `git add`, `git commit`, `git push` 정도만 사용하고, Git이 제공하는 강력한 기능의...