Skip to content

필사 모드: Git 마스터 가이드 — 기초부터 rebase, cherry-pick, bisect, worktree까지

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

들어가며

Git은 개발자가 매일 사용하지만, 대부분은 add-commit-push 루프에서 벗어나지 못한다. merge 충돌이 발생하면 당황하고, rebase는 두렵고, bisect나 worktree의 존재조차 모르는 경우가 많다.

이 글에서는 Git의 내부 구조부터 시작해서 실무에서 반드시 알아야 할 고급 명령어, 브랜칭 전략, PR 리뷰 문화, 모노레포 관리, 위기 상황 대처법까지 **Git의 모든 것**을 350줄 이상에 걸쳐 총정리한다.

1. Git 내부 구조 이해하기

Git을 제대로 쓰려면 내부 구조를 이해해야 한다. Git은 본질적으로 **키-값 저장소(content-addressable filesystem)**이다.

1.1 네 가지 핵심 객체

Git의 모든 데이터는 네 가지 객체 타입으로 저장된다.

| 객체 | 역할 | 설명 |

|------|------|------|

| blob | 파일 내용 | 파일의 스냅샷 (이름 없이 내용만) |

| tree | 디렉토리 | blob과 다른 tree를 참조하는 목록 |

| commit | 스냅샷 | tree + 부모 커밋 + 메타데이터 |

| tag | 이름표 | 특정 커밋에 붙이는 annotated tag |

각 객체는 SHA-1 해시로 식별된다. 같은 내용이면 같은 해시가 나오므로, Git은 자연스럽게 중복을 제거한다.

객체 타입 확인

git cat-file -t HEAD

커밋 객체 내용 보기

git cat-file -p HEAD

tree 객체 탐색

git ls-tree HEAD

1.2 세 가지 영역

Git에는 세 가지 핵심 영역이 있다.

- **Working Directory** -- 실제 파일이 있는 디렉토리. 우리가 편집하는 공간이다.

- **Staging Area (Index)** -- 다음 커밋에 포함될 변경 사항을 준비하는 영역이다.

- **Repository (.git)** -- 커밋 히스토리와 모든 객체가 저장되는 공간이다.

세 영역 간 파일 이동 흐름

Working -> Staging

git add file.txt

Staging -> Repository

git commit -m "feat: add file"

Repository -> Working (특정 파일 되돌리기)

git checkout HEAD -- file.txt

1.3 HEAD와 ref

- **HEAD** -- 현재 체크아웃된 커밋을 가리키는 포인터이다. 보통 브랜치를 가리킨다.

- **branch** -- 특정 커밋을 가리키는 이동 가능한 포인터이다.

- **tag** -- 특정 커밋을 가리키는 고정 포인터이다.

HEAD가 가리키는 곳 확인

cat .git/HEAD

ref: refs/heads/main

브랜치가 가리키는 커밋 확인

cat .git/refs/heads/main

Detached HEAD 상태 만들기

git checkout HEAD~2

2. 필수 명령어 치트시트

매일 쓰는 명령어를 상황별로 정리했다.

2.1 기본 워크플로우

저장소 초기화 / 클론

git init

git clone https://github.com/user/repo.git

변경 사항 확인

git status

git diff # unstaged 변경

git diff --staged # staged 변경

git diff HEAD # 전체 변경

스테이징 & 커밋

git add -p # 대화형 부분 스테이징

git commit -m "feat: login" # 커밋

git commit --amend # 마지막 커밋 수정

원격 동기화

git fetch origin # 원격 변경만 가져오기

git pull --rebase origin main # fetch + rebase

git push origin feature/login # 푸시

2.2 브랜치 관리

브랜치 생성 & 이동

git branch feature/auth

git checkout -b feature/auth # 생성 + 이동

git switch -c feature/auth # Git 2.23+ 추천

브랜치 목록

git branch -a # 로컬 + 원격

git branch --merged # 병합 완료된 브랜치

git branch -d feature/old # 안전 삭제

git branch -D feature/old # 강제 삭제

원격 브랜치 정리

git remote prune origin

git fetch -p

2.3 stash -- 작업 임시 저장

작업 중 급하게 다른 브랜치로 이동해야 할 때 stash를 사용한다.

현재 변경 사항 저장

git stash

git stash push -m "WIP: login form"

stash 목록 확인

git stash list

복원

git stash pop # 꺼내면서 삭제

