Git Commands 가이드: 개념부터 실전 명령어까지

2026-02-12
GitCLI버전관리개발도구

Git이란?

Git은 분산 버전 관리 시스템(DVCS)이다. 코드의 변경 이력을 추적하고, 여러 사람이 동시에 작업할 수 있게 해준다.

핵심 특징:

공식 문서: Git Reference


기본 개념

Working Directory / Staging Area / Repository

Working Directory  →  Staging Area (Index)  →  Local Repository  →  Remote Repository
      (작업 공간)        (git add)               (git commit)         (git push)

파일의 상태

Untracked → Staged → Committed
              ↑         ↓
           Modified ←───┘

HEAD는 현재 체크아웃된 커밋을 가리키는 포인터다. 보통 브랜치의 최신 커밋을 가리킨다.

HEAD → main → commit C
               commit B
               commit A

초기 설정

사용자 정보 설정

git config --global user.name "이름"
git config --global user.email "이메일"

설정 확인

git config --list
git config user.name

공식 문서: git-config


저장소 생성 및 복제

새 저장소 초기화

git init

현재 디렉토리에 .git 폴더를 생성하고 Git 저장소로 만든다.

원격 저장소 복제

git clone <url>
git clone <url> <디렉토리명>

원격 저장소를 로컬에 복사한다. origin이라는 이름으로 자동 등록된다.

공식 문서: git-init / git-clone


상태 확인 명령어

git status

git status
git status -s    # 짧은 형식

작업 디렉토리와 스테이징 영역의 상태를 보여준다.

 M file.txt      # 수정됨 (unstaged)
M  file.txt      # 수정됨 (staged)
MM file.txt      # staged 후 다시 수정됨
?? newfile.txt   # untracked
A  newfile.txt   # 새 파일 (staged)
D  deleted.txt   # 삭제됨

git log

git log                      # 전체 로그
git log --oneline            # 한 줄 요약
git log --oneline --graph    # 브랜치 그래프 포함
git log -5                   # 최근 5개 커밋
git log --author="이름"       # 특정 작성자의 커밋
git log -- path/to/file      # 특정 파일의 변경 이력

git diff

git diff                    # unstaged 변경사항
git diff --staged           # staged 변경사항
git diff HEAD               # 모든 변경사항 (staged + unstaged)
git diff branch1..branch2   # 브랜치 간 차이
git diff commit1..commit2   # 커밋 간 차이

공식 문서: git-status / git-log / git-diff


변경사항 기록

git add

git add file.txt             # 특정 파일 스테이징
git add .                    # 현재 디렉토리의 모든 변경사항
git add -A                   # 저장소 전체의 모든 변경사항
git add -p                   # 변경사항을 하나씩 확인하며 스테이징
git add *.js                 # 패턴 매칭

-p (patch) 모드는 하나의 파일 안에서도 원하는 부분만 골라 스테이징할 수 있어 유용하다.

git commit

git commit -m "커밋 메시지"
git commit -am "메시지"       # add + commit (tracked 파일만)
git commit --amend            # 직전 커밋 수정 (메시지 또는 내용)

좋은 커밋 메시지 작성법

타입: 제목 (50자 이내)

본문 (선택사항, 72자 줄바꿈)
- 왜 변경했는지
- 어떤 영향이 있는지

흔히 사용하는 타입: feat, fix, refactor, docs, test, chore

git rm / git mv

git rm file.txt              # 파일 삭제 + 스테이징
git rm --cached file.txt     # Git 추적만 제거 (파일은 보존)
git mv old.txt new.txt       # 파일 이름 변경

공식 문서: git-add / git-commit


브랜치

브랜치 기본

git branch                   # 브랜치 목록
git branch -a                # 원격 브랜치 포함
git branch <이름>             # 새 브랜치 생성
git branch -d <이름>          # 브랜치 삭제 (병합 완료된 것만)
git branch -D <이름>          # 브랜치 강제 삭제

브랜치 전환

git checkout <브랜치>          # 브랜치 전환
git checkout -b <브랜치>       # 생성 + 전환
git switch <브랜치>            # 브랜치 전환 (Git 2.23+)
git switch -c <브랜치>         # 생성 + 전환 (Git 2.23+)

git switchgit checkout의 브랜치 전환 기능만 분리한 명령어다. 더 명확하고 안전하다.

병합 (Merge)

