Skip to content

✍️ 필사 모드: Git 완전 정복: 주니어부터 시니어까지, 실무에서 바로 쓰는 Git 고급 워크플로우

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

들어가며

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 FlowGitHub FlowTrunk-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

사용 가능한 명령어:

명령약자설명
pickp커밋을 그대로 사용
rewordr커밋 메시지만 변경
edite커밋을 수정 (파일 변경 가능)
squashs이전 커밋과 합치고 메시지 편집
fixupf이전 커밋과 합치고 메시지 버림
dropd커밋 삭제

실전 예시 — 지저분한 히스토리 정리:

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 비교:

항목revertreset
히스토리보존 (새 커밋 추가)변경 (커밋 삭제)
안전성안전위험
공유 브랜치사용 가능사용 금지
되돌리기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
ciCI 설정 변경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

항목MonorepoMultirepo
코드 공유쉬움패키지 발행 필요
의존성 관리통합 관리개별 관리
CI/CD복잡 (선택적 빌드)단순 (저장소별)
코드 리뷰전체 맥락 파악 가능저장소별로 분산
권한 관리복잡저장소별 설정
대표 사례Google, Meta, MicrosoftNetflix, 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 등)가 변경되었다면, 그 패키지에 의존하는 모든 프로젝트의 테스트를 돌려야 합니다.


참고 자료

공식 문서

  1. Git 공식 문서 — 가장 정확한 레퍼런스
  2. GitHub Docs — GitHub 기능 가이드
  3. Pro Git Book (한국어) — 무료 온라인 서적

브랜칭 전략

  1. Trunk Based Development — TBD 공식 사이트
  2. GitHub Flow Guide
  3. A successful Git branching model — Git Flow 원문

CI/CD

  1. GitHub Actions 공식 문서
  2. Semantic Release — 자동 버전 관리
  3. Conventional Commits — 커밋 규약

Monorepo

  1. Nx 공식 문서
  2. Turborepo 공식 문서
  3. Monorepo Tools — 도구 비교

성능

  1. Git LFS — 대용량 파일 관리
  2. Scalar — 대규모 저장소
  3. git-filter-repo — 히스토리 정리

심화

  1. Oh Shit, Git!?! — Git 실수 복구 가이드
  2. Learn Git Branching — 시각적 Git 학습
  3. Git Internals (PDF) — Git 내부 구조

마무리

Git은 단순한 도구가 아니라 개발 문화를 형성하는 핵심 인프라입니다. 깔끔한 커밋 히스토리는 팀의 협업 능력을 반영하고, 효과적인 브랜칭 전략은 배포 안정성을 결정합니다.

이 글에서 다룬 내용을 한 번에 모두 익힐 필요는 없습니다. 먼저 일상적으로 사용하는 명령어의 동작 원리를 이해하고, 점차 고급 기법을 적용해 보세요. 특히 interactive rebase와 bisect는 한번 익히면 생산성이 크게 올라가는 도구입니다.

기억하세요: 좋은 커밋 히스토리는 미래의 자신과 동료에게 보내는 편지입니다. 오늘부터 Conventional Commits를 시작해 보는 것은 어떨까요?

현재 단락 (1/558)

Git은 모든 개발자의 일상 도구입니다. 하지만 대부분의 개발자가 `git add`, `git commit`, `git push` 정도만 사용하고, Git이 제공하는 강력한 기능의...

작성 글자: 0원문 글자: 19,810작성 단락: 0/558