git stash apply stash@{0} # 꺼내되 유지

특정 파일만 stash

git stash push -m "partial" -- src/auth.ts

stash를 브랜치로 변환

git stash branch new-branch stash@{0}

3. 브랜칭 전략 비교

3.1 Git Flow

가장 전통적인 브랜칭 모델로, Vincent Driessen이 2010년에 제안했다.

**구조:**

- `main` -- 프로덕션 코드

- `develop` -- 다음 릴리스 개발

- `feature/*` -- 기능 개발

- `release/*` -- 릴리스 준비

- `hotfix/*` -- 긴급 버그 수정

**적합한 팀:** 릴리스 주기가 긴 프로젝트 (월 1-2회), 여러 버전을 동시에 유지해야 하는 경우.

**단점:** 브랜치가 많아서 복잡하고, CI/CD와 잘 맞지 않는다.

3.2 GitHub Flow

GitHub가 실제로 사용하는 단순한 모델이다.

**구조:**

- `main` -- 항상 배포 가능한 상태

- `feature/*` -- main에서 분기, PR로 병합

**적합한 팀:** 지속적 배포 환경, 소규모 팀, 웹 서비스.

**규칙:** main은 항상 배포 가능해야 하며, feature 브랜치에서 작업 후 PR을 통해 merge한다.

3.3 Trunk-Based Development

Google, Meta 등 대형 IT 기업이 사용하는 전략이다.

**구조:**

- `main` (trunk) -- 모든 개발자가 직접 커밋하거나 short-lived 브랜치로 작업

- 브랜치 수명: 최대 1-2일

**적합한 팀:** Feature Flag 인프라가 있는 팀, 대규모 조직, 빠른 피드백 루프.

3.4 비교 요약

| 항목 | Git Flow | GitHub Flow | Trunk-Based |

|------|----------|-------------|-------------|

| 복잡도 | 높음 | 낮음 | 중간 |

| 배포 빈도 | 월 1-2회 | 매일 | 하루 수회 |

| 팀 규모 | 대규모 | 소-중규모 | 모든 규모 |

| Feature Flag 필요 | 아니오 | 아니오 | 예 |

| CI/CD 궁합 | 보통 | 좋음 | 매우 좋음 |

4. Merge vs Rebase

Git에서 가장 논쟁적인 주제 중 하나이다.

4.1 Merge -- 히스토리 보존

feature 브랜치를 main에 merge

git checkout main

git merge feature/auth

merge는 두 브랜치의 공통 조상을 찾아 3-way merge를 수행하고, **merge commit**을 생성한다. 히스토리가 그대로 보존되므로 "언제 어떤 브랜치에서 작업했는지"를 추적할 수 있다.

4.2 Rebase -- 깔끔한 히스토리

feature 브랜치에서 main의 최신 변경을 가져오기

git checkout feature/auth

git rebase main

rebase는 feature 브랜치의 커밋들을 main의 끝에 하나씩 재적용한다. 결과적으로 **직선형 히스토리**가 만들어진다.

4.3 Interactive Rebase -- 커밋 정리의 핵심

최근 5개 커밋 정리

git rebase -i HEAD~5

인터랙티브 리베이스 편집기에서 사용할 수 있는 명령어는 다음과 같다.

- **pick** -- 커밋 유지

- **reword** -- 커밋 메시지 수정

- **edit** -- 커밋 내용 수정

- **squash** -- 이전 커밋과 합치기 (메시지 합침)

- **fixup** -- 이전 커밋과 합치기 (메시지 버림)

- **drop** -- 커밋 삭제

실제 사용 예시: PR 전에 커밋 정리

에디터에서 아래처럼 수정

pick abc1234 feat: add login page

squash def5678 fix: typo in login

squash ghi9012 style: adjust padding

-> 3개 커밋이 1개로 합쳐짐

4.4 언제 어떤 것을 쓸까

| 상황 | 추천 |

|------|------|

| PR 머지 | Squash Merge 또는 Rebase Merge |

| 로컬 커밋 정리 | Interactive Rebase |

| 공유 브랜치 | Merge (rebase 금지) |

| 개인 feature 브랜치 | Rebase로 main 동기화 |

**황금률:** 이미 push된 커밋은 rebase하지 마라. 다른 사람이 참조하고 있을 수 있다.

5. 고급 명령어 마스터