git merge <브랜치>             # 현재 브랜치에 대상 브랜치를 병합
git merge --no-ff <브랜치>     # fast-forward 없이 병합 커밋 생성
git merge --abort             # 충돌 시 병합 취소

Fast-forward vs Merge commit:

리베이스 (Rebase)

git rebase <브랜치>            # 현재 브랜치를 대상 브랜치 위로 재배치
git rebase -i HEAD~3          # 최근 3개 커밋을 인터랙티브 리베이스
git rebase --abort            # 리베이스 취소
git rebase --continue         # 충돌 해결 후 계속

리베이스는 히스토리를 깔끔하게 만들지만, 이미 push한 커밋은 리베이스하지 않는 것이 원칙이다.

공식 문서: git-branch / git-merge / git-rebase


원격 저장소

remote 관리

git remote -v                       # 원격 저장소 목록
git remote add origin <url>         # 원격 저장소 추가
git remote remove <이름>             # 원격 저장소 제거
git remote set-url origin <new-url> # URL 변경

push / pull / fetch

git push origin main                # 로컬 → 원격
git push -u origin main             # 업스트림 설정 + push
git push --force                    # 강제 push (주의!)

git pull                            # fetch + merge
git pull --rebase                   # fetch + rebase
git fetch                           # 원격 변경사항만 가져오기 (병합 X)
git fetch --all                     # 모든 원격의 변경사항 가져오기

pull vs fetch:

공식 문서: git-remote / git-push / git-pull / git-fetch


되돌리기

변경사항 취소

git checkout -- file.txt       # 특정 파일 변경사항 취소 (unstaged)
git restore file.txt           # 위와 동일 (Git 2.23+)
git restore --staged file.txt  # 스테이징 취소 (변경사항 보존)

커밋 되돌리기

git revert <commit>            # 해당 커밋을 취소하는 새 커밋 생성
git reset --soft HEAD~1        # 커밋 취소 (변경사항은 staged 상태 유지)
git reset --mixed HEAD~1       # 커밋 취소 (변경사항은 unstaged 상태)
git reset --hard HEAD~1        # 커밋 취소 + 변경사항 완전 삭제 (위험!)

revert vs reset:

공식 문서: git-restore / git-revert / git-reset


임시 저장 (Stash)

git stash                     # 현재 변경사항 임시 저장
git stash -m "메시지"          # 메시지와 함께 저장
git stash list                # stash 목록
git stash pop                 # 가장 최근 stash 적용 + 삭제
git stash apply               # stash 적용 (삭제하지 않음)
git stash drop                # 가장 최근 stash 삭제
git stash clear               # 모든 stash 삭제

브랜치를 전환해야 하는데 현재 작업을 커밋하기엔 애매할 때 유용하다.

공식 문서: git-stash


태그

git tag                       # 태그 목록
git tag v1.0.0                # 태그 생성 (lightweight)
git tag -a v1.0.0 -m "설명"   # 태그 생성 (annotated)
git push origin v1.0.0        # 특정 태그 push
git push origin --tags        # 모든 태그 push
git tag -d v1.0.0             # 로컬 태그 삭제

공식 문서: git-tag


기타 유용한 명령어

cherry-pick

git cherry-pick <commit>      # 특정 커밋만 현재 브랜치에 적용

blame

git blame file.txt            # 각 줄을 누가, 언제 수정했는지 확인

reflog

git reflog                    # HEAD 이동 이력 (reset으로 잃어버린 커밋 복구 시 유용)

clean

git clean -n                  # 삭제 대상 미리 보기 (dry run)
git clean -f                  # untracked 파일 삭제
git clean -fd                 # untracked 파일 + 디렉토리 삭제

공식 문서: git-cherry-pick / git-blame / git-reflog / git-clean


.gitignore

프로젝트 루트에 .gitignore 파일을 만들어 추적하지 않을 파일을 지정한다.

# 빌드 결과물
node_modules/
dist/
build/

# 환경 설정
.env
.env.local

# OS 파일
.DS_Store
Thumbs.db

# IDE
.vscode/
.idea/

# 로그
*.log

공식 문서: gitignore


자주 쓰는 조합

새 기능 개발 흐름

git switch -c feature/new-feature    # 브랜치 생성 + 전환
# ... 작업 ...
git add .
git commit -m "feat: 새 기능 추가"
git push -u origin feature/new-feature
# PR 생성 → 코드 리뷰 → 병합

충돌 해결

