구성 & 초기화
전역 & 로컬 구성
Git은 세 가지 수준에서 구성을 저장합니다: 시스템(/etc/gitconfig), 전역(사용자용 ~/.gitconfig), 로컬(저장소당 .git/config). 하위 수준이 상위 수준을 덮어씁니다. 커밋하기 전에 항상 user.name과 user.email을 설정하세요. 그렇지 않으면 커밋이 도움되지 않는 기본 ID를 사용합니다. init.defaultBranch를 main으로 설정하면 더 이상 사용되지 않는 master 기본값을 피하고 현대 관례에 맞춥니다.
# set user identity (required for commits)
git config --global user.name "Alice Lee"
git config --global user.email "[email protected]"
# set default editor and branch name
git config --global core.editor "code --wait"
git config --global init.defaultBranch main
# view all settings and their origin
git config --list --show-origin
# edit config files directly
git config --global --edit # ~/.gitconfig
git config --edit # repo .git/config저장소 생성 & 복제
git init은 모든 버전 데이터를 저장하는 숨겨진 .git 디렉토리를 추가하여 빈 저장소를 만듭니다. git clone은 전체 기록을 포함하여 원격 저장소를 복사합니다. 최신 스냅샷만 필요할 때(예: CI 빌드) --depth 1을 사용하여 얕은 복제를 하세요 — 다운로드 크기를 크게 줄입니다. --single-branch는 관련 없는 브랜치를 가져오지 않습니다.
# create a new repo from scratch in current dir
mkdir my-app && cd my-app
git init
# clone a remote repository
git clone https://github.com/user/repo.git
# clone into a specific folder name
git clone https://github.com/user/repo.git my-folder
# clone a single branch (saves bandwidth)
git clone -b dev --single-branch https://github.com/user/repo.git
# shallow clone: only the latest commit
git clone --depth 1 https://github.com/user/repo.git별칭 & 단축키
별칭을 사용하면 자주 사용하는 명령이나 명령 시퀀스에 대해 더 짧은 이름을 정의할 수 있습니다. gitconfig의 [alias] 섹션에 저장됩니다. !로 시작하는 별칭은 셸 명령으로 실행되어 복잡한 워크플로를 가능하게 합니다. 위의 lg 별 칭은 브랜치 구조를 이해하는 데 매우 유용한 간결한 시각적 기록 그래프를 생성합니다.
# create shortcuts for common commands
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --all"
# now use them
git co main
git lg
# alias that runs an external command (starts with !)
git config --global alias.unstage "reset HEAD --"
git unstage file.txt도움말 & 문서
Git은 포괄적인 내장 문서와 함께 제공됩니다. git help <명령>은 페이저에서 매뉴얼 페이지를 엽니다. -h 플래그는 옵션의 빠른 한 화면 요약을 제공합니다. 가이드(git help -g)에는 튜토리얼, 용어집 및 일상적인 워크플로 참조가 포함되어 있습니다 — 용어를 배우는 초보자에게 훌륭합니다.
# open the full manual for a command
git help commit
git commit --help
# show a concise synopsis
git commit -h
# list all git commands
git help -a
# list all guides (tutorial, glossary, etc.)
git help -g
git help glossary.gitignore 패턴
.gitignore는 버전 관리에서 제외할 파일을 Git에 알려줍니다 — 빌드 산출물, 종속성 및 비밀에 필수적입니다. 패턴은 glob 구문을 사용합니다; 후행 슬래시는 디렉토리를 매칭합니다. !를 접두어로 하면 패턴을 부정하여 파일이 추적되도록 강제합니다. .gitignore 자체는 커밋하여 팀이 무시 규칙을 공유해야 합니다. 이미 추적된 파일은 새 무시 패턴의 영향을 받지 않습니다 — 먼저 git rm --cached로 제거하세요.
# .gitignore file — patterns for files to skip
node_modules/
*.log
.env
.env.local
dist/
build/
# but track this specific file even if it matches
!important.log
# ignore all .txt files in build/ but not subdirs
build/*.txt
# ignore everything in a folder except one file
secrets/*
!secrets/template.env스테이징 & 커밋
상태 & 스테이징
Git은 2단계 모델을 사용합니다: 변경 사항은 커밋되기 전에 스테이징 영역(인덱스)으로 이동합니다. git status는 수정, 스테이지 및 추적되지 않은 항목을 보여줍니다. git add -p를 사용하면 패치의 개별 헝크를 스테이징할 수 있습니다 — 지저분한 작업 트리를 집중적이고 논리적인 커밋으로 분할하는 데 매우 유용합니다. git restore --staged(현대 명령)를 사용하여 편집 내용을 잃지 않고 스테이지 해제하세요.
# see current state of working tree
git status
git status -s # short format
git status -sb # short + branch info
# stage changes
git add file.txt # one file
git add src/ # a directory
git add . # all changes in repo
git add -p # stage interactively by hunk
# unstage a file (keep changes in working dir)
git restore --staged file.txt
git reset HEAD file.txt # older syntax변경 사항 커밋
커밋은 스테이지된 변경 사항의 스냅샷을 기록합니다. 명령형으로 메시지를 작성하세요('기능 추가'가 아니라 'add feature'). -a 플래그는 이미 추적된 파일만 스테이징합니다 — 새 파일은 여전히 git add가 필요합니다. --amend는 마지막 커밋을 다시 작성합니다; 오타를 수정하거나 잊어버린 파일을 추가하는 데 사용하지만, 공유 브랜치에 이미 푸시한 커밋은 절대 수정하지 마세요.
# commit staged changes with a message
git commit -m "feat: add login form"
# multi-line commit message
git commit -m "feat: add login form" -m "Closes #42"
# stage tracked files AND commit in one step
git commit -am "fix: correct typo"
# amend the previous commit (keep message)
git commit --amend --no-edit
# amend and edit the message
git commit --amend -m "feat: add login form (v2)"커밋 메시지 규칙
Conventional Commits는 구조화된 커밋 메시지에 대한 널리 채택된 사양입니다. 타입 접두어(feat, fix, docs 등)는 자동화된 변경 로그 생성과 시맨틱 버저닝을 가능하게 합니다. ! 마커는 호환성을 깨는 변경을 나타냅니다. 빈 줄은 제목(<=50자)을 본문과 분리하고, 또 다른 빈 줄은 GitHub에서 이슈를 자동으로 닫는 'Closes #123' 같은 푸터를 분리합니다.
# Conventional Commits format
feat: add user registration endpoint
fix: resolve crash on empty cart
docs: update API reference
style: format login component
refactor: extract validation logic
test: add unit tests for parser
chore: upgrade dependencies
# with scope and breaking change marker
feat(api): add pagination to list endpoint
fix!: change default port (BREAKING CHANGE)
# with body and footer
feat: add dark mode
Implement theme toggle using CSS variables.
Closes #128log로 기록 보기
git log는 기록을 탐색하는 기본 도구입니다. --oneline --graph --all 은 브랜치 구조를 한눈에 이해하는 가장 유용한 조합입니다. --author, 날짜 범위 또는 --grep로 메시지 내용으로 필터링할 수 있습니다. --stat는 어떤 파일이 변경되었고 몇 줄인지 보여주고, --patch는 모든 커밋의 전체 diff를 보여줍니다.
# full history with details
git log
git log --oneline # one line per commit
git log --oneline --graph --all # visual branch graph
git log -n 5 # last 5 commits
# filter by author, date, or message
git log --author="Alice"
git log --since="2 weeks ago"
git log --grep="fix"
# show files changed in each commit
git log --stat
git log --patch # full diffsDiff & Show
git diff는 스냅샷을 비교합니다 — 인수가 없으면 인덱스에 대한 스테이지되지 않은 변경 사항을 보여줍니다. --staged는 인덱스를 HEAD와 비교합니다. git show는 단일 커밋의 메타데이터와 패치를 표시합니다. HEAD:path 구문을 사용하면 체크아웃하지 않고 모든 커밋에서 모든 파일의 내용을 볼 수 있어, 이전 버전을 복구하거나 기록을 검사하는 데 편리합니다.
# compare working tree, index, and commits
git diff # unstaged changes
git diff --staged # staged but uncommitted
git diff HEAD # all changes vs last commit
git diff main feature # compare two branches
git diff abc1234 def5678 # compare two commits
# inspect a single commit
git show HEAD # latest commit diff + metadata
git show abc1234
git show HEAD:file.txt # view a file at a given commit브랜칭 & 병합
브랜치 생성 & 전환
Git의 브랜치는 커밋에 대한 가벼운 포인터입니다 — 생성이 거의 즉각적입니다. git switch(Git 2.23+)는 체크아웃을 파일 복원용으로 남겨두고 브랜치 변경을 위한 현대적이고 안전한 대안입니다. -d는 병합되지 않은 브랜치 삭제를 거부합니다(작업 보호); -D는 강제 삭제합니다. 병합 후 항상 브랜치를 삭제하여 브랜치 목록을 깨끗하게 유지하세요.
# list branches
git branch # local branches
git branch -a # local + remote
git branch -vv # with tracking info
# create and switch
git branch feature # create only
git checkout feature # switch to it
git checkout -b feature # create + switch (classic)
git switch -c feature # create + switch (modern)
# delete branches
git branch -d feature # safe delete (merged only)
git branch -D feature # force delete브랜치 병합
패스트포워드 병합은 대상에 새 커밋이 없을 때 브랜치 포인터를 단순히 앞으로 이동합니다 — 선형 기록을 생성합니다. --no-ff는 병합 커밋을 강제하여 브랜치가 존재했다는 사실을 보존합니다(기능 추적에 유용). --squash는 모든 브랜치 커밋을 단일 스테이지된 변경 사항으로 결합하여 한 번에 커밋합니다 — main에 통합하기 전에 시끄러운 기능 기록을 정리하는 데 좋습니다.
# merge feature into main
git checkout main
git merge feature
# fast-forward merge (default when possible)
# main just moves forward to feature's commit
# create a merge commit (preserves branch history)
git merge --no-ff feature -m "Merge feature branch"
# squash all feature commits into one
git merge --squash feature
git commit -m "feat: add feature (squashed)"
# abort a merge with conflicts
git merge --abort병합 충돌 해결
충돌은 동일한 줄이 두 브랜치에서 다르게 변경되었을 때 발생합니다. Git은 양쪽을 보여주는 충돌 마커(<<<<<<<, =======, >>>>>>>)를 삽입합니다. 파일을 원하는 최종 상태로 편집한 다음 git add로 해결됨을 표시하여 해결하세요. 병합을 완료하려면 커밋하세요. git mergetool은 시각적 diff 도구를 시작합니다. 감당하기 어려우면 git merge --abort가 병합 전 상태로 돌아갑니다.
# a conflict produces markers in the file
# <<<<<<< HEAD
# my changes (current branch)
# =======
# their changes (incoming branch)
# >>>>>>> feature
# edit the file to resolve, then:
git add resolved-file.txt
git commit # finalize the merge
# use a merge tool
git mergetool
# see which files conflict
git status
# abandon the merge
git merge --abort리베이스
Rebase는 브랜치의 커밋을 다른 브랜치 위에 재생하여 병합 커밋 없이 선형 기록을 생성합니다. 대화형 리베이스(-i)는 강력한 도구입니다: squash는 커밋을 병합하고, reword는 메시지를 편집하고, drop은 커밋을 제거하고, edit는 커밋을 수정하기 위 해 일시 중지합니다. 푸시되고 공유된 커밋은 절대 리베이스하지 마세요 — 기록을 다시 작성하여 팀원의 저장소를 손상시킵니다. 자신의 로컬 브랜치에서만 리베이스를 사용하세요.
# rebase feature onto main (replay feature commits)
git checkout feature
git rebase main
# interactive rebase — rewrite last 5 commits
git rebase -i HEAD~5
# options: pick, reword, squash, fixup, drop, edit
# continue, skip, or abort during a rebase
git rebase --continue
git rebase --skip
git rebase --abort
# rebase while pulling
git pull --rebase origin main체리픽 & Reflog
Cherry-pick은 다른 브랜치의 개별 커밋을 현재 브랜치에 적용합니다 — 전체 브랜치를 병합하지 않고 버그 수정을 백포트하는 데 유용합니다. reflog는 ~90일 동안 보관되는 모든 HEAD 이동(커밋, 체크아웃, 리셋)의 로컬 로그입니다. 안전망입니다: 파괴적인 리셋 후에도 reflog에서 이전 커밋 해시를 찾아 복구할 수 있습니다. reflog 데이터는 로컬 전용이며 푸시되지 않습니다.
# apply a specific commit onto current branch
git cherry-pick abc1234
git cherry-pick abc1234 def5678 # multiple commits
git cherry-pick abc1234..def5678 # range (exclusive start)
# reflog: record of where HEAD has been
git reflog
git reflog show feature
# recover a 'lost' commit
git reset --hard HEAD@{2}
# view a branch's history of moves
git reflog show main원격 저장소
원격 관리
원격은 다른 저장소에 대한 이름이 지정된 참조이며, 일반적으로 포크의 경우 origin이고 원래 프로젝트의 경우 upstream입니다. git remote -v는 가져오기 및 푸시 URL을 보여줍니다. GitHub의 포크는 원래 저장소와 동기화하기 위해 upstream 원격을 사용합니다: upstream에서 가져오고, 병합 또는 리베이스한 다음 origin에 푸시합니다. set-url은 HTTPS와 SSH 인증 사이를 전환하는 데 편리합니다.
# list configured remotes
git remote -v
git remote show origin
# add a remote
git remote add origin https://github.com/user/repo.git
# add an upstream remote (for forks)
git remote add upstream https://github.com/original/repo.git
# rename or remove
git remote rename origin upstream
git remote remove origin
# change a remote URL (e.g. HTTPS to SSH)
git remote set-url origin [email protected]:user/repo.gitFetch, Pull & Push
fetch는 원격 데이터를 다운로드하지만 작업 트리는 그대로 둡니다 — 병합 전에 검사하기에 안전합니다. pull = fetch + merge(또는 --rebase가 있는 리베이스). 새 브랜치의 첫 번째 푸시는 향후 git push/pull이 인수 없이 작동하도록 추적을 설정하기 위해 -u가 필요합니다. --force-with-lease는 --force의 안전한 대안입니다: 누구도 그 사이에 푸시하지 않은 경우에만 원격을 덮어써 팀원의 작업을 실수로 덮어쓰는 것을 방지합니다.
# download remote changes without merging
git fetch origin
git fetch --all --prune # all remotes, drop deleted branches
# fetch + merge in one step
git pull
git pull --rebase # rebase instead of merge
# push local commits to remote
git push origin main
git push -u origin feature # push + set upstream tracking
git push # subsequent pushes (uses tracking)
# force push (rewrites remote history — DANGER)
git push --force-with-lease # safer than --force추적 & 동기화 브랜치
추적 브랜치는 로컬 브랜치를 원격 브랜치에 연결하여 git pull과 git push가 지정 없이 어디서 가져오고/푸시할지 알게 합니다. -u(--set-upstream-to의 약자)는 첫 번째 푸시에서 이를 설정합니다. 팀원이 원격 브랜치를 삭제하면 로컬 원격 추적 참조가 만료됩니다 — git remote prune origin이 정리합니다. git fetch --prune은 가져오는 동안 자동으로 이를 수행합니다.
# set upstream for current branch
git branch -u origin/main
git branch --set-upstream-to=origin/main
# create a local branch tracking a remote one
git checkout -b feature origin/feature
git switch feature # auto-detects tracking branch
# delete a remote branch
git push origin --delete feature
# list all remote-tracking branches
git branch -r
git remote prune origin # remove stale remote refs풀 리퀘스트 워크플로
표준 GitHub 흐름: 기능 브랜치를 만들고, 푸시하고, 리뷰를 위해 Pull Request를 열고, 병합 후 브랜치를 삭제합니다. 포크의 경우 upstream 원격을 통해 원래 저장소에서 변경 사항을 가져올 수 있습니다. 포크의 main을 upstream과 정기적으로 동기화하면 나중에 크고 고통스러운 병합을 방지합니다. 많은 팀이 브랜치 목록을 깔끔하게 유지하기 위해 '병합 시 브랜 치 자동 삭제'를 활성화합니다.
# typical feature workflow
git checkout -b feature/login
# ... make changes, commit ...
git push -u origin feature/login
# create PR on GitHub, then after merge:
git checkout main
git pull origin main
git branch -d feature/login
# sync a fork with its upstream
git fetch upstream
git checkout main
git merge upstream/main
git push origin main베어 저장소 & 미러
베어 저장소는 작업 트리가 없습니다 — .git 데이터만 저장합니다. 베어 저장소는 여러 사람이 푸시하고 풀하는 중앙 원격으로 서버(자체 호스팅 Git 등)에서 사용됩니다. --mirror는 원격 추적 참조를 포함한 모든 것을 복제하며 백업이나 호스트 간 저장소 마이그레이션에 사용됩니다. --all은 모든 브랜치를 푸시합니다; --tags는 모든 태그를 푸시합니다.
# create a bare repo (no working tree) — for servers
git init --bare project.git
# mirror clone (full copy including all refs)
git clone --mirror https://github.com/user/repo.git
# push all branches and tags
git push --all
git push --tags
# push a specific branch to a specific remote
git push origin local-name:remote-name변경 취소
Reset: Soft, Mixed, Hard
reset은 현재 브랜치 포인터를 이동합니다. --soft는 변경 사항을 스테이지된 상태로 유지합니다(커밋만 취소) — 재커밋에 이상적입니다. --mixed(기본값)는 스테이지 해제하지만 작업 트리 변경 사항은 유지합니다. --hard는 모든 것을 영구적으로 폐기합니다 — 유일한 복구는 reflog입니다. 공유 기록을 다시 작성하므로 푸시한 커밋에는 절대 --hard를 사용하지 마세요.
# reset moves HEAD and optionally the index/worktree
git reset --soft HEAD~1 # undo commit, keep staged
git reset --mixed HEAD~1 # undo commit + unstage (DEFAULT)
git reset --hard HEAD~1 # undo commit + discard changes
# reset to a specific commit
git reset --hard abc1234
# reset a single file to HEAD
git reset HEAD file.txt # unstage
git checkout -- file.txt # discard working changesRevert(안전한 취소)
reset(기록을 다시 작성)과 달리 revert는 대상 커밋을 역전하는 새 커밋을 추가합니다 — 기록이 보존되므로 공유 브랜치에 안전합니다. 이미 푸시된 변경을 취소하는 올바른 방법입니다. 병합 커밋을 되돌리려면 어느 부모 줄을 유지할지 지정하기 위해 -m 1이 필요합니다(1 = 병합한 브랜치).
# revert creates a NEW commit that undoes another
git revert abc1234
git revert HEAD # undo last commit
# revert a range
git revert HEAD~3..HEAD
# revert without committing (stage the inverse)
git revert --no-commit abc1234
# revert a merge commit
git revert -m 1 abc1234 # -m 1 = keep main branch parentRestore & Clean
git restore(Git 2.23+)는 작업 트리 작업을 위한 현대적이고 집중된 명령으로, 체크아웃의 관심사를 분리합니다. --staged는 작업 변경 사항을 건드리지 않고 스테이지 해제합니다. git clean은 추적되지 않은 파일을 제거합니다 — 삭제될 항목을 미리 보려면 항상 -n(드라이 런)으로 먼저 실행하세요. -x는 공격적입니다: gitignored 파일도 삭제하여 클린 빌드에 유용하지만 비밀이나 빌드 출력을 지울 수 있습니다.
# discard unstaged changes in a file
git restore file.txt
git checkout -- file.txt # older syntax
# unstage a file (keep working changes)
git restore --staged file.txt
# restore a file from a specific commit
git restore --source=abc1234 file.txt
# remove untracked files
git clean -n # dry run (preview)
git clean -fd # remove untracked files + dirs
git clean -fdx # also remove ignored filesAmend & Fixup
--amend는 마지막 커밋을 다시 작성합니다 — 오타 수정이나 잊어버린 파일 추가에 편리하지만, 푸시된 커밋은 절대 수정하지 마세요. fixup 워크플로는 우아합니다: 작은 문제를 발견할 때마다 fixup 커밋을 만들고, git rebase -i --autosquash가 자동으로 재정렬하여 대상 커밋에 스쿼시합니다. 이는 기록을 깨끗하게 유지하면서 작은 수정을 점진적으로 커밋할 수 있게 합니다.
# amend the last commit (message + content)
git add forgotten-file.txt
git commit --amend --no-edit
# change only the commit message
git commit --amend -m "better message"
# create a fixup commit (for later autosquash)
git commit --fixup=abc1234
# squash fixups during interactive rebase
git rebase -i --autosquash abc1234~1Reflog 복구
reflog는 안전망입니다. 모든 커밋, 체크아웃, 리셋 및 리베이스를 기록합니다 — 커밋을 '파괴'하는 작업까지도. 항목은 ~90일 동안 유지됩니다. 실수로 reset --hard하거나 브랜치를 삭제한 경우, reflog에서 분리된 커밋 해시를 찾아 리셋하거나 가리키는 새 브랜치를 만드세요. reflog는 로컬 전용이므로 오프라인에서도 작동합니다.
# reflog records every HEAD movement
git reflog
# abc1234 HEAD@{0}: reset: moving to abc1234
# def5678 HEAD@{1}: commit: feat: add x
# ghi9012 HEAD@{2}: checkout: moving to feature
# recover a 'lost' commit
git reset --hard def5678
# recover a deleted branch
git branch recovered-feature def5678
# reflog for a specific branch
git reflog show feature스태시 & 워크플로
변경 사항 스태시
Stash는 커밋되지 않은 변경 사항을 보관하여 깨끗한 트리로 브랜치를 전환하거나 업데이트를 풀할 수 있게 합니다. apply는 스태시를 목록에 유지합니다(여러 브랜치에 적용하려는 경우 유용); pop은 적용하고 제거합니다. 스태시는 stash@{N}으로 참조되는 LIFO 스택입니다. clear는 주의해서 사용하세요 — 모든 스태시를 영구적으로 폐기합니다.
# save uncommitted changes (reverts working tree to HEAD)
git stash
git stash push -m "wip: login form" # with a message
# list, show, apply
git stash list
git stash show -p stash@{0} # show diff
git stash apply # apply latest, keep stash
git stash pop # apply latest, drop stash
# apply a specific stash
git stash apply stash@{2}
# drop a stash
git stash drop stash@{0}
git stash clear # drop ALL stashes부분 & 선택적 스태시
이 플래그는 스태시할 항목을 세밀하게 제어합니다. --keep-index는 논리적 커밋을 스테이지했지만 해당 변경 사항만 테스트하려는 경우 유용합니다 — 나머지를 스태시하고, 테스트를 실행한 다음 pop하세요. -u는 추적되지 않은 파일을 포함합니다(그렇지 않으면 작업 트리에 남음). -p는 git add -p처럼 특정 헝크를 선택할 수 있게 합니다.
# stash only staged changes
git stash --staged
# stash only unstaged changes (keep staged)
git stash --keep-index
# stash interactively by hunk
git stash -p
# stash including untracked files
git stash -u
git stash --include-untracked
# stash everything (even ignored)
git stash -a스태시 브랜치 & 생성
git stash branch는 스태시의 원래 부모 커밋에 새 브랜치를 만들고 거기에 스태시를 적용합니다 — 충돌로 인해 스태시가 현재 브랜치에 더 이상 깔끔하게 적용되지 않을 때 완벽합니다. 보관 또는 공유를 위해 show -p로 스태시를 패치 파일로 내보낼 수도 있습니다. 스태시는 로컬이며 푸시되지 않으므로 장기 저장에 사용해서는 안 됩니다.
# create a branch from a stash (great for conflicts)
git stash branch feature/wip stash@{0}
# create a commit from a stash without applying
git stash store -m "saved wip" stash@{0}
# apply a stash to a different branch
git checkout other-branch
git stash apply stash@{0}
# inspect stash contents
git stash show stash@{0} --stat
git stash show -p stash@{0} > patch.diffGit 워크플로 모델
GitHub Flow가 가장 간단합니다: 하나의 main 브랜치, PR이 있는 기능 브랜치, 병합 시 배포 — 지속적 배포에 이상적입니다. Git Flow(Vincent Driessen의 모델)는 구조화된 릴리스 관리를 위해 develop, release, hotfix 브랜치를 추가합니다 — 버전이 지정된 제품에 적합합 니다. Trunk-Based Development는 매우 수명이 짧은 브랜치를 사용하며 최대 통합 속도를 위해 고성능 DevOps 팀에서 선호합니다.
# GitHub Flow (simple, popular)
# main is always deployable; feature branches + PRs
git checkout -b feature/x
git push -u origin feature/x
# open PR, review, merge to main, deploy
# Git Flow (structured, with release branches)
# main: production releases
# develop: integration branch
# feature/*: features off develop
# release/*: release prep
# hotfix/*: urgent fixes off main
# Trunk-Based Development
# short-lived branches (1-2 days), frequent rebase on main서브모듈
서브모듈은 하나의 Git 저장소를 다른 저장소에 포함합니다 — 라이브러리를 버전이 지정된 상태로 프로젝트 간에 공유하는 데 유용합니다. 부모 저장소는 서브모듈의 특정 커밋에 대한 포인터를 저장합니다. 복제는 기본적으로 서브모듈 내용을 가져오지 않습니다; --recurse-submodules가 한 번에 수행합니다. 서브모듈은 까다로울 수 있습니다; 더 간단한 종속성 관리를 위해 Git subtree나 패키지 관리자를 고려하세요.
# add another repo as a submodule
git submodule add https://github.com/user/lib.git libs/lib
# clone a repo with its submodules
git clone --recurse-submodules https://github.com/user/repo.git
# initialize submodules in an existing clone
git submodule update --init --recursive
# update submodules to their latest remote commit
git submodule update --remote
# record a submodule pointer change
git add libs/lib
git commit -m "chore: bump lib submodule"검사 & 디버깅
Blame & Annotate
git blame(annotate라고도 함)은 파일의 모든 줄에 대한 커밋과 작성자를 보여줍니다 — 코드가 왜 그렇게 보이는지 이해하는 데 필수적입니다. -L은 줄 범위로 제한하여 큰 파일에 유용합니다. -w는 순수 공백 변경을 무시하고, -C는 다른 파일에서 이동되거나 복사된 코드를 감지하여 줄이 실제로 어디서 왔는지 더 정확한 기록을 제공합니다.
# show who last changed each line
git blame file.txt
git blame -L 10,20 file.txt # only lines 10-20
git blame -e file.txt # show author email
git blame -w file.txt # ignore whitespace changes
git blame -C file.txt # detect moved lines across files
# GUI annotation in some editors
git gui blame file.txtBisect(이진 검색 버그)
bisect는 기록을 이진 검색하여 버그를 도입한 정확한 커밋을 찾아냅니다. 알려진 좋은 커밋과 나쁜 커밋을 표시합니다; Git은 중간점을 체크아웃하고, 테스트한 다음 좋음 또는 나쁨으로 표시하여 매번 범위를 반으로 줄입니다. 스크립트를 사용하면 전체 프로세스가 완전히 자동화됩니다 — 큰 기록의 회귀에 엄청난 시간 절약입니다.
# find the commit that introduced a bug
git bisect start
git bisect bad # current commit is broken
git bisect good v1.0.0 # v1.0.0 was working
# Git checks out a midpoint; test it, then:
git bisect good # or git bisect bad
# automate with a script that exits non-zero on bug
git bisect start HEAD v1.0.0 -- npm test
# finish and return to original branch
git bisect reset
# view the bisect log
git bisect log코드 & 기록 검색
git grep는 작업 트리의 추적된 파일을 검색합니다 — 인덱스를 사용하므로 grep -r보다 빠릅니다. -S 'pickaxe' 옵션은 특정 문자열을 추가하거나 제거한 커밋을 찾아, 함수나 버그가 언제 도입되었는지 추적하는 데 매우 유용합니다. -G는 비슷하지만 diff의 어디서든 정규식을 매칭합니다. --author 및 --since 필터와 결합하여 기록의 모든 변경을 찾아낼 수 있습니다.
# search working tree for a string
git grep "TODO"
git grep -n "TODO" -- "*.js"
git grep -i "error" src/
# search across all commits (history)
git log -S "functionName" --oneline # pickaxe: when added/removed
git log -G "functionName.*\(" --oneline # regex match in diffs
# search commit messages
git log --grep="fix.*login" --oneline
git log --author="Alice" --since="1 week ago"FSCK & 매달린 객체
git fsck(파일 시스템 검사)는 객체 데이터베이스의 무결성을 검증하고 매달린 커밋을 찾을 수 있습니다 — reflog가 부족할 때 복구에 유용합니다. git gc는 객체를 재구성하고 압축하여 디스크 공간을 절약합니다; --prune=now는 도달할 수 없는 객체를 즉시 제거합니다. Git은 주기적으로 자동 gc하지만, 수동으로 실행하면 큰 저장소를 줄일 수 있습니다. --aggressive는 최대 압축을 위해 델타를 재계산합니다.
# check repository integrity
git fsck --full
git fsck --unreachable
# find dangling (unreachable) commits & blobs
git fsck --lost-found
# garbage collect and prune old objects
git gc
git gc --prune=now
git gc --aggressive
# count objects and disk usage
git count-objects -vArchive & Bundle
git archive는 .git 디렉토리 없이 커밋의 깨끗한 스냅샷을 내보냅니다 — 릴리스를 배포하거나 기록이 필요 없는 사람에게 소스를 보내는 데 이상적입니다. git bundle은 저장소(또는 커밋 범위)를 복제하거나 가져올 수 있는 단일 파일로 패키징합니다 — 원격 서버를 사용할 수 없을 때 에어갭 네트워크나 이메일을 통해 저장소를 전송하는 데 완벽합니다.
# export a snapshot as a tar/zip (no .git history)
git archive --format=zip --output=app.zip HEAD
git archive --format=tar HEAD | gzip > app.tar.gz
git archive -o release.zip v1.0.0
# bundle a repo (with history) into a single file
git bundle create repo.bundle --all
git bundle create patch.bundle main..feature
# clone from a bundle (offline transfer)
git clone repo.bundle new-repo
git fetch patch.bundle feature고급 기술
훅
훅은 특정 시점에 자동으로 실행되는 스크립트입니다. 클라이언트 측 훅(pre-commit, commit-msg, pre-push)은 린팅이나 테스트 같은 로컬 정책을 강제합니다. 서버 측 훅(pre-receive, post-receive)은 원격에서 실행되어 브랜치 보호를 강제하거나 CI/CD를 트리거할 수 있습니다. .git/hooks 디렉토리에는 .sample으로 끝나는 샘플 스크립트가 포함되어 있습니다 — 활성화하려면 이름을 바꾸세요. Husky나 pre-commit 프레임워크 같은 도구는 팀 일관성을 위해 저장소 자체에서 훅을 관리합니다.
# client-side hooks live in .git/hooks/
# pre-commit runs before a commit is created
# commit-msg validates the commit message
# pre-push runs before pushing to remote
# sample pre-commit hook (.git/hooks/pre-commit)
#!/bin/sh
npm run lint || exit 1
npm test || exit 1
# server-side hooks (on the remote)
# pre-receive, update, post-receive
# make a hook executable
chmod +x .git/hooks/pre-commitWorktree
Worktree를 사용하면 복제 없이 단일 저장소에 대해 각각 다른 브랜치에 있는 여러 작업 디렉토리를 가질 수 있습 니다. 기능 브랜치의 작업 트리를 그대로 유지하면서 핫픽스를 작업해야 하거나, 한 브랜치에서 긴 빌드를 실행하면서 다른 브랜치를 편집할 때 매우 유용합니다. 모든 worktree는 동일한 .git 객체 데이터베이스를 공유하므로 디스크 사용량이 최소화됩니다.
# create a second working tree of the same repo
git worktree add ../app-feature feature/x
# list worktrees
git worktree list
# create a worktree with a new branch
git worktree add -b hotfix/y ../app-hotfix main
# remove a worktree
git worktree remove ../app-feature
# prune stale worktree metadata
git worktree prune기록 필터 & 다시 쓰기
비밀이나 큰 파일이 커밋되었을 때 기록을 다시 작성해야 합니다. git filter-repo는 git filter-branch의 현대적이고 빠른 대안입니다. BFG Repo-Cleaner는 큰 파일이나 비밀번호 패턴을 제거하기 위한 사용자 친화적인 대안입니다. 다시 작성 후에는 강제 푸시하고 모든 협력자에게 다시 복제하도록 알려야 합니다 — 이전 커밋은 만료될 때까지 reflog에 남습니다. 유출된 비밀은 항상 즉시 교체하세요.
# remove a file from ALL of history (sensitive data)
git filter-repo --path secrets.env --invert-paths
# (install git-filter-repo; the old filter-branch is deprecated)
# rewrite author info across all commits
git filter-repo --mailmap mailmap.txt
# split a subdirectory into its own repo
git filter-repo --subdirectory-filter libs/lib
# the simpler BFG Repo-Cleaner (Java tool)
bfg --delete-files *.env
bfg --replace-text passwords.txtSparse Checkout & Partial Clone
Partial clone(--filter)은 커밋과 트리를 가져오지만 액세스할 때 blob(파일 내용)을 지연 다운로드합니다 — 거대한 저장소의 복제를 극적으로 가속합니다. Sparse checkout은 작업 트리를 특정 디렉토리로 제한하여 작업하는 부분만 봅니다. 함께 사용하면 거대한 모노레포를 관리 가능하게 만듭니다: 복제가 빠르고 작업 트리가 작습니다.
# partial clone: download history on demand
git clone --filter=blob:none https://github.com/user/huge-repo.git
# sparse checkout: only certain directories
git clone --no-checkout https://github.com/user/repo.git
cd repo
git sparse-checkout init --cone
git sparse-checkout set src docs
git checkout main
# add a directory to the sparse set later
git sparse-checkout add tests
# disable sparse checkout (fetch everything)
git sparse-checkout disableReflog, Refspec & Notes
Refspec은 fetch/push 중에 참조가 매핑되는 방식에 대한 명시적 제어를 제공합니다 — 로 컬 기능 브랜치를 원격 main으로 푸시하는 것과 같은 비정상적인 워크플로에 유용합니다. git notes는 커밋을 다시 작성하지 않고 메타데이터를 첨부하며, 리뷰 코멘트나 CI 링크에 편리합니다. Notes는 별도의 참조(refs/notes/commits)에 저장되며 명시적으로 푸시하고 가져와야 합니다.
# refspec: explicit fetch/push mapping
git fetch origin "refs/heads/*:refs/remotes/origin/*"
git push origin "refs/heads/feature:refs/heads/main"
# add a note to a commit (without changing it)
git notes add -m "Reviewed by Alice" abc1234
git notes show abc1234
git log --show-notes
# configure where notes are stored
git config --global notes.displayRef "refs/notes/*"
# push notes to a remote
git push origin refs/notes/commits모범 사례 & 팁
커밋 위생
좋은 커밋은 작고, 원자적이며, 자체 완결적입니다: 커밋당 하나의 논리적 변경. 이렇게 하면 코드 리뷰가 쉬워지고, bisect가 빨라지며, revert가 정확해집니다. git add -p를 사용하여 단일 관심사와 관련된 헝크만 스테이징하세요. 명령형 메시지('added'가 아닌 'add')는 코드베이스에 대한 지시로 읽힙니다. 병합 전에 최신 main에 기능 브랜치를 리베이스하면 기록이 선형이고 이해하기 쉽게 유지됩니다.
# commit small, focused, logical units
git add -p # stage only relevant hunks
git commit -m "fix: handle null user in login"
# write clear, imperative messages
# GOOD: "feat: add password reset endpoint"
# BAD: "stuff", "fix", "WIP", "asdf"
# one concern per commit
git add login.ts && git commit -m "feat: add login"
git add styles.css && git commit -m "style: format login"
# rebase before merging to keep history clean
git fetch && git rebase origin/main브랜치 보호 & 코드 리뷰
브랜치 보호 규칙은 강제 푸시를 방지하고, PR 리뷰를 요구하며, CI 통과 시 병합을 제어합니다 — 팀 안전에 필수적입니다. 선형 기록 요구는 리베이스 또는 스쿼시 병합을 강제하여 기록을 읽기 쉽게 유지합니다. 서명된 커밋(GPG 또는 SSH)은 작성자를 증명하고 가장을 방지합니다. 이 설정은 Git 자체가 아닌 호스팅 플랫폼(GitHub/GitLab)에서 구성되지만, 조직 전체의 좋은 Git 위생을 강제합니다.
# on GitHub/GitLab: protect the main branch
# - require pull request reviews
# - require status checks (CI) to pass
# - require linear history (no merge commits)
# - dismiss stale reviews on push
# - require signed commits
# enforce via config (GitHub CLI)
gh api repos/:owner/:repo/branches/main/protection \
-X PUT -f required_status_checks[strict]=true
# sign commits and verify on receive
git config --global commit.gpgsign true
git config --global gpg.format ssh무시 & 비밀 관리
커밋된 비밀은 가장 일반적인 Git 보안 사고입니다. 푸시되면 비밀이 손상된 것으로 간주하세요 — 기록에서 제거한 후에도 복제와 포크가 보존되므로 즉시 교체하세요. 예방이 최선입니다: 비밀을 .gitignore에 추가하고, 환경 변수나 비밀 관리자(Vault, AWS Secrets Manager)를 사용하고, 각 커밋 전에 API 키와 비밀번호를 스캔하는 git-secrets 또는 pre-commit 훅을 설치하세요.
# never commit secrets — use .gitignore
echo ".env" >> .gitignore
echo "*.pem" >> .gitignore
echo "secrets/" >> .gitignore
# if you accidentally committed a secret:
# 1. rotate/revoke the secret immediately
# 2. remove from history
git filter-repo --path .env --invert-paths
git push --force-with-lease
# use environment files or secret managers
echo "API_KEY=$API_KEY" > .env.local # gitignored
# load via dotenv in your app
# use git-secrets to scan pre-commit
git secrets --install
git secrets --register-aws성능 팁
큰 저장소는 느릴 수 있습니다. fsmonitor와 untrackedcache는 파일 시스템 상태를 캐싱하여 git status를 훨씬 빠르게 만듭니다. 얕은 및 부분 복제는 초기 다운로드를 줄입니다. 객체를 압축하기 위해 주기적으로 git gc를 실행하세요. --no-verify는 pre-commit 및 commit-msg 훅을 건너뜁니다 — 긴급 상황에 유용하지만 습관이 되어서는 안 되며, 팀의 품질 검사를 우회하기 때문입니다.
# speed up status on large repos
git config --global core.fsmonitor true
git config --global core.untrackedcache true
# shallow clone for CI
git clone --depth 1 https://github.com/user/repo.git
# partial clone for huge monorepos
git clone --filter=blob:none https://github.com/user/monorepo.git
# periodic garbage collection
git gc --prune=now
# disable slow hooks temporarily
git commit --no-verify일반적인 함정
이런 고전적 실수를 피하세요: 공유 브랜치에 절대 강제 푸시하지 마세요(--force-with-lease가 안전한 옵션); 다른 사람이 작업을 기반으로 했을 수 있는 커밋을 절대 리베이스하지 마세요; 분리된 HEAD에서 먼저 브랜치를 만들지 않고 커밋하지 마세요. 큰 바이너리에는 Git LFS를 사용하세요 — 그렇지 않으면 기록이 영구적으로 부풀어 오릅니다. 크로스 플랫폼 팀에서 공백만 있는 diff를 피하기 위해 OS별로 줄 끝(autocrlf)을 구성하세요.
# PITFALL: force-pushing to shared branches
git push --force origin main # DON'T — use --force-with-lease
# PITFALL: rebasing pushed commits
# rebase only your local, unpushed branches
# PITFALL: committing on detached HEAD
git checkout v1.0.0
# changes here are not on a branch — create one:
git checkout -b fix/v1.0.1
# PITFALL: large binary files bloating history
# use Git LFS for binaries
git lfs install
git lfs track "*.psd"
git add .gitattributes
# PITFALL: CRLF/LF line endings across OS
git config --global core.autocrlf input # on Linux/Mac
git config --global core.autocrlf true # on WindowsGit Flow 워크플로
Git Flow 브랜치 모델
Git Flow는 릴리스 기반 프로젝트를 위한 엄격한 브랜칭 모델입니다. main은 항상 프로덕션 코드를 보유합니다; develop는 통합 작업을 보유합니다. 기능은 develop에서 분기되어 다시 병합됩니다. 릴리스는 develop에서 분기되어 안정화된 후 main(태그 포함)과 develop 모두에 병합됩니다. 핫픽스는 main에서 분기되어 main과 develop 모두에 병합됩니다. 이 모델은 예정된 릴리스(데스크톱 앱, 온프레미스 소프트웨어)가 있는 프로젝트에 적합합니다. 지속적 배포의 경우 GitHub Flow(main + 기능 브랜치)가 더 간단합니다. git-flow CLI 도구가 브랜치 댄스를 자동화합니다.
# Git Flow uses long-lived branches:
# main → production-ready code
# develop → latest delivered development changes
# feature/* → new features (branched from develop)
# release/* → release preparation (branched from develop)
# hotfix/* → urgent production fixes (branched from main)
# Initialize git-flow (interactive setup)
git flow init
# Start a new feature
git flow feature start my-feature
# Creates feature/my-feature from develop
# Finish a feature (merges to develop, deletes branch)
git flow feature finish my-feature
# Publish a feature to remote
git flow feature publish my-feature
# Start a release
git flow release start 1.2.0
# Creates release/1.2.0 from develop
# Finish a release (merges to main AND develop, tags)
git flow release finish 1.2.0GitHub Flow(더 간단)
GitHub Flow는 가장 간단한 워크플로입니다: main은 항상 배포 가능하고, 기능 브랜치는 수명이 짧으며, 모든 것이 Pull Request를 통해 병합됩니다. develop 브랜치나 릴리스 브랜치가 없습니다 — main이 지속적으로 배포됩니다. 이는 지속적 배포가 있는 웹 앱에 잘 작동합니다. 핵심 규칙: main에 직접 커밋하지 마세요; 항상 리뷰를 위해 PR을 사용하세요. 기능 브랜치를 작고 수명이 짧게(몇 주가 아닌 며칠) 유지하세요. 저장소를 깨끗하게 유지하기 위해 병합 후 브랜치를 삭제하세요. 이 모델은 Git Flow의 구조화된 릴리스 관리보다 속도와 단순성을 우선시합니다.
# GitHub Flow: only main + feature branches
# 1. Create branch from main
git checkout main
git pull origin main
git checkout -b feature/add-login
# 2. Commit changes
git add .
git commit -m "feat: add login page"
# 3. Push to remote
git push -u origin feature/add-login
# 4. Open Pull Request on GitHub
# 5. Review, discuss, get approval
# 6. Merge to main (via GitHub UI or CLI)
git checkout main
git pull origin main
git branch -d feature/add-login # delete local branch
# 7. Deploy from main (continuous deployment)Trunk-Based Development
Trunk-Based Development는 가장 극단적입니다: 개발자가 main에 직접 커밋합니다(또는 24시간 이내에 병합되는 매우 짧은 수명의 브랜치). 이는 진정한 지속적 통합을 가능하게 합니다 — 모두가 지속적으로 통합합니다. 미완성 기능은 수명이 긴 브랜치 대신 기능 플래그(배포되었지만 숨겨짐)를 사용합니다. 이는 강력한 CI/CD, 포괄적인 테스트 및 기능 플래그 인프라가 필요합니다. Google, Facebook, Netflix에서 사용됩니다. 이점: 병합 지옥 없음, 빠른 피드백, 작은 변경. 과제: 규율, 테스 트 커버리지 및 기능 플래그 관리 필요. 강력한 CI/CD가 있는 숙련된 팀에 가장 적합합니다.
# Trunk-Based: everyone commits to main (trunk)
# Short-lived feature branches optional
# Direct commit to main (small teams)
git checkout main
git pull
# make changes
git add . && git commit -m "fix: typo in header"
git push
# With short-lived branches (larger teams)
git checkout -b quick-fix
git commit -m "fix: validation bug"
git push
# PR merged within 24 hours
# Feature flags enable incomplete code on main
# Code is deployed but hidden behind a flag
if (featureFlag.isEnabled("new-checkout")) {
showNewCheckout();
} else {
showOldCheckout();
}Fork & Pull 워크플로
Fork & Pull 워크플로는 오픈 소스의 표준입니다. 기여자는 저장소를 포크(자체 사본 생성)하고, 포크에 브랜치를 푸시하고, 원래(upstream) 저장소에 PR을 엽니다. upstream 원격을 통해 포크를 원래와 동기화할 수 있습니다. 항상 업데이트된 main에서 기능 브랜치를 만드세요. 이 워크플로는 쓰기 권한 없이 누구나 기여할 수 있게 합니다. 유지 관리자가 PR을 리뷰하고 병합합니다. 포크를 동기화하려면 upstream을 정기적으로 가져오고 병합/리베이스하세요. 일부 프로젝트는 직접 푸시 권한이 있는 내부 기여자를 위해 '복제, 분기, PR' 모델을 사용합니다.
# For open-source projects (contributors don't have push access)
# 1. Fork the repo on GitHub (UI button)
# 2. Clone YOUR fork
git clone https://github.com/YOUR-USERNAME/project.git
cd project
# 3. Add upstream (original repo)
git remote add upstream https://github.com/ORIGINAL/project.git
# 4. Keep your fork updated
git fetch upstream
git checkout main
git merge upstream/main # or: git rebase upstream/main
git push origin main
# 5. Create feature branch
git checkout -b feature/my-contribution
# 6. Push to YOUR fork
git push origin feature/my-contribution
# 7. Open Pull Request from your fork to upstream브랜치 명명 규칙
일관된 브랜치 명명은 명확성을 향상하고 자동화를 가능하게 합니다. 일반적인 접두어: feature, bugfix, hotfix, release, chore, docs, refactor, experiment. 티켓 번호(PROJ-123)를 포함하면 브랜치를 이슈에 연결하고 자동 링크를 가능하게 합니다. 슬래시는 Git GUI에서 시각적 계층 구조를 만듭니다. 일부 팀은 Git 훅이나 CI 검사로 명명을 강제합니다. 규칙은 CONTRIBUTING.md에 문서화해야 합니다. 이름을 설명적이지만 간결하게 유지하세요. 개인 이름(johns-branch)을 피하세요 — 작업을 설명하지 작성자를 설명합니다. 일관된 명명은 브랜치 정리와 기록 탐색을 훨씬 쉽게 만듭니다.
# Common naming patterns:
feature/add-user-authentication
feature/PROJ-123-user-profile
bugfix/fix-login-redirect
bugfix/PROJ-456-crash-on-startup
hotfix/security-patch-xss
release/v2.0.0
chore/update-dependencies
docs/api-documentation
refactor/extract-auth-module
experiment/new-algorithm
# Using ticket numbers (Jira, Linear, etc.)
git checkout -b feature/PROJ-123-oauth-login
# Auto-linking in commit messages
git commit -m "PROJ-123: implement OAuth login"
# GitHub auto-links PROJ-123 to the Jira ticket
# Branch naming with slashes creates hierarchy
# in Git GUI tools (GitHub, GitKraken, SourceTree)리베이스 심층
대화형 리베이스
대화형 리베이스(-i)는 가장 강력한 기록 편집 도구입니다. 푸시하기 전에 커밋을 다시 작성, 재정렬, 결합, 분할 또는 삭제할 수 있게 합니다. squash는 커밋을 부모에 결합합니다(메시지 병합); fixup은 동일하지만 커밋 메시지를 폐기합니다('WIP' 커밋 정리). edit는 커밋을 수정(파일 추가, 내용 변경)하기 위해 리베이스를 일시 중지합니다. reword를 사용하면 메시지만 변경할 수 있습니다. drop은 커밋을 제거합니다. 기록을 깨끗하게 유지하기 위해 항상 푸시 전에 리베이스하세요. 다른 사람이 이미 풀한 커밋은 절대 리베이스하지 마세요 — 공유 기록을 다시 작성합니다.
# Rebase last 5 commits interactively
git rebase -i HEAD~5
# Opens editor with:
# pick a1b2c3d First commit
# pick e4f5g6h Second commit
# pick i7j8k9l Third commit
# pick m0n1o2p Fourth commit
# pick q3r4s5t Fifth commit
# Commands:
# pick = use commit as-is
# reword = use commit, edit message
# edit = pause to amend the commit
# squash = combine with previous commit
# fixup = like squash, discard this message
# drop = remove commit entirely
# exec = run a shell command
# reorder = move lines to reorder commits커밋 스쿼시
스쿼시는 여러 커밋을 하나로 결합하여 깨끗한 기록을 만듭니다. 이는 기능 브랜치를 병합하는 데 이상적입니다: 20개의 'WIP' 커밋을 하나의 의미 있는 'feat: add login' 커밋으로 스쿼시합니다. --fixup 플래그는 --autosquash가 자동으로 배치하고 대상과 스쿼시하는 특수 커밋을 만듭니다 — 기록을 어지럽히지 않고 리뷰 피드백을 수정하는 데 좋습니다. git reset --soft main 다음에 단일 커밋은 한 번에 모든 것을 스쿼시합니다(전체 스쿼시를 위한 대화형 리베이스보다 간단). 많은 팀이 PR 병합을 자동 스쿼시로 구성합니다(GitHub의 'Squash and merge' 옵션).
# Squash the last 3 commits into one
git rebase -i HEAD~3
# In editor, change:
# pick a1b2c3d First
# squash e4f5g6h Second (or 'fixup' to discard message)
# squash i7j8k9l Third
# Git prompts for combined commit message
# Squash everything since branching from main
git rebase -i main
# Auto-squash fixup commits
git commit --fixup a1b2c3d # creates fixup! commit
git rebase -i --autosquash main
# Git automatically reorders and squashes fixup commits
# Squash all commits into one on a branch
git reset --soft main
git commit -m "feat: complete feature X"리베이스 vs 병합
병합은 완전한 브랜치 기록을 보존합니다(기능이 분기되고 병합된 위치를 보여주는 병합 커밋 포함). 리베이스는 커밋을 대상 위에 재생하여 병합 커밋 없이 선형 기록을 만듭니다. 병합은 더 안전하고(기록 다시 쓰기 없음) 기능 컨텍스트를 보여줍니다. 리베이스는 더 깨끗하지만 커밋 기록을 다시 씁니다. 일반적인 전략: 병합 전에 최신 main에 기능 브랜치를 리베이스한 다음 병합(패스트포워드 또는 병합 커밋을 위해 --no-ff). 이는 깨끗한 커밋과 기능을 표시하는 병합 커밋을 모두 제공합니다. 공개/공유 브랜치의 경우 기록 충돌을 피하기 위해 병합을 선호하세요.
# MERGE: preserves complete history with merge commits
git checkout main
git merge feature
# Creates a merge commit, history looks like a graph:
# * merge commit
# |\
# | * feature commit 2
# | * feature commit 1
# * main commit
# REBASE: linear history, no merge commits
git checkout feature
git rebase main
git checkout main
git merge feature # fast-forward, no merge commit
# History is linear:
# * feature commit 2
# * feature commit 1
# * main commit
# When to use each:
# Merge: preserve context of feature branch, public repos
# Rebase: clean linear history, before pushing feature branch리베이스 충돌 해결
리베이스 충돌은 변경된 베이스에 커밋을 재생할 때 발생합니다. 각 충돌을 해결하고, 해결된 파일을 git add하고, git rebase --continue하세요. 리베이스는 한 번에 하나의 커밋을 처리하므로 여러 충돌이 발생할 수 있습니다. --skip은 커밋을 폐기합니다(리베이스 후 비어 있는 경우 사용). --abort는 모든 것을 취소하고 리베이스 전 상태로 돌아갑니다 — 항상 안전한 탈출구입니다. 복잡한 충돌의 경우 git mergetool이 시각적 병합 도구(VS Code, Beyond Compare 등)를 시작합니다. 병합 충돌과의 주요 차이점: 리베이스는 동일한 충돌을 여러 번(재생된 커밋마다 한 번) 해결해야 할 수 있습니다.
# During rebase, conflicts pause the process
git rebase main
# CONFLICT in file.txt
# 1. Resolve conflicts manually in the file
# (look for <<<<<<< ======= >>>>>>> markers)
# 2. Stage resolved files
git add file.txt
# 3. Continue the rebase
git rebase --continue
# Skip a commit (if it's empty after rebase)
git rebase --skip
# Abort the entire rebase (return to original state)
git rebase --abort
# Use a merge tool for conflicts
git mergetool
# After resolving, the rebase continues
# with the next commit automaticallyRebase Onto(고급)
git rebase --onto는 정확한 커밋 이식을 위한 고급 형태입니다. 구문: rebase --onto NEW-BASE OLD-BASE BRANCH — OLD-BASE와 BRANCH 사이의 커밋을 가져와 NEW-BASE 위에 재생합니다. 이는 브랜치의 베이스 포인트를 변경하는 데 유용합니다(예: 기능이 병합된 다른 기능을 기반으로 했던 경우; main으로 리베이스하여 정리). 기록에서 특정 커밋을 제거하는 데(주변으로 재생) 사용되기도 합니다. 이는 파워 유저 기능입니다 — 먼저 일반 리베이스를 이해하세요. 고급 기록 다시 쓰기 전에 항상 백업(reflog)을 가지세요.
# Scenario: feature branch was based on old-branch,
# but you want to rebase onto main instead
# git rebase --onto new-base old-base branch
git rebase --onto main old-branch feature
# This takes commits from old-branch..feature
# and replays them onto main
# Use case: remove commits from the middle
# Remove commit C from branch (replay A,B,D onto base)
# base -> A -> B -> C -> D
# git rebase --onto base C D
# Result: base -> A -> B -> D'
# Use case: move a branch to a different parent
git rebase --onto main feature/sub-feature feature/main-feature
# Moves main-feature's unique commits from sub-feature to mainCherry-pick & Bisect
git cherry-pick
cherry-pick은 한 브랜치의 특정 커밋을 다른 브랜치에 적용합니다. 사용 사례: 릴리스 브랜치에 버그 수정 적용, 병합을 잊은 커밋 복사, 또는 선택적으로 기능 포트. 커밋은 새 해시를 얻습니다(다른 부모). 대상 브랜치가 분기된 경우 cherry-pick은 충돌을 일으킬 수 있습니다. --no-commit은 커밋하지 않고 변경 사항을 스테이징합니다(여러 cherry-pick 결합에 유용). 과도한 cherry-pick을 피하세요 — 브랜치가 결국 병합될 때 중복 커밋을 만들 수 있습니다. 체계적인 백포트를 위해 병합이 있는 릴리스 브랜치를 사용하세요.
# Apply a specific commit to current branch
git cherry-pick a1b2c3d
# Cherry-pick multiple commits
git cherry-pick a1b2c3d e4f5g6h i7j8k9l
# Cherry-pick a range (exclusive start, inclusive end)
git cherry-pick A..E # commits B, C, D, E
# Cherry-pick without committing (stage only)
git cherry-pick --no-commit a1b2c3d
# or: -n
# Cherry-pick and edit commit message
git cherry-pick --edit a1b2c3d
# Cherry-pick from another branch
git cherry-pick feature-branch~2
# If conflicts occur:
git add . && git cherry-pick --continue
git cherry-pick --abort # cancelgit bisect(이진 검색)
git bisect는 커밋 기록을 이진 검색하여 버그를 도입한 정확한 커밋 을 찾습니다. 현재 상태를 '나쁨'으로, 알려진 작동 커밋을 '좋음'으로 표시합니다. Git이 중간점을 체크아웃합니다; 테스트하고 좋음/나쁨으로 표시하세요. 각 단계마다 검색 공간을 반으로 줄입니다 — 1000개 커밋에서 버그를 찾는 데 ~10단계가 걸립니다. bisect reset은 원래 브랜치로 돌아갑니다. 이는 회귀를 추적하는 데 매우 유용합니다. bisect 세션을 저장/복원하려면 git bisect log와 결합하세요. 범인 커밋은 종종 근본 원인을 즉시 드러냅니다.
# Find which commit introduced a bug
git bisect start
# Mark current (bad) commit
git bisect bad
# Mark a known-good commit (last working version)
git bisect good v1.0.0
# or: git bisect good a1b2c3d
# Git checks out a middle commit
# Test it, then mark:
git bisect good # if this commit works
git bisect bad # if this commit is broken
# Repeat until Git identifies the culprit:
# "a1b2c3d is the first bad commit"
# When done:
git bisect reset # return to original branch
# Skip a commit (can't test, e.g., doesn't build)
git bisect skip자동화된 Bisect
자동화된 bisect는 각 커밋에 대해 테스트 스크립트를 실행하여 수동 테스트를 제거합니다. 스크립트는 0(좋음), 0이 아닌 값(나쁨) 또는 125(건너뜀 — 예: 빌드 실패)으로 종료됩니다. Git이 자동으로 각 커밋을 표시하고 범인을 찾습니다. 이는 테스트 스위트와 매우 강력합니다: git bisect run npm test가 몇 분 안에 손상된 커밋을 찾습니다. 검색을 특정 파일로 제한하여 속도를 높일 수도 있습니다(git bisect start -- path/to/file). 스크립트는 테스트, 빌드 검사 또는 API를 확인하는 curl 명령 등 모든 것이 될 수 있습니다. 나중에 재현하거나 재개하려면 bisect 로그를 저장하세요.
# Auto-bisect with a test script
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
# Git runs this script for each commit
# Exit 0 = good, exit 1 = bad, 125 = skip
git bisect run npm test
# Or a custom script
git bisect run ./scripts/check-bug.sh
# Example check script:
#!/bin/bash
npm run build || exit 125 # skip if build fails
npm test -- --grep "login bug"
# exit 0 if test passes (good), 1 if fails (bad)
# Git automatically finds the bad commit
# without manual testing
# Bisect with a file range (faster)
git bisect start -- src/auth/login.jsgit blame & annotate
git blame은 파일의 각 줄에 대한 작성자와 커밋을 보여줍니다 — 코드가 왜 존재하는지 이해하는 데 필수적입니다. -L은 줄 범위로 제한합니다(더 빠르고 집중적). -w는 공백 전용 변경을 무시합니다(실제 내용 작성자 표시). -M은 동일한 파일 내에서 이동된 코드를 감지; -C는 다른 파일에서 복사된 코드를 감지합니다(복사자가 아닌 원래 작성자 표시). blame은 비난이 아닌 이해를 위한 것입니다 — 코드에 대한 컨텍스트를 찾는 데 사용한 다음 git show로 전체 커밋을 읽으세요. GitHub의 'Blame' 버튼은 시각적 인터페이스를 제공합니다. 특정 텍스트가 언제 추가되었는지 찾으려면 git log -S와 결합하세요.
# Show who last modified each line
git blame file.txt
# Blame specific line range
git blame -L 10,20 file.txt
# Show full commit hash (not abbreviated)
git blame -l file.txt
# Show email instead of name
git blame -e file.txt
# Ignore whitespace changes
git blame -w file.txt
# Detect moved lines within file
git blame -M file.txt
# Detect moved lines from other files
git blame -C file.txt
# Blame with commit message
git blame --show-name --show-email file.txt | headgit revert(안전한 취소)
git revert는 이전 커밋을 취소하는 새 커밋을 만듭니다 — 기록을 다시 쓰는 reset과 달리 공유 브랜치에서 변경을 취소하는 안전한 방법입니다. revert는 기록을 다시 쓸 수 없는 프로덕션 브랜치에 이상적입니다. 병합 커밋을 되돌리려면 -m 1(메인라인 부모)이 필요합니다 — 이는 브랜치 기록을 유지하면서 병합을 취소합니다. revert를 되돌리면 원래 변경이 다시 적용됩니다(revert가 실수였을 때 흔함). 여러 커밋의 경우 충돌을 최소화하기 위해 역순(최신부터)으로 되돌리세요. 공유/공개 브랜치에서는 항상 revert를 사용하세요; 로컬 브랜치에서만 reset을 사용하세요.
# Revert a commit (creates a NEW commit that undoes it)
git revert a1b2c3d
# Revert multiple commits
git revert a1b2c3d e4f5g6h
# Revert a range
git revert A..E
# Revert without committing (stage the reversal)
git revert --no-commit a1b2c3d
# Revert a merge commit
git revert -m 1 a1b2c3d
# -m 1 specifies the mainline parent (parent 1 = the branch
# you merged INTO, parent 2 = the branch you merged FROM)
# If revert conflicts:
git add . && git revert --continue
git revert --abortReflog & 복구
git reflog 기본
reflog는 HEAD와 브랜치 포인터에 대한 모든 변경을 기록합니다 — 커밋을 '파괴'하는 작업(reset --hard, rebase, 브랜치 삭제)까지도. 이는 안전망입니다: '잃어버린' 커밋은 ~90일(기본값) 동안 reflog를 통해 복구할 수 있습니다. reflog는 로컬(푸시되지 않음)이며 포인터 이동의 시간순 기록을 보여줍니다. 복구하려면 reflog에서 커밋 해시를 찾아 체크아웃/리셋하세요. @{N} 구문은 항목을 참조합니다: HEAD@{0}은 현재, HEAD@{1}은 이전입니다. 작업을 '잃어버렸다'고 생각되면 항상 먼저 reflog를 확인하세요 — 거의 확실히 여전히 거기에 있습니다.
# View the reflog (reference log)
git reflog
# Shows ALL reference changes, including:
# - commits, checkouts, resets, rebases, merges
# Example output:
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# e4f5g6h HEAD@{1}: commit: add feature
# i7j8k9l HEAD@{2}: checkout: moving from main to feature
# Reflog for a specific branch
git reflog show feature-branch
# Reflog with dates
git reflog --date=iso
# Recover a "lost" commit
git reflog
# Find the commit hash, then:
git checkout a1b2c3d # or: git reset --hard a1b2c3d삭제된 브랜치 복구
삭제된 브랜치와 리셋된 커밋은 reflog를 통해 복구할 수 있습니다. 가비지 컬렉션이 실행될 때까지(기본값: 도달할 수 없는 객체의 경우 90일) 커밋 객체는 Git의 객체 저장소에 여전히 존재합니다. 삭제된 브랜치를 복구하려면 reflog에서 끝 커밋을 찾아 가리키는 새 브랜치를 만드세요. reset --hard 실수의 경우 reflog가 이전 HEAD 위치를 보여줍니다 — 다시 리셋하세요. 잘못된 리베이스의 경우 리베이스가 시작되기 전의 reflog 항목을 찾아 리셋하세요. 핵심 교훈: Git에서 거의 모든 것은 즉시 진정으로 사라지지 않습니다. 당황하기 전에 항상 reflog를 확인하세요.
# Accidentally deleted a branch?
git branch -D feature # force deleted
# Find it in reflog
git reflog
# e4f5g6h HEAD@{2}: commit: work on feature
# Recreate the branch at that commit
git branch feature e4f5g6h
# Or checkout and create
git checkout -b feature e4f5g6h
# Recover after reset --hard
git reset --hard HEAD~3 # oops, went too far
git reflog
# Find the commit before the reset
git reset --hard HEAD@{1} # undo the reset
# Recover after a bad rebase
git reflog
git reset --hard HEAD@{5} # before the rebase startedgit fsck(매달린 객체)
git fsck는 저장소 무결성을 검사하고 매달린 객체 — 어떤 브랜치나 태그에서도 참조되지 않는 커밋, blob 및 트리 — 를 찾습니다. --lost-found는 이것들을 .git/lost-found/에 씁니다. 이는 reflog에 필요한 것이 없을 때(참조 항목이 만료되었거나 git gc가 실행된 경우) 최후의 수단입니다. 매달린 커밋은 종종 중단된 작업이나 만료된 reflog 항목의 결과입니다. git show로 검사한 다음 브랜치를 만들어 복구하세요. fsck --full은 모든 객체의 무결성을 검증합니다(손상 감지에 유용). 중요한 저장소에서 문제를 조기에 발견하기 위해 주기적으로 fsck를 실행하세요.
# Find dangling (unreachable) commits
git fsck --lost-found
# Output:
# dangling commit a1b2c3d...
# dangling blob e4f5g6h...
# Inspect a dangling commit
git show a1b2c3d
# Recover it
git branch recovered a1b2c3d
# Full fsck (check repository integrity)
git fsck --full
# Check for dangling objects only
git fsck --no-reflogs --dangling
# When reflog doesn't have what you need
# (e.g., expired, or gc ran), fsck finds
# ALL dangling objects in the object storegit stash 심층
git stash는 커밋되지 않은 변경 사항을 일시적으로 보관합니다. push -m은 설명 메시지를 추가합니다(여러 스태시 관리에 필수). -u는 추적되지 않은 파일을 포함; -a는 무시된 파일도 포함합니다. apply는 제거 없이 재적용; pop은 적용하고 제거합니다. stash branch는 스태시에서 새 브랜치를 만듭니다(스태시가 현재 브랜치와 충돌하는 경우 유용). 스태시는 스택(LIFO)에 저장됩니다 — stash@{N}으로 참조. show -p는 diff를 표시합니다. 스태시는 재부팅 후에도 유지되지만 로컬입니다(푸시되지 않음). 오래된 스태시를 정기적으로 정리하세요; 축적됩니다. 장기 작업의 경우 스태싱 대신 브랜치를 만드세요.
# Stash with message
git stash push -m "work in progress on login"
# Stash specific files
git stash push -m "wip" file1.txt file2.txt
# Stash including untracked files
git stash push -u # or --include-untracked
# Stash including ignored files
git stash push -a # or --all
# List stashes
git stash list
# stash@{0}: On feature: wip on login
# stash@{1}: On main: quick fix
# Apply a specific stash
git stash apply stash@{1}
# Apply and drop (pop)
git stash pop # applies stash@{0} and removes it
# Show stash contents
git stash show -p stash@{0}
# Create branch from stash
git stash branch new-branch stash@{0}
# Drop a stash
git stash drop stash@{1}
git stash clear # drop ALL stashesgit tag 관리
태그는 특정 커밋을 중요(릴리스, 마일스톤)로 표시합니다. 주석 태그(-a)는 메타데이터(태거, 날짜, 메시지)를 저장하며 릴리스에 권장됩니다. 경량 태그는 단순한 이름이 지정된 포인터입니다(메타데이터 없음). 서명된 태그(-s)는 검증을 위해 GPG를 사용합니다(보안 릴리스에 중요). 태그는 기본적으로 푸시되지 않습니다 — --tags를 사용하여 푸시하세요. 시맨틱 버저닝(v1.2.3)이 표준 명명 규칙입니다. 태그를 체크아웃하면 분리된 HEAD 상태가 됩니다(검사 또는 릴리스 빌드용). GitHub 릴리스는 태그를 기반으로 구축됩니다 — 태그를 만든 다음 노트와 함께 릴리스를 게시하세요.
# Create annotated tag (recommended)
git tag -a v1.0.0 -m "Release 1.0.0"
# Create lightweight tag
git tag v1.0.0
# Tag a specific commit
git tag -a v0.9.0 -m "beta" a1b2c3d
# List all tags
git tag
git tag -l "v1.*" # filter by pattern
# Push tags to remote
git push origin v1.0.0 # single tag
git push origin --tags # all tags
# Delete a tag
git tag -d v1.0.0 # local
git push origin --delete v1.0.0 # remote
# Show tag details
git show v1.0.0
# Checkout a tag (detached HEAD)
git checkout v1.0.0
# Signed tags (GPG)
git tag -s v1.0.0 -m "signed release"Worktree & 서브모듈
git worktree
git worktree는 동일한 저장소에서 추가 작업 디렉토리를 만듭니다 — 복제할 필요가 없습니다. 각 worktree는 다른 브랜치를 동시에 체크아웃합니다. 이는 다음에 완벽합니다: 기능 브랜치를 열어둔 채 핫픽스 작업, 한 브랜치에서 테스트를 실행하면서 다른 브랜치에서 코딩, 또는 하나의 worktree에서 장기 실행 빌드. 모든 worktree는 동일한 .git 디렉토리(객체, 참조)를 공유하므로 동기화 상태를 유지하고 디스크 공간을 절약합니다. 두 worktree에서 동일한 브랜치를 체크아웃할 수 없습니다(Git은 충돌을 방지하기 위해 이를 방지). worktree는 다중 브랜치 워크플로에 복제보다 빠릅니다.
# Create a new working directory linked to the repo
git worktree add ../project-hotfix hotfix-branch
# Work in the new directory
cd ../project-hotfix
# This is a full working tree on hotfix-branch
# Shares the same .git, so no cloning needed
# List worktrees
git worktree list
# /path/to/project main
# /path/to/project-hotfix hotfix-branch
# Remove a worktree
git worktree remove ../project-hotfix
# Prune stale worktree entries
git worktree prune
# Create worktree at new branch
git worktree add -b feature-x ../project-feature maingit submodule 기본
서브모듈은 하나의 Git 저장소를 다른 저장소에 포함합니다 — 공유 라이브러리나 종속성을 포함하는 데 유용합니다. 부모 저장소는 서브모듈의 내용이 아닌 포인터(커밋 해시)를 저장합니다. 복제 시 --recurse-submodules가 필수입니다(그렇지 않으면 서브모듈이 비어 있음). 서브모듈 업데이트(--remote)는 최신 커밋을 가져옵니다; 그런 다음 부모 저장소에서 새 해시를 커밋해야 합니다. 서브모듈은 복잡합니다: 브랜치, 충돌 및 업데이트는 신중한 처리가 필요합니다. 더 간단한 종속성 관리를 위해 Git subtree, 패키지 관리자(npm, pip) 또는 모노레포 전략을 고려하세요. 특정 외부 커밋을 추적해야 할 때 서브모듈을 사용하세요.
# Add a submodule to your repo
git submodule add https://github.com/user/lib.git libs/lib
# Clone a repo with submodules
git clone --recurse-submodules https://github.com/user/project.git
# If you forgot --recurse-submodules:
git submodule update --init --recursive
# Pull latest changes in all submodules
git submodule update --remote
# Pull specific submodule
git submodule update --remote libs/lib
# After updating submodules, commit the new hash
git add libs/lib
git commit -m "update lib submodule"
# Execute command in all submodules
git submodule foreach 'git status'서브모듈 워크플로
서브모듈 내부에서 작업하는 것은 일반 저장소에서 작업하는 것과 같습니다 — 서브모듈 디렉토리 내에서 커밋하고 푸시합니다. 부모 저장소는 커밋 해시를 추적하므로 서브모듈을 변경한 후 부모에서도 커밋해야 합니다. 브랜치를 전환할 때 서브모듈 내용이 일치하지 않을 수 있습니다 — git submodule update --init --recursive를 실행하여 동기화하세요. 서브모듈 삭제는 세 단계가 필요합니다: deinit(등록 취소), git rm(추적에서 제거), .git/modules의 수동 삭제. 서브모듈 워크플로는 오류가 발생하기 쉽습니다; 해시 불일치를 피하기 위해 서브모듈을 업데이트할 때 항상 팀과 소통하세요.
# Change code inside a submodule
cd libs/lib
# Make changes, commit, and push
git add .
git commit -m "fix: bug in lib"
git push origin HEAD:main
# Back in parent repo, update the pointer
cd ../..
git add libs/lib
git commit -m "chore: update lib submodule"
# Switch branches with submodules
git checkout main
git submodule update --init --recursive
# Delete a submodule
git submodule deinit -f libs/lib
git rm libs/lib
rm -rf .git/modules/libs/lib
git commit -m "remove lib submodule"
# Move a submodule
git mv libs/lib libs/new-libGit 훅
Git 훅은 Git 수명 주기의 특정 시점에 스크립트를 실행합니다. 클라이언트 측 훅(pre-commit, pre-push, commit-msg)은 로컬 표준을 강제합니다. pre-commit은 린팅/포맷팅에 이상적; pre-push는 테스트 실행; commit-msg는 Conventional Commits 강제용. 훅은 Git에 의해 추적되지 않으므로(.git/hooks/에 있음) 복제 간에 동기화되지 않습니다. 팀 전체에 훅을 공유하려면 Husky(npm), pre-commit(Python) 같은 도구를 사용하거나 훅을 체크인된 디렉토리에 커밋하고 심볼릭 링크하세요. 서버 측 훅(pre-receive, post-receive)은 원격에서 실행되어 모든 기여자에 대한 정책을 강제할 수 있습니다.
# Hooks live in .git/hooks/ (not tracked by Git)
# Sample hooks are provided with .sample extension
# pre-commit: runs before commit is created
# .git/hooks/pre-commit
#!/bin/bash
npm run lint || exit 1 # block commit if lint fails
# pre-push: runs before pushing
#!/bin/bash
npm test || exit 1 # block push if tests fail
# commit-msg: validate commit message format
#!/bin/bash
# $1 is the path to the commit message file
if ! grep -qE "^(feat|fix|docs|chore):" "$1"; then
echo "Use conventional commit format: type: message"
exit 1
fi
# prepare-commit-msg: auto-populate message
#!/bin/bash
echo "# Branch: $(git branch --show-current)" >> "$1"
# Make hooks executable
chmod +x .git/hooks/pre-commitGit LFS(대용량 파일 저장소)
Git LFS는 큰 파일(바이너리, 비디오, 데이터셋)을 Git의 텍스트 포인터로 교체하여 실제 내용은 별도의 LFS 서버에 저장합니다. 이는 저장소를 가볍게 유지합니다 — LFS 없이 바이너리 파일은 저장소를 영구적으로 부풀립니다(모든 버전이 저장됨). git lfs track으로 파일 패턴을 추적한 다음 .gitattributes를 커밋하세요. 그 후 큰 파일은 투명하게 작동합니다. git lfs migrate import는 기존 파일을 LFS로 소급 변환합니다(기록을 다시 작성 — 먼저 팀과 조정). LFS는 서버 지원이 필요합니다(GitHub, GitLab, Bitbucket 모두 지원). 참고: LFS는 호스팅 플랫폼에서 대역폭/저장소 할당량이 있습니다. 진정으로 거대한 파일의 경우 URL이 있는 외부 저장소를 고려하세요.
# Initialize Git LFS
git lfs install
# Track large file types
git lfs track "*.psd"
git lfs track "*.zip"
git lfs track "assets/**"
# This creates/updates .gitattributes
# Commit the .gitattributes file
git add .gitattributes
git commit -m "chore: configure LFS tracking"
# Add large files normally
git add design.psd
git commit -m "add design file"
git push
# View LFS tracked files
git lfs ls-files
# Pull LFS content (if not auto-downloaded)
git lfs pull
# Migrate existing files to LFS (rewrites history)
git lfs migrate import --include="*.psd" --everything
# Check LFS status
git lfs statusStash
저장 & Pop
git stash는 커밋되지 않은 변경 사항을 보관하여 깨끗한 작업 트리로 브랜치를 전환하거나 업데이트를 풀할 수 있게 합니다. pop은 최상위 스태시를 적용하고 제거; apply는 유지합니다. 스태시는 LIFO 스택입니다.
# Save uncommitted changes (tracked files only)
git stash
# Save including untracked files
git stash -u
# Pop the most recent stash (removes it)
git stash pop
# Apply without removing (keeps stash in list)
git stash apply이름이 지정된 스태시
항상 -m을 전달하여 스태시에 레이블을 지정하세요 — 기본 메시지는 브랜치와 커밋이며 거의 설명적이지 않습니다. stash@{N}은 인덱스로 특정 스태시를 참조합니다.
# Save with a descriptive message
git stash push -m "WIP: refactor auth flow"
# List all stashes with messages
git stash list
# Apply a specific stash by index
git stash apply stash@{1}스태시 브랜치
git stash branch는 스태시가 원래 만들어진 커밋에서 새 브랜치를 만든 다음 거기에 스태시를 적용합니다. 이는 스태시가 더 이상 깔끔하게 적용되지 않을 때 복구하는 가장 깨끗한 방법입니다.
# Create a new branch from a stash
git stash branch feature-branch stash@{0}
# Useful when stash conflicts with current branch
# - Creates branch from the commit where stash was made
# - Applies stash on top
# - Drops stash if apply succeeds부분 스태시
-p(대화형 헝크 선택)로 필요한 것만 스태시하거나 특정 파일을 나열하세요. --keep-index는 스테이지되지 않은 변경 사항을 스태시하지만 스테이지된 변경 사항은 그대로 둡니다.
# Interactively choose hunks to stash
git stash push -p
# Stash specific files only
git stash push -m "config tweaks" config.yml .env.local
# Stash with keep-index (staged changes stay)
git stash --keep-index스태시 관리
git stash show -p는 스태시의 전체 diff를 표시합니다. drop은 단일 스태시를 제거; clear는 모두 지웁니다(되돌릴 수 없음). 스태시는 로컬 전용; 원격에 푸시되지 않습니다.
# Show what's in a stash
git stash show -p stash@{0}
# Drop a specific stash
git stash drop stash@{0}
# Clear all stashes (irreversible)
git stash clear
# Show stash list with dates
git stash list --date=relativeRebase
기본 리베이스
Rebase는 브랜치 커밋을 다른 브랜치 위로 이동하여 선형 기록을 생성합니다. 병합과 달리 커밋 해시를 다시 씁니다. 푸시되고 공유된 커밋은 절대 리베이스하지 마세요.
# Rebase current branch onto main
git checkout feature
git rebase main
# Abort if conflicts are too messy
git rebase --abort
# Continue after resolving conflicts
git rebase --continue대화형 리베이스
대화형 리베이스(-i)를 사용하면 공유 전에 기록을 다시 작성할 수 있습니다: 커밋 재정렬, 관련 커밋을 단일 깔끔한 커밋으로 스쿼시, 메시지 다시 작성, 또는 실수를 삭제. 항상 푸시되지 않은 커밋에서 수행하세요.
# Rebase last 5 commits interactively
git rebase -i HEAD~5
# Commands: pick, reword, edit, squash, fixup, drop
# squash = combine with previous, keep message
# fixup = combine with previous, discard message
# reword = change commit message onlySquash & Fixup
--fixup은 다른 커밋에 대한 수정으로 표시된 커밋을 만듭니다. 리베이스 중 --autosquash는 fixup! 및 squash! 커밋을 대상 옆에 자동으로 배치합니다. 이는 '일찍 커밋하고 나중에 정리' 워크플로를 간소화합니다.
# Create a fixup commit targeting an earlier commit
git commit --fixup a1b2c3
# Autosquash during rebase (auto-reorders fixups)
git rebase -i --autosquash HEAD~5Rebase --onto
--onto는 외과적 리베이스입니다: 커밋 범위를 한 베이스에서 다른 베이스로 이동합니다. 브랜치를 다시 부모화하거나 브랜치의 처음 몇 커밋을 삭제하는 데 사용하세요.
# Move commits from one base to another
# git rebase --onto <new-base> <old-base> <branch>
git rebase --onto main feature-old feature-new
# Drop the first N commits of a branch
git rebase --onto main HEAD~3리베이스 충돌
리베이스 중 충돌은 각 커밋에서 중지합니다. 해결하고, git add하고, --continue로 진행하세요. --skip은 충돌하는 커밋을 완전히 폐기합니다. --abort는 리베이스 전 상태로 돌아갑니다.
# During rebase, conflicts pause the process
git rebase main
# CONFLICT (content): Merge conflict in file.js
# Resolve in editor, then:
git add file.js
git rebase --continue
# Skip a commit that conflicts (drop it)
git rebase --skip
# Give up entirely
git rebase --abortCherry-Pick
커밋 체리픽
cherry-pick은 다른 브랜치의 특정 커밋을 현재 브랜치에 적용하여 동일한 변경으로 새 커밋을 만듭니다. 부모가 다르므로 새 커밋은 다른 해시를 갖습니다.
# Apply a specific commit to current branch
git cherry-pick a1b2c3d
# Cherry-pick multiple commits
git cherry-pick a1b2c3d e4f5g6h
# Cherry-pick a range (exclusive of start, inclusive of end)
git cherry-pick A..E커밋 없는 체리픽
--no-commit(-n)은 커밋을 만들지 않고 체리픽된 변경 사항을 스테이징합니다. 이를 통해 여러 체리픽을 하나의 커밋으로 결합하거나 커밋 전에 변경 사항을 수정할 수 있습니다.
# Apply changes to working tree without committing
git cherry-pick --no-commit a1b2c3d
# Stage the changes yourself
git add -p
git commit -m "Custom message"체리픽 충돌
체리픽 중 충돌은 작업을 일시 중지합니다. 해결하고, git add하고, --continue하세요. --skip은 현재 커밋을 포기합니다. --abort는 체리픽을 취소하고 브랜치를 복원합니다.
git cherry-pick a1b2c3d
# error: could not apply a1b2c3d...
# Resolve conflicts, then:
git add resolved-file.js
git cherry-pick --continue
# Skip this commit
git cherry-pick --skip
# Abort the entire cherry-pick
git cherry-pick --abort다른 브랜치에서 체리픽
고전적인 핫픽스 워크플로: 유지 관리 브랜치에서 버그를 수정한 다음 동일한 커밋을 main(및 기타 활성 브랜치)에 체리픽합니다. 이는 관련 없는 기능 작업을 병합하지 않습니다.
# Find the commit hash on another branch
git log --oneline feature-branch
# Switch to target branch
git checkout main
# Cherry-pick the commit
git cherry-pick <hash>
# Useful for hotfixes: fix on a feature branch,
# then cherry-pick the fix to main체리픽 전략
-X theirs/ours는 충돌 해결에 편향됩니다. -x는 원래 커밋 해시를 기록하는 줄을 추가합니다 — 브랜치 간 핫픽스를 체리픽할 때 감사 추적에 필수적입니다.
# Use a different merge strategy
git cherry-pick -X theirs a1b2c3d # prefer their changes on conflict
git cherry-pick -X ours a1b2c3d # prefer our changes on conflict
# Preserve original commit author
git cherry-pick -x a1b2c3d # adds "(cherry picked from ...)" to message
# Edit commit message before committing
git cherry-pick -e a1b2c3dBisect
기본 Bisect
git bisect는 커밋 기록을 이진 검색하여 어느 커밋이 버그를 도입했는지 찾습니다. 현재 커밋을 나쁨으로, 알려진 좋은 커밋을 좋음으로 표시합니다. ~log2(N)단계 후 git이 문제의 커밋을 지정합니다.
# Start bisecting
git bisect start
# Mark current commit as bad (has the bug)
git bisect bad
# Mark a known-good commit (older)
git bisect good v1.0.0
# Git checks out the midpoint. Test, then mark:
git bisect good # or
git bisect bad
# Exit bisect mode
git bisect resetBisect 로그 & 재생
git bisect log는 모든 좋음/나쁨 결정을 기록합니다. 커밋을 잘못 표시한 경우(흔한 실수), 리셋하고 로그를 재생한 다음 잘못된 단계를 수정하세요.
# Record what happens during bisect
git bisect log > bisect.log
# If you make a mistake, replay from the log
git bisect reset
git bisect replay bisect.log
# Visualize the bisect state
git bisect visualize자동화된 Bisect
git bisect run은 검색을 자동화합니다: git이 각 후보를 체크아웃하고, 스크립트를 실행하고, 종료 코드를 기반으로 커밋을 표시합니다. 이는 수동 테스트보다 극적으로 빠릅니다.
# Auto-bisect: git runs a test script and marks good/bad itself
git bisect start HEAD v1.0.0 -- # bad=HEAD, good=v1.0.0
git bisect run npm test # exit 0=good, 1-124=bad, 125=skip
# Or with a custom script
git bisect run ./scripts/check-bug.sh파일별 Bisect
git bisect start에 경로를 전달하면 해당 파일을 수정한 커밋으로 검색을 제한합니다. 이는 수백 개의 관련 없는 커밋을 건너뛰고 버그가 있을 가능성이 있는 파일에 집중합니다.
# Limit bisect to changes in a specific file
git bisect start -- path/to/file.js
# Combine with bad/good markers
git bisect bad HEAD
git bisect good v1.0.0
# Git only considers commits that touched that fileBisect Reset
완료되면 항상 git bisect reset을 실행하세요 — 원래 브랜치로 돌아가고 bisect 상태를 정리합니다. reset 없이 작업 트리가 마지막으로 테스트된 커밋에 머무릅니다.
# Exit bisect mode and return to original branch
git bisect reset
# Reset to a specific branch/commit instead
git bisect reset <branch>
# View current bisect state
git bisect status서브모듈
서브모듈 추가
서브모듈은 하나의 Git 저장소를 다른 저장소에 포함합니다 — 공유 라이브러리를 벤더링하는 데 유용합니다. git submodule add는 .gitmodules에 서브모듈을 등록합니다. 새 복제에는 --recurse-submodules가 필요합니다.
# Add a submodule at a specific path
git submodule add https://github.com/user/lib.git libs/lib
# This creates:
# - libs/lib/ (the submodule checkout)
# - .gitmodules (tracks submodule URLs and paths)
# Commit the new submodule
git commit -m "Add lib submodule"
# Clone a repo with submodules included
git clone --recurse-submodules https://github.com/user/repo.git서브모듈 업데이트
서브모듈은 특정 커밋에 고정됩니다. git submodule update --remote는 추적된 브랜치의 최신 커밋을 가져오고 포인터를 업데이트합니다. 이 포인터 변경을 부모 저장소에 커밋해야 합니다.
# Pull latest changes in all submodules
git submodule update --remote
# Update a specific submodule
git submodule update --remote libs/lib
# Then commit the updated pointer
git add libs/lib
git commit -m "Bump lib submodule"
# Initialize submodules after cloning
git submodule update --init --recursive서브모듈 Foreach
foreach는 각 서브모듈 디렉토리에서 셸 명령을 실행합니다 — 상태 확인, 업데이트 풀 또는 빌드와 같은 대량 작업에 유용합니다. --recursive는 중첩된 서브모듈로 내려갑니다.
# Run a command in every submodule
git submodule foreach 'git status'
# With recursion into nested submodules
git submodule foreach --recursive 'git checkout main'
# Use --quiet to suppress the "Entering..." messages
git submodule foreach --quiet 'git pull'Deinit & 제거
서브모듈 제거는 다단계 프로세스입니다: deinit은 등록을 취소하고, rm -rf .git/modules/...는 서브모듈 Git 데이터를 삭제하고, git rm은 작업 트리를 제거합니다. .git/modules 정리를 잊으면 분리된 데이터가 남습니다.
# Deinit a submodule (unregisters, keeps files)
git submodule deinit libs/lib
# Fully remove a submodule
git submodule deinit -f libs/lib
rm -rf .git/modules/libs/lib
git rm -f libs/lib
git commit -m "Remove lib submodule"서브모듈 브랜치
기본적으로 서브모듈은 분리된 HEAD입니다. submodule.<이름>.branch를 설정하면 --remote가 해당 브랜치를 추적합니다. 서브모듈 내에서 변경하려면 cd로 들어가서 브랜치를 체크아웃하고, 커밋하고, 푸시하세요.
# Configure a submodule to track a branch
git config -f .gitmodules submodule.libs/lib.branch main
# Now --remote updates from that branch
git submodule update --remote
# Work inside a submodule like a normal repo
cd libs/lib
git checkout feature-branch
git push
cd ../..
git add libs/lib
git commit -m "Update lib to feature-branch"훅
일반적인 훅
Git 훅은 특정 시점에 자동으로 실행되는 .git/hooks/의 스크립트입니다. 클라이언트 측 훅은 기기에서 실행되어 작업을 차단할 수 있습니다. 서버 측 훅은 원격에서 실행되어 정책을 강제합니다. 훅은 기본적으로 버전 관리되지 않습니다 — 공유하려면 Husky를 사용하세요.
# Client-side (run on your machine):
# pre-commit - runs before commit is created
# prepare-commit-msg - can edit commit message
# commit-msg - validates commit message
# pre-push - runs before pushing
# post-merge - runs after git merge
# Server-side (run on the remote):
# pre-receive - runs before refs are updated
# update - runs once per ref
# post-receive - runs after refs are updatedpre-commit 훅
pre-commit은 커밋이 생성되기 전에 실행됩니다; 0이 아닌 종료는 커밋을 중단합니다. 일반적인 용도: 스테이지된 파일 린트, 집중 테스트 실행, 코드 포맷. 빠르게 유지하세요(<5초) 그렇지 않으면 개발자가 --no-verify로 우회할 것입니다.
#!/bin/sh
# .git/hooks/pre-commit
# Run linter on staged files
npm run lint-staged
if [ $? -ne 0 ]; then
echo "Linting failed. Fix errors and try again."
exit 1
fi
# Run tests
npm test -- --findRelatedTests
if [ $? -ne 0 ]; then
echo "Tests failed."
exit 1
fi
exit 0commit-msg 훅
commit-msg는 $1로 임시 커밋 메시지 파일의 경로를 받습니다. 메시지를 검증하거나 다시 작성할 수 있습니다. 0이 아닌 종료는 커밋을 거부합니다. 이는 Conventional Commits를 강제하는 표준 방법입니다.
#!/bin/sh
# .git/hooks/commit-msg
# Enforce Conventional Commits format
pattern='^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)(\(.*\))?: .{1,72}$'
if ! grep -qE "$pattern" "$1"; then
echo "Invalid commit message format."
echo "Use: <type>(<scope>): <description>"
exit 1
fiHusky 설정
Husky는 버전이 지정된 .husky/ 디렉토리에서 Git 훅을 설치하므로 npm install 후 모든 팀원이 동일한 훅을 받습니다. lint-staged는 스테이지된 파일에서만 명령을 실행하여 pre-commit을 빠르게 유지합니다.
# Install Husky
npm install --save-dev husky
npx husky init
# Add a pre-commit hook
echo 'npm run lint-staged' > .husky/pre-commit
# Add a commit-msg hook
echo 'npx --no-install commitlint --edit $1' > .husky/commit-msg
# package.json
{
"scripts": { "prepare": "husky" },
"lint-staged": {
"*.{js,ts}": ["eslint --fix", "prettier --write"]
}
}pre-push 훅
pre-push는 참조가 푸시되기 전에 실행됩니다; 0이 아닌 종료는 중단합니다. stdin에서 제안된 푸시를 읽습니다. 일반적인 용도: 보호된 브랜치로의 푸시 차단, 전체 테스트 스위트 실행.
#!/bin/sh
# .husky/pre-push
# Reads stdin: <local ref> <local sha> <remote ref> <remote sha>
while read local_ref local_sha remote_ref remote_sha; do
if [ "$remote_ref" = "refs/heads/main" ]; then
echo "Direct push to main is not allowed."
exit 1
fi
done
npm test
if [ $? -ne 0 ]; then
echo "Tests failed. Push aborted."
exit 1
fiWorktree
Worktree 추가
worktree는 동일한 저장소에 연결된 별도의 작업 디렉토리입니다. 컨텍스트를 전환하기 위해 스태싱 없이 다른 디렉토리에서 여러 브랜치를 동시에 체크아웃할 수 있습니다.
# Create a worktree at a path, on a new branch
git worktree add ../project-feature feature-branch
# Worktree on an existing branch
git worktree add ../project-hotfix hotfix-branch
# Worktree at a specific commit (detached HEAD)
git worktree add --detach ../project-inspect v1.0.0
# List all worktrees
git worktree listWorktree 워크플로
worktree는 컨텍스트 전환에 빛을 발합니다: 기능에 깊이 빠져 있을 때 긴급 버그가 도착합니다. 스태싱하고 IDE 상태를 잃는 대신 main에 worktree를 만들고, 거기서 버그를 수정하고, 돌아오세요.
# Scenario: working on feature, urgent bug comes in
git worktree add ../project-hotfix main
cd ../project-hotfix
git checkout -b fix-urgent
# ... fix the bug, commit, push ...
cd ../project-feature
# Your feature work is untouched
# Clean up when done
git worktree remove ../project-hotfix제거 & 정리
remove는 worktree 디렉토리와 관리 메타데이터를 삭제합니다. 있던 브랜치는 남습니다. worktree에 커밋되지 않은 변경 사항이 있으면 --force를 전달하지 않는 한 remove가 거부합니다.
# Remove a worktree (must be clean or use --force)
git worktree remove ../project-feature
# Force remove even with uncommitted changes
git worktree remove --force ../project-feature
# Prune worktree admin files for deleted directories
git worktree prune
# Show what would be pruned
git worktree prune --dry-run -vWorktree 이점
worktree는 여러 고통스러운 점을 해결합니다: 컨텍스트 전환을 위한 스태싱 없음, 병 렬 빌드/테스트, 브랜치별 격리된 node_modules, 나란히 브랜치 비교. 공유 객체 데이터베이스는 최소한의 디스크 오버헤드를 의미합니다.
# 1. No stashing needed for context switches
# 2. Run long builds/tests in one worktree while
# continuing work in another
# 3. Each worktree has its own node_modules
# 4. Compare two branches side-by-side in two
# editor windows
# 5. Shared object database = minimal disk overhead
# Typical layout:
# ~/projects/
# main-repo/ (main branch)
# main-repo-feature/ (feature worktree)
# main-repo-hotfix/ (hotfix worktree)잠긴 Worktree
교란되지 않아야 할 작업이 포함된 경우 worktree를 잠그세요(장기 실행 빌드, 디버거 연결). 잠긴 worktree는 정리(prune)에서 살아남습니다. move는 worktree를 재배치; repair는 관리 파일을 수정합니다.
# Lock a worktree (prevents it from being pruned)
git worktree lock ../project-feature --reason "Running long build"
# Unlock when done
git worktree unlock ../project-feature
# Move a worktree to a new path
git worktree move ../project-feature ../new-location/project-feature
# Repair after moving manually
git worktree repair ../new-location/project-featureReflog
Reflog 보기
reflog는 HEAD와 브랜치 끝에 대한 모든 변경을 기록합니다 — 커밋, 체크아웃, 리셋, 리베이스. 로컬 안전망입니다: 파괴적인 작업 후에도 커밋이 reflog에 여전히 있습니다.
# Show reflog for HEAD
git reflog
# a1b2c3d HEAD@{0}: commit: Fix bug
# e4f5g6h HEAD@{1}: checkout: moving to feature
# 789abc0 HEAD@{2}: reset: moving to HEAD~1
# Show reflog for a specific branch
git reflog show feature
# Show reflog with dates
git reflog --date=iso잃어버린 커밋 복구
하드 리셋이나 리베이스 후 '잃어버린' 커밋은 여전히 reflog를 통해 도달 가능합니다. git reflog에서 해시를 찾은 다음 reset --hard 또는 cherry-pick으로 복구하세요. 이것이 Git이 안전한 이유입니다 — 거의 모든 것이 진정으로 사라지지 않습니다.
# Find the commit you lost (e.g., after a hard reset)
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# e4f5g6h HEAD@{1}: commit: Important work <-- this one
# Reset back to the lost commit
git reset --hard e4f5g6h
# Or cherry-pick it onto your current branch
git cherry-pick e4f5g6hReflog & Reset
ORIG_HEAD는 파괴적인 작업(reset, merge, rebase) 후 이전 HEAD를 가리키는 편의 참조입니다. git reset --hard ORIG_HEAD가 한 명령으로 마지막 작업을 취소합니다.
# Undo a git reset --hard
git reflog
git reset --hard HEAD@{1}
# Undo a rebase
git reflog
git reset --hard HEAD@{5}
# Undo a merge
git reset --hard ORIG_HEAD
# ORIG_HEAD is set by merge, rebase, reset, and cherry-pick만료 & 정리
reflog 항목은 축적되어 디스크 공간을 소비합니다. expire는 오래된 항목을 제거; --expire-unreachable은 어떤 참조에서도 도달할 수 없는 항목만 대상으로 합니다. 만료 후 git gc --prune=now를 실행하여 도달할 수 없는 객체를 삭제하세요.
# Expire reflog entries older than 30 days
git reflog expire --expire=30.days
# Expire entries unreachable from current branches
git reflog expire --expire-unreachable=30.days
# Delete a specific reflog entry
git reflog delete HEAD@{2}
# Dry run (see what would be expired)
git reflog expire --dry-run --expire=now --all브랜치용 Reflog
각 브랜치는 자체 reflog를 유지합니다. git branch -D로 브랜치를 삭제해도 커밋은 reflog에 남습니다 — 해시를 찾아 git branch <이름> <해시>로 브랜치를 재생성하세요.
# Each branch has its own reflog
git reflog show main
# a1b2c3d main@{0}: commit: Update docs
# e4f5g6h main@{1}: pull origin main: Fast-forward
# Recover a deleted branch
git reflog # find the hash the branch pointed to
git branch recovered-branch e4f5g6h
# Compare current state with a past reflog entry
git diff HEAD@{1} HEADLFS
설치 & 추적
Git LFS는 큰 파일(이미지, 비디오, 바이너리)을 Git 저장소 밖에 저장하고 커밋에서 포인터 파일로 교체합니다. git lfs track은 .gitattributes에 패턴을 등록합니다. 큰 파일을 추가하기 전에 항상 .gitattributes를 커밋하세요.
# Install Git LFS (once per user)
git lfs install
# Track large file types
git lfs track "*.psd"
git lfs track "*.zip"
git lfs track "assets/*"
# View tracking rules
cat .gitattributes
# Commit the .gitattributes file
git add .gitattributes
git commit -m "Configure LFS tracking"LFS 파일 추가 & 커밋
파일 패턴이 추적되면 git add가 LFS를 통해 자동으로 파일을 스테이징합니다. 커밋은 바이너리 대신 작은 포인터 파일(~130바이트)을 저장합니다. 실제 내용은 푸시 시 LFS 서버에 업로드됩니다.
# After configuring tracking, add files normally
git add design.psd
git commit -m "Add design file"
# Verify LFS is handling the file
git lfs ls-files
# a1b2c3d4 * design.psd
# The commit contains a pointer, not the actual file
git show HEAD -- design.psd
# version https://git-lfs.github.com/spec/v1
# oid sha256:...
# size 12345678복제 & 풀
LFS가 있는 저장소를 복제하면 먼저 포인터 파일을 다운로드한 다음 실제 내용을 다운로드합니다. LFS 다운로드가 실패하면 git lfs pull이 재시도합니다. git lfs fetch는 작업 트리에 쓰지 않고 객체를 다운로드합니다.
# Clone a repo with LFS files (downloads them automatically)
git clone https://github.com/user/repo.git
# If LFS files are missing, fetch them
git lfs pull
# Fetch LFS objects without checking them out
git lfs fetch
# Checkout LFS files for specific paths
git lfs checkout assets/LFS로 마이그레이션
git lfs migrate import는 기록의 큰 파일을 LFS 포인터로 소급 변환합니다. 이는 모든 커밋 해시를 다시 작성합니다 — 모든 협력자가 다시 복제해야 합니다. 영향을 보려면 먼저 --dry-run을 실행하세요.
# Convert existing large files to LFS (rewrites history!)
git lfs migrate import --include="*.psd" --include-ref=refs/heads/main
# Migrate all branches
git lfs migrate import --include="*.psd" --everything
# Check what would be migrated (dry run)
git lfs migrate import --include="*.psd" --include-ref=refs/heads/main --dry-runLFS 관리
git lfs status는 보류 중인 LFS 변경 사항을 보여줍니다. git lfs env는 구성을 표시합니다. git lfs fsck는 포인터 파일이 참조하는 모든 LFS 객체가 있고 손상되지 않았는지 검증합니다.
# View LFS status
git lfs status
# List all LFS files in the repo
git lfs ls-files
# Check LFS configuration
git lfs env
# Untrack a file type (does not remove existing LFS objects)
git lfs untrack "*.zip"
# Verify LFS objects are present and valid
git lfs fsckCI/CD 통합
GitHub Actions 기본
GitHub Actions는 push/PR 시 워크플로를 실행합니다. actions/checkout이 저장소를 가져옵니다; fetch-depth: 0은 전체 기록을 가져옵니다. npm ci는 lockfile에서 설치합니다(install보다 빠르고 엄격). 캐시 키로 종속성을 캐싱하세요.
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm test
- run: npm run build조건부 워크플로
on: push: branches로 브랜치나 이벤트별로 워크플로를 필터링합니다. 컨텍스트를 기반으로 작업을 건너뛰려면 작업 수준의 if: 조건을 사용하세요. needs:는 작업 간 종속성을 만듭니다 — 배포는 테스트가 통과할 때만 실행됩니다.
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test
deploy:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- run: ./deploy.shCI에서 Git 훅
CI 파이프라인은 종종 로컬 훅을 반영합니다: 먼저 린트(빠른 실패), 그 다음 테스트. needs: lint는 린팅이 통과할 때만 테스트가 실행되도록 보장하여 CI 시간을 절약합니다. 작업을 분할하면 속도를 위해 병렬 실행기가 가능합니다.
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci
- run: npm run lint
- run: npm run typecheck
test:
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test -- --coverage비밀 & 환경
비밀(API 키, 토큰)을 저장소 설정에 저장하고 ${{ secrets.NAME }}으로 참조하세요. 로그에 절대 표시되지 않습니다. 환경은 배포 전 수동 승인을 요구할 수 있어 게이트를 추가합니다.
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # requires manual approval
steps:
- uses: actions/checkout@v4
- name: Deploy
env:
API_KEY: ${{ secrets.API_KEY }}
DB_URL: ${{ secrets.DATABASE_URL }}
run: ./scripts/deploy.sh "$API_KEY" "$DB_URL"매트릭스 빌드
매트릭스 빌드는 동일한 작업을 여러 OS/언어 조합에서 병렬로 실행합니다. 이는 플랫폼별 버그를 조기에 발견합니다. 하나가 실패해도 모든 조합을 실행하려면 fail-fast: false를 사용하세요. CI 시간을 제어하기 위해 매트릭스를 합리적으로 유지하세요.
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node-version: ['18', '20', '22']
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test관련 Git 스니펫
Copy-paste ready code for common tasks.
Was this helpful?