5.1 cherry-pick -- 특정 커밋만 가져오기

다른 브랜치의 특정 커밋 하나를 현재 브랜치로 복사한다.

특정 커밋 가져오기

git cherry-pick abc1234

여러 커밋 한번에

git cherry-pick abc1234 def5678

범위로 가져오기 (abc는 미포함, def는 포함)

git cherry-pick abc1234..def5678

커밋하지 않고 변경만 적용

git cherry-pick --no-commit abc1234

**사용 사례:**

- hotfix 브랜치의 버그 수정을 develop에도 적용

- 잘못된 브랜치에 커밋한 것을 올바른 브랜치로 이동

- 릴리스 브랜치에 특정 기능만 선별 포함

5.2 bisect -- 이진 검색으로 버그 찾기

수백 개의 커밋 중 어디서 버그가 생겼는지 이진 검색으로 찾는다.

bisect 시작

git bisect start

현재(버그 있음)를 bad로 표시

git bisect bad

정상이었던 커밋을 good으로 표시

git bisect good v2.0.0

Git이 중간 커밋을 체크아웃 -> 테스트 -> 판별

git bisect good # 또는 git bisect bad

원인 커밋을 찾으면 리셋

git bisect reset

자동화도 가능하다.

테스트 스크립트로 자동 bisect

git bisect start HEAD v2.0.0

git bisect run npm test

이렇게 하면 Git이 자동으로 각 커밋에서 테스트를 돌리고, 처음으로 실패하는 커밋을 찾아준다.

5.3 worktree -- 여러 브랜치 동시 작업

하나의 저장소에서 여러 작업 디렉토리를 만들어 동시에 다른 브랜치를 작업할 수 있다.

새 worktree 생성

git worktree add ../project-hotfix hotfix/critical-bug

worktree 목록 확인

git worktree list

worktree 제거

git worktree remove ../project-hotfix

새 브랜치를 만들면서 worktree 생성

git worktree add -b feature/new-ui ../project-ui

**사용 사례:**

- main에서 코드 리뷰하면서 feature에서 개발 계속하기

- 긴급 hotfix와 현재 작업을 동시에 진행

- CI 빌드를 기다리는 동안 다른 작업 시작

5.4 reflog -- 실수 복구의 최후 보루

reflog는 HEAD가 가리킨 모든 곳의 기록이다. 실수로 커밋을 잃어버려도 reflog로 복구할 수 있다.

reflog 확인

git reflog

실수로 reset --hard 했을 때 복구

git reflog

HEAD@{2}: commit: important feature 를 찾으면

git reset --hard HEAD@{2}

삭제된 브랜치 복구

git reflog

git checkout -b recovered-branch HEAD@{5}

특정 기간 내 기록

git reflog --since="2 days ago"

**주의:** reflog는 로컬에만 존재하고, 기본 90일 후 만료된다.

6. .gitconfig 최적화

생산성을 높이는 Git 설정을 소개한다.

6.1 유용한 alias

[alias]

상태 & 로그

st = status -sb

lg = log --oneline --graph --decorate --all

last = log -1 HEAD --stat

브랜치

co = checkout

sw = switch

br = branch -vv

brd = branch -d

커밋

cm = commit -m

ca = commit --amend --no-edit

undo = reset HEAD~1 --mixed

diff

df = diff --stat

dfc = diff --cached

stash

sl = stash list

sp = stash pop

ss = stash push -m

정리

cleanup = "!git branch --merged | grep -v '\\*\\|main\\|develop' | xargs -n 1 git branch -d"

6.2 core 설정

[core]

editor = code --wait

autocrlf = input # macOS/Linux

ignorecase = false

pager = delta # delta pager 사용

[pull]

rebase = true # pull 시 항상 rebase

[push]

default = current # 현재 브랜치만 push

autoSetupRemote = true # push 시 자동 upstream 설정

[init]

defaultBranch = main

[diff]

tool = vscode

colorMoved = default

[merge]

conflictstyle = diff3 # 3-way 충돌 표시

tool = vscode

[rerere]

enabled = true # 충돌 해결 기억하기

6.3 delta -- 더 나은 diff 도구

delta는 Git diff 출력을 보기 좋게 바꿔주는 도구이다.

설치

brew install git-delta

.gitconfig에 추가

[core]

pager = delta

[interactive]

diffFilter = delta --color-only

[delta]

navigate = true

