Git 완벽 정리
Git의 내부 동작 원리부터 기본/고급 명령어, 브랜치 전략, 협업, 트러블슈팅까지 한 문서로 정리한 실전 레퍼런스.
Git의 내부 동작 원리부터 기본/고급 명령어, 브랜치 전략, 협업, 트러블슈팅까지 한 문서로 정리한 실전 레퍼런스.
목표: 어떤 상황에서도 “지금 무슨 일이 일어났고, 어떻게 되돌리는지” 스스로 판단할 수 있는 수준.
[!warning] 히스토리 변경 주의
reset --hard,push --force,rebase,commit --amend는 작업을 잃거나 동료의 작업을 덮어쓸 수 있다. 공유 브랜치에서는 절대 강제로 히스토리를 바꾸지 말 것. 꼭 필요하면 먼저 백업 브랜치(git branch backup/now)를 만든다.
🧠 Git의 멘탈 모델
Git은 “스냅샷”을 저장한다
대부분의 VCS가 파일의 변경분(diff) 을 저장하는 반면, Git은 매 커밋마다 프로젝트 전체의 스냅샷을 저장한다. 바뀌지 않은 파일은 이전 스냅샷에 대한 참조(포인터)만 남긴다.
세 가지 영역 + 저장소
graph LR
WD["💻 Working Directory<br/>(작업 디렉토리)"] -->|"git add"| STAGE["📋 Staging Area<br/>(Index)"]
STAGE -->|"git commit"| REPO["📦 Local Repository<br/>(.git)"]
REPO -->|"git push"| REMOTE["🌐 Remote<br/>(origin)"]
REMOTE -->|"git fetch"| REPO
REPO -->|"git checkout / restore"| WD
STAGE -->|"git restore --staged"| WD
| 영역 | 설명 | 확인 명령 |
|---|---|---|
| Working Directory | 실제로 편집 중인 파일 | git status |
| Staging Area (Index) | 다음 커밋에 포함될 변경 | git diff --staged |
| Local Repository | 커밋된 히스토리 (.git) | git log |
| Remote | 원격 공유 저장소 | git remote -v |
파일의 4가지 상태
stateDiagram-v2
[*] --> Untracked: 새 파일
Untracked --> Staged: git add
Staged --> Unmodified: git commit
Unmodified --> Modified: 파일 편집
Modified --> Staged: git add
Staged --> Modified: 다시 편집
Unmodified --> Untracked: git rm
📝 기본 명령어
초기 설정
# 사용자 정보 (커밋에 기록됨)
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
# 기본 브랜치 이름을 main으로
git config --global init.defaultBranch main
# 줄바꿈 자동 변환 (Windows: true, mac/Linux: input)
git config --global core.autocrlf true # Windows
git config --global core.autocrlf input # mac/Linux
# 유용한 별칭(alias)
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --all"
# 설정 확인 / 위치 확인
git config --list --show-origin
저장소 시작
git init # 현재 폴더를 저장소로
git clone <url> # 원격 복제
git clone <url> my-folder # 폴더명 지정
git clone --depth 1 <url> # 최신 1개 커밋만 (얕은 복제)
일상 워크플로우
git status # 현재 상태
git status -s # 짧게 보기
git add file.txt # 특정 파일
git add . # 전체
git add -p # 변경을 조각(hunk)별로 선택 ⭐
git commit -m "feat: 로그인 추가"
git commit # 에디터로 본문까지 작성
git commit -am "fix: 버그 수정" # 추적 중인 파일 add+commit
git push origin main
git push -u origin main # upstream 설정 (이후 git push만으로 OK)
git pull # fetch + merge
git pull --rebase # fetch + rebase (히스토리 깔끔)
git fetch # 받아오기만 (병합 X)
🔍 히스토리 보기 & 비교
# 로그
git log --oneline --graph --all # 그래프로 한눈에 ⭐
git log -p file.txt # 특정 파일의 변경 내역
git log --author="Jongmin" # 작성자별
git log --since="2 weeks ago" # 기간별
git log -S "함수명" # 특정 코드가 추가/삭제된 커밋 찾기 (pickaxe)
# 차이 비교
git diff # 작업 디렉토리 vs 스테이징
git diff --staged # 스테이징 vs 마지막 커밋
git diff main..feature # 브랜치 간 비교
git diff HEAD~3 # 3커밋 전과 비교
# 한 줄의 작성자 추적
git blame file.txt
git blame -L 10,20 file.txt # 10~20줄만
# 특정 커밋 상세
git show <commit>
🌿 브랜치 & 병합
브랜치 조작
git branch # 목록
git branch -a # 원격 포함
git branch -vv # upstream + 마지막 커밋
git switch -c feature/login # 생성 + 전환 (최신 권장) ⭐
git checkout -b feature/login # 동일 (구식 방식)
git switch main # 전환
git branch -d feature/login # 병합된 브랜치 삭제
git branch -D feature/login # 강제 삭제
git branch -m old new # 이름 변경
git push origin --delete feature/x # 원격 브랜치 삭제
Merge vs Rebase
graph TB
subgraph "Merge (병합 커밋 생성)"
M1["A"] --> M2["B"] --> M3["C"]
M1 --> M4["D"] --> M5["E"]
M3 --> M6["Merge"]
M5 --> M6
end
subgraph "Rebase (선형 히스토리)"
R1["A"] --> R2["B"] --> R3["C"] --> R4["D'"] --> R5["E'"]
end
| 구분 | Merge | Rebase |
|---|---|---|
| 히스토리 | 분기 그대로 보존 | 선형으로 재작성 |
| 커밋 해시 | 유지 | 변경됨 |
| 충돌 해결 | 한 번 | 커밋마다 가능 |
| 공유 브랜치 | ✅ 안전 | ❌ 위험 (절대 금지) |
| 추천 상황 | 협업 main 통합 | 내 로컬 feature 정리 |
# Merge
git switch main
git merge feature/login
git merge --no-ff feature/login # 항상 병합 커밋 생성
# Rebase
git switch feature/login
git rebase main # main 위로 내 커밋 재배치
# 대화형 리베이스 (커밋 정리: squash/reword/drop)
git rebase -i HEAD~3
[!tip] 황금 규칙 이미 push 해서 남과 공유한 커밋은 rebase 하지 않는다. 내 로컬에만 있는 커밋을 정리할 때만 rebase를 사용한다.
충돌(Conflict) 해결
# 충돌 발생 시
git status # 충돌 파일 확인
# <<<<<<< / ======= / >>>>>>> 마커를 직접 편집
git add 해결된파일
git merge --continue # 또는 git rebase --continue
git merge --abort # 병합 취소하고 원상복구
git rebase --abort
🎒 자주 쓰는 실전 명령어
Stash — 작업 임시 보관
급하게 브랜치를 바꿔야 하는데 커밋하긴 이른 변경이 있을 때.
git stash # 변경을 치워두기
git stash -u # untracked 파일까지 포함
git stash push -m "로그인 작업 중" # 메시지 붙여 저장
git stash list # 목록
git stash pop # 최근 것 꺼내고 삭제
git stash apply stash@{1} # 특정 것 적용 (보관 유지)
git stash drop stash@{0} # 삭제
Tag — 버전 표시
git tag v1.0.0 # 가벼운 태그
git tag -a v1.0.0 -m "첫 릴리스" # 주석 태그 (권장)
git tag # 목록
git push origin v1.0.0 # 태그 푸시
git push origin --tags # 전체 태그 푸시
Cherry-pick — 특정 커밋만 가져오기
git cherry-pick <commit> # 다른 브랜치의 커밋 1개만 적용
git cherry-pick A^..B # 범위 적용
Reflog — 잃어버린 커밋 복구 ⭐
reset --hard나 잘못된 rebase로 커밋이 사라진 것 같을 때, Git은 거의 아무것도 진짜로 지우지 않는다.
git reflog # HEAD가 거쳐온 모든 이동 기록
git reset --hard HEAD@{2} # 2단계 전 상태로 복구
⏪ 되돌리기 총정리
상황별로 명령이 다르므로 무엇을 되돌릴지 먼저 판단한다.
| 상황 | 명령 | 위험도 |
|---|---|---|
| 스테이징만 취소 | git restore --staged file | 🟢 안전 |
| 파일 편집 내용 버리기 | git restore file | 🟡 변경 손실 |
| 마지막 커밋 메시지 수정 | git commit --amend | 🟡 해시 변경 |
| 공개된 커밋 되돌리기 | git revert <commit> | 🟢 안전 (새 커밋) |
| 커밋만 취소, 변경 유지 | git reset --soft HEAD~1 | 🟢 안전 |
| 커밋+스테이징 취소 | git reset HEAD~1 (mixed) | 🟡 |
| 모두 버리기 | git reset --hard HEAD~1 | 🔴 작업 손실 |
graph TB
Q1{"이미 push 했나?"} -->|"예"| REVERT["git revert<br/>(되돌리는 새 커밋)"]
Q1 -->|"아니오"| Q2{"변경을 유지?"}
Q2 -->|"커밋만 취소"| SOFT["git reset --soft"]
Q2 -->|"전부 버림"| HARD["git reset --hard"]
[!danger] revert vs reset 공유 브랜치는 무조건
revert.reset은 히스토리를 다시 쓰므로 남이 받은 커밋과 어긋난다.
🌳 브랜치 전략
GitHub Flow (단순·추천)
graph LR
MAIN["main (항상 배포 가능)"] -->|"브랜치"| FEAT["feature/xyz"]
FEAT -->|"PR"| PR["Pull Request + CI"]
PR -->|"리뷰·승인"| MAIN
MAIN -->|"자동 배포"| PROD["Production"]
main은 항상 배포 가능 상태 유지- 모든 작업은 feature 브랜치 → PR → 리뷰 → 머지
- 소규모 팀, 지속적 배포에 적합
Git Flow (릴리스 주기가 명확할 때)
graph TB
MAIN["main"] --> HOT["hotfix/*"]
MAIN --> REL["release/*"]
REL --> DEV["develop"]
DEV --> FEAT["feature/*"]
FEAT --> DEV
DEV --> REL
REL --> MAIN
HOT --> MAIN
HOT --> DEV
main(프로덕션) /develop(통합) /feature/release/hotfix- 정해진 릴리스 주기·버전이 있는 제품에 적합하지만 복잡함
Trunk-Based (대규모·CI 성숙 팀)
- 모두가
main(trunk)에 짧게 사는 브랜치로 자주 머지 - Feature Flag로 미완성 기능 숨김 → CI/CD와 궁합 최고
🤝 협업 워크플로우
표준 PR 흐름
git switch -c feature/login # 1. 브랜치
git add . && git commit -m "feat: 로그인 추가" # 2. 작업
git push -u origin feature/login # 3. 푸시
# 4. GitHub/GitLab에서 PR 생성 → CI 통과 → 리뷰
# 5. 머지 후 로컬 정리
git switch main && git pull
git branch -d feature/login
커밋 메시지 컨벤션 (Conventional Commits)
<type>(<scope>): <subject>
<body>
<footer>
| 타입 | 의미 |
|---|---|
feat | 새 기능 |
fix | 버그 수정 |
docs | 문서 |
style | 포맷팅(동작 변화 없음) |
refactor | 리팩토링 |
test | 테스트 |
chore | 빌드·설정 등 잡무 |
git commit -m "feat(auth): JWT 인증 추가
- 토큰 생성·검증 미들웨어 구현
- 로그인 엔드포인트 수정
Closes #123"
.gitignore
# 의존성
node_modules/
__pycache__/
# 빌드 산출물
dist/
build/
*.log
# 환경·비밀
.env
.env.local
*.key
# OS·에디터
.DS_Store
.idea/
.vscode/
[!tip] 이미 추적된 파일을 무시하려면
.gitignore는 추적 안 된 파일에만 적용된다. 이미 커밋된 파일은:git rm --cached file후 커밋해야 무시가 적용된다.
🚑 트러블슈팅 (자주 겪는 상황)
| 상황 | 해결 |
|---|---|
| 방금 커밋 메시지 오타 | git commit --amend |
| 잘못된 브랜치에 커밋함 | git switch 올바른브랜치 → git cherry-pick <커밋> → 원래 브랜치에서 git reset --hard HEAD~1 |
reset --hard로 날린 커밋 복구 | git reflog → git reset --hard HEAD@{n} |
| push 거부됨 (non-fast-forward) | git pull --rebase 후 다시 push |
| 큰 파일 실수로 커밋 | history 정리는 git filter-repo 또는 BFG 사용 |
| 충돌 무서워서 못 합치겠음 | git merge --abort로 안전하게 취소 가능 |
| 특정 파일만 다른 브랜치 버전으로 | git checkout <브랜치> -- file |
| 변경 다 무시하고 원격과 동일하게 | git fetch && git reset --hard origin/main 🔴 |
📋 학습 체크리스트
- 세 영역(Working/Staging/Repo)과 파일 상태 흐름 이해
-
git add -p로 부분 스테이징 -
git log --oneline --graph --all로 히스토리 읽기 - Merge와 Rebase의 차이·황금 규칙
- 충돌 해결 +
--abort로 안전 탈출 - stash / tag / cherry-pick 활용
- reflog로 잃은 커밋 복구
- reset(soft/mixed/hard) vs revert 구분
- 브랜치 전략 1개 이상 설명 가능
- PR 흐름 + 커밋 컨벤션 + .gitignore
🔗 관련 노트
- 01-02-버전관리-Git — Git 기본(기존 정리 문서)
- 01-01-CI-CD-개념 — CI/CD 파이프라인
- 02-02-GitHub-Actions — GitHub Actions 자동화
- 03-01-GitOps-원칙 — Git을 단일 진실 공급원으로
마지막 업데이트: 2026-06-02