git merge feature-branch             # 충돌 발생
# 충돌 파일 편집 (<<<<<<, ======, >>>>>> 마커 해결)
git add .                            # 해결 완료 표시
git commit                           # 병합 커밋 생성

실수로 커밋한 파일 제거

git rm --cached secrets.env          # Git 추적만 제거 (파일은 남김)
echo "secrets.env" >> .gitignore     # .gitignore에 추가
git commit -m "chore: remove tracked secret file"

이전 커밋 상태 확인

git log --oneline                    # 커밋 해시 확인
git show <commit>                    # 해당 커밋의 변경 내용 보기
git checkout <commit> -- file.txt    # 특정 파일만 해당 커밋 상태로 복원

브랜치 병합 전략 가이드: 작업 브랜치에서 main으로

실제 개발에서 가장 많이 하는 작업 중 하나가 "작업 브랜치에서 완성된 코드를 main에 합치는 것"이다. 같은 결과를 내더라도 어떤 방식으로 합치느냐에 따라 히스토리의 모양과 추적 가능성이 크게 달라진다.

실전 시나리오: drafts → main

drafts 브랜치에서 작업하다가 완료 후 main에 반영하는 기본 흐름:

# 1. main을 최신 상태로 업데이트
git switch main
git pull origin main

# 2. drafts를 main에 병합 (방법은 아래에서 선택)
git merge drafts

# 3. (선택) 원격에 push
git push origin main

핵심은 2번 단계에서 어떤 병합 방법을 쓰느냐다. 아래에서 각 방법을 비교한다.


방법 1: Fast-Forward Merge (기본 동작)

main에 drafts 분기 이후 새로운 커밋이 없으면, Git은 단순히 포인터만 앞으로 이동한다.

git switch main
git merge drafts
# Before
main:    A --- B
                \
drafts:          C --- D

# After (fast-forward)
main:    A --- B --- C --- D

적합한 상황: 혼자 작업하는 프로젝트, 커밋 1~2개짜리 단순 수정


방법 2: Merge Commit (`--no-ff`)

Fast-forward가 가능한 상황에서도 강제로 merge 커밋을 생성한다.

git switch main
git merge --no-ff drafts
# After (merge commit M 생성)
main:    A --- B --- E --- M
                \         /
drafts:          C --- D

--no-ff vs 기본 merge:

적합한 상황: 팀 프로젝트, 기능 단위 추적이 필요한 경우, Git Flow 등 브랜칭 전략 사용 시


방법 3: Squash Merge

drafts의 모든 커밋을 하나의 새 커밋으로 합쳐서 main에 적용한다.

git switch main
git merge --squash drafts
git commit -m "feat: 새 기능 추가"   # 별도로 commit 필요!
# Before
drafts:  C --- D --- E  (WIP 커밋 여러 개)

# After (squash)
main:    A --- B --- S  (C+D+E가 하나의 커밋 S로)

주의: Git이 drafts가 "merge되었다"고 인식하지 않기 때문에, squash merge 후에는 반드시 브랜치를 삭제하는 것이 좋다. 삭제하지 않고 다시 merge하면 충돌이 발생할 수 있다.

적합한 상황: 실험적/임시 커밋이 많은 브랜치, PR 단위로 깔끔한 히스토리를 원할 때


방법 4: Rebase 후 Fast-Forward Merge

drafts를 main의 최신 상태 위로 "재배치"한 뒤 fast-forward merge한다.

# Step 1: drafts에서 main 위로 rebase
git switch drafts
git rebase main
# (충돌 시 해결 후 git rebase --continue)

# Step 2: main에서 fast-forward merge
git switch main
git merge drafts    # 이제 반드시 fast-forward됨
# Before
main:    A --- B --- E
                \
drafts:          C --- D

# After rebase
main:    A --- B --- E
                      \
drafts:                C' --- D'  (새로운 hash)

# After merge (fast-forward)
main:    A --- B --- E --- C' --- D'

적합한 상황: 개인 브랜치, 직선형 히스토리를 선호하는 경우, push 전 로컬 정리


방법 5: Cherry-Pick (선택적 반영)

브랜치 전체가 아니라 특정 커밋만 골라서 main에 적용한다.

git switch main
git cherry-pick <commit-hash>

# 여러 커밋
git cherry-pick <hash1> <hash2>