line-numbers = true

side-by-side = true

7. GitHub PR 리뷰 베스트 프랙티스

7.1 좋은 PR의 조건

1. **크기:** 200-400줄 이하. 그 이상이면 쪼개라.

2. **단일 목적:** 하나의 PR은 하나의 변경 사항만.

3. **설명:** 왜 이 변경이 필요한지, 어떻게 테스트했는지 기술.

4. **Self-Review:** 올리기 전에 본인이 먼저 리뷰.

7.2 PR 템플릿

변경 사항

- 무엇을 왜 변경했는지

테스트

- [ ] 단위 테스트 추가/수정

- [ ] 로컬에서 동작 확인

- [ ] 엣지 케이스 검증

스크린샷 (UI 변경 시)

관련 이슈

- closes #123

7.3 리뷰 에티켓

**리뷰어:**

- 코드의 "의도"를 먼저 이해하라. 스타일보다 로직에 집중.

- 질문 형태로 피드백하라: "이 부분은 왜 이렇게 했나요?" 가 "이건 틀렸습니다"보다 낫다.

- nit, suggestion, question 등 코멘트 유형을 구분하라.

- Approve, Request Changes, Comment를 명확히 사용하라.

**작성자:**

- 리뷰어의 시간을 존중하라. PR을 작게 유지하라.

- 모든 코멘트에 응답하라 (최소한 리액션이라도).

- force push 후에는 리뷰어에게 알려라.

7.4 CODEOWNERS

.github/CODEOWNERS

전체 코드베이스

* @team-lead

프론트엔드

/src/components/ @frontend-team

/src/pages/ @frontend-team

백엔드 API

/src/api/ @backend-team

인프라

/terraform/ @devops-team

/k8s/ @devops-team

보안 민감 파일

/src/auth/ @security-team @team-lead

8. 커밋 메시지 컨벤션

8.1 Conventional Commits

type(scope): description

body (선택)

footer (선택)

**type 종류:**

| type | 설명 |

|------|------|

| feat | 새 기능 |

| fix | 버그 수정 |

| docs | 문서 변경 |

| style | 코드 포맷팅 (기능 변경 없음) |

| refactor | 리팩토링 |

| perf | 성능 개선 |

| test | 테스트 추가/수정 |

| chore | 빌드, 설정 변경 |

| ci | CI 설정 변경 |

예시

git commit -m "feat(auth): add Google OAuth login"

git commit -m "fix(api): handle null response from payment gateway"

git commit -m "docs(readme): update installation instructions"

Breaking Change

git commit -m "feat(api)!: change response format to JSON:API"

8.2 gitmoji

이모지로 커밋 유형을 시각적으로 구분한다.

git commit -m ":sparkles: add user profile page"

git commit -m ":bug: fix login redirect loop"

git commit -m ":recycle: refactor database connection pool"

git commit -m ":white_check_mark: add unit tests for auth module"

8.3 commitlint로 강제하기

설치

npm install -D @commitlint/cli @commitlint/config-conventional

commitlint.config.js

module.exports = {

extends: ['@commitlint/config-conventional'],

rules: {

'type-enum': [2, 'always', [

'feat', 'fix', 'docs', 'style',

'refactor', 'perf', 'test', 'chore', 'ci'

]],

'subject-max-length': [2, 'always', 72],

},

};

9. 모노레포 관리

9.1 git sparse-checkout

대규모 모노레포에서 필요한 디렉토리만 체크아웃한다.

sparse-checkout 활성화

git sparse-checkout init --cone

필요한 디렉토리만 지정

git sparse-checkout set packages/frontend packages/shared

디렉토리 추가

git sparse-checkout add packages/backend

설정 확인

git sparse-checkout list

전체 복원

git sparse-checkout disable

9.2 git subtree

외부 저장소를 서브디렉토리로 통합 관리한다.

외부 저장소 추가

git subtree add --prefix=libs/shared-utils \

https://github.com/org/shared-utils.git main --squash

변경 사항 가져오기

git subtree pull --prefix=libs/shared-utils \

https://github.com/org/shared-utils.git main --squash

변경 사항 내보내기

git subtree push --prefix=libs/shared-utils \

https://github.com/org/shared-utils.git main

9.3 Nx / Turborepo와의 연동

모노레포 빌드 도구와 Git을 연동하면 변경된 패키지만 빌드/테스트할 수 있다.

Nx: 영향받는 프로젝트만 테스트

npx nx affected --target=test --base=main --head=HEAD

Turborepo: 변경된 패키지만 빌드

npx turbo run build --filter=...[HEAD~1]

GitHub Actions에서 변경 감지

CI에서 main과 비교하여 변경된 패키지만 처리

10. 위기 상황 대처법

10.1 force push 복구

누군가 실수로 force push를 했을 때 대처법이다.

1. reflog에서 원래 커밋 찾기

git reflog show origin/main

2. 원래 커밋으로 복구

git push origin HEAD@{1}:main --force

3. 다른 팀원에게 알리기

"main 브랜치가 복구되었습니다. git pull --rebase를 실행해주세요"

**예방책:**

main 브랜치 force push 차단 (GitHub Settings)

Settings -> Branches -> Branch protection rules

"Restrict force pushes" 활성화

10.2 민감 정보 제거 (BFG Repo-Cleaner)

실수로 비밀번호, API 키 등을 커밋했을 때이다.

BFG 설치

brew install bfg

특정 파일 히스토리에서 완전 제거

bfg --delete-files secrets.env

특정 텍스트 치환

bfg --replace-text passwords.txt

정리

git reflog expire --expire=now --all

git gc --prune=now --aggressive

강제 푸시

git push --force

**주의사항:**

- BFG 실행 전에 저장소를 반드시 백업하라.

- 이미 clone한 팀원들에게 fresh clone을 요청해야 한다.

- GitHub에서 캐시 삭제를 요청해야 할 수 있다.

10.3 대용량 파일 관리 (Git LFS)

바이너리 파일, 미디어 파일 등 대용량 파일은 Git LFS를 사용한다.

Git LFS 설치 & 초기화

brew install git-lfs

git lfs install

추적할 파일 패턴 지정

git lfs track "*.psd"

git lfs track "*.zip"

git lfs track "assets/videos/*"

.gitattributes가 자동 생성됨 - 커밋 필요

git add .gitattributes

git commit -m "chore: configure Git LFS tracking"

LFS 파일 목록 확인

git lfs ls-files

이미 커밋된 대용량 파일을 LFS로 마이그레이션

git lfs migrate import --include="*.psd" --everything

10.4 잘못된 merge 되돌리기

merge 커밋 자체를 revert

git revert -m 1 MERGE_COMMIT_SHA

-m 1: 첫 번째 부모(main)를 기준으로 되돌림

-m 2: 두 번째 부모(feature)를 기준으로 되돌림

10.5 모든 것을 잃었을 때의 최후 수단

1. reflog 확인 (90일 이내)

git reflog

2. dangling 객체에서 복구

git fsck --lost-found

3. 최악의 경우: 팀원의 로컬 저장소에서 복구

팀원에게 push를 요청하거나, bundle로 받기

git bundle create backup.bundle --all

마무리

Git은 단순한 버전 관리 도구가 아니다. 팀의 협업 방식을 정의하고, 코드 품질을 보증하며, 배포 파이프라인의 근간이 되는 **핵심 인프라**이다.

이 글에서 다룬 내용을 요약하면 다음과 같다.

1. **내부 구조**를 이해하면 명령어가 직관적으로 이해된다.

2. **브랜칭 전략**은 팀 상황에 맞게 선택하라 -- 정답은 없다.

3. **rebase**는 로컬에서, **merge**는 공유 브랜치에서 사용하라.

4. **cherry-pick, bisect, worktree, reflog**는 실전에서 빛을 발한다.

5. **PR 리뷰 문화**가 코드 품질을 결정한다.

6. **Conventional Commits**로 커밋 히스토리를 깔끔하게 유지하라.

7. **위기 상황**에서 reflog와 BFG는 생명줄이다.

Git을 마스터하는 것은 하루아침에 되지 않는다. 하지만 매일 한 가지씩 새로운 명령어를 써보고, 내부 구조를 이해해 나간다면, 어느새 어떤 상황에서도 흔들리지 않는 Git 마스터가 되어 있을 것이다.

현재 단락 (1/305)

Git은 개발자가 매일 사용하지만, 대부분은 add-commit-push 루프에서 벗어나지 못한다. merge 충돌이 발생하면 당황하고, rebase는 두렵고, bisect나 wo...

작성 글자: 0원문 글자: 10,379작성 단락: 0/305