# 연속 범위 (hash1 제외, hash2까지 포함)
git cherry-pick <hash1>..<hash2>
# cherry-pick C와 E만 (D는 제외)
main:    A --- B --- C' --- E'
                \
drafts:          C --- D --- E  (원본은 그대로)

적합한 상황: hotfix를 여러 브랜치에 적용할 때, 특정 커밋만 먼저 main에 반영해야 할 때


전략 비교

방법 merge 커밋 개별 커밋 보존 직선형 히스토리 기능 전체 revert
Fast-Forward X O O 어려움
--no-ff O O X 쉬움
Squash X X (1개로 합침) O 쉬움
Rebase + FF X O O 어려움
Cherry-Pick X 선택적 O 어려움

어떤 전략을 선택할까?

작업 브랜치를 main에 합치려 한다
│
├─ 커밋이 1~2개이고 단순한 수정?
│  └─ Fast-Forward 또는 Squash
│
├─ 팀에서 기능 단위 추적이 필요?
│  └─ git merge --no-ff
│
├─ main 히스토리를 최대한 깔끔하게?
│  ├─ 개별 커밋 이력 불필요 → Squash
│  └─ 개별 커밋 이력 필요 → Rebase 후 FF
│
├─ 특정 커밋만 선택적으로 가져와야?
│  └─ Cherry-Pick
│
└─ 혼자 작업 + 직선형 히스토리 선호?
   └─ Rebase 후 FF

GitHub PR 병합 옵션

GitHub에서 Pull Request를 merge할 때 세 가지 버튼이 표시된다. 각각 위에서 설명한 로컬 명령어와 대응된다.

Create a merge commit

git merge --no-ff와 동일한 동작.

main:  A --- B --- M
              \   /
feature:       C --- D

Squash and merge

git merge --squash + git commit과 동일한 동작.

main:  A --- B --- S

Rebase and merge

git rebase main + git merge (fast-forward)와 유사한 동작.

main:  A --- B --- C' --- D'

참고: GitHub 저장소 Settings > General > "Automatically delete head branches"를 체크하면 PR merge 시 브랜치가 자동 삭제된다.

공식 문서: About merge methods on GitHub


병합 전 체크리스트

실수를 줄이기 위해 병합 전에 확인할 것들.

1. 반드시 main을 최신화하라

git switch main
git pull origin main

main이 최신 상태가 아니면 원격과 로컬의 히스토리가 어긋나서 push 시 충돌이 발생한다.

2. 작업 브랜치와 main의 차이를 확인하라

git log main..drafts --oneline    # drafts에만 있는 커밋
git diff main..drafts --stat      # 변경된 파일 요약

3. main이 앞서 나간 경우 처리

작업 중에 다른 사람(또는 다른 브랜치에서의 자신)이 main에 커밋을 추가한 경우:

# 방법 A: merge로 동기화 (안전, 히스토리 복잡해짐)
git switch drafts
git merge main

# 방법 B: rebase로 동기화 (깔끔, 개인 브랜치일 때만)
git switch drafts
git rebase main

4. 병합 후 브랜치 정리

# merge된 브랜치 확인
git branch --merged main

# 로컬 브랜치 삭제
git branch -d drafts

# 원격 브랜치 삭제
git push origin --delete drafts

# 원격에서 삭제된 브랜치의 로컬 tracking 참조 정리
git fetch --prune

삭제 기준:


알아두면 좋은 최신 기능

git rerere (충돌 해결 재사용)

git config --global rerere.enabled true

merge 충돌을 한 번 해결하면 Git이 해결 방법을 기록해두고, 같은 충돌이 다시 발생하면 자동으로 동일하게 해결한다. rebase 중 반복되는 충돌에 특히 유용하다.

--force-with-lease (안전한 Force Push)

# 위험: 원격의 모든 변경을 덮어씀
git push --force

# 안전: 원격이 예상한 상태일 때만 push
git push --force-with-lease

rebase 후 push할 때 --force 대신 --force-with-lease를 쓰면, 다른 사람이 그 사이에 push한 내용이 있을 경우 push를 거부한다.

merge-ort 전략 (Git 2.34+ 기본값)

기존 merge-recursive 전략을 대체하는 새로운 merge 엔진. 대규모 rename이 있는 merge에서 수백~수천 배의 성능 향상이 보고되었다. Git 2.34 이상이면 자동 적용되므로 별도 설정이 필요 없다.

공식 문서: git-rerere / merge strategies


참고 링크