Skip to main content

Git 기초

Git은 분산 버전 관리 시스템(DVCS)입니다. 코드의 변경 이력을 추적하고, 여러 사람이 동시에 작업하고, 언제든 이전 상태로 되돌릴 수 있게 해줍니다. AI/ML 분야에서 Git은 단순한 코드 관리 도구를 넘어 실험 재현성의 기반이 됩니다. 어떤 코드로, 어떤 설정으로, 어떤 결과를 얻었는지 — 이 모든 것을 Git 이력으로 추적할 수 있습니다.

학습 목표

  • Git의 내부 모델(스냅샷, 3가지 영역, HEAD)을 이해하고 설명할 수 있다
  • 브랜치를 생성하고, 커밋하고, 원격 저장소에 푸시하며, PR을 통해 협업할 수 있다
  • Conventional Commits 규칙에 따른 의미 있는 커밋 메시지를 작성할 수 있다
  • ML 프로젝트에 적합한 .gitignore를 구성하고, 실험 브랜치를 관리할 수 있다

왜 중요한가

ML 프로젝트에서 가장 흔한 문제 중 하나는 “지난 주에 좋았던 결과를 재현할 수 없다”는 것입니다. 하이퍼파라미터를 바꾸고, 데이터 전처리를 수정하고, 모델 구조를 변경하면서 — 어떤 조합이 최고 성능을 냈는지 추적할 수 없게 됩니다. Git으로 코드를 관리하면, 모든 변경 사항이 기록되어 특정 시점의 코드 상태를 정확히 복원할 수 있습니다. 팀 협업에서도 Git은 필수입니다. 여러 사람이 같은 코드베이스에서 동시에 작업할 때, 브랜치와 머지를 통해 충돌 없이 협업할 수 있습니다. 코드 리뷰(PR)를 통해 품질을 유지하고, 문제가 생기면 즉시 이전 버전으로 되돌릴 수 있습니다.

Git 내부 모델

스냅샷 기반 (vs diff 기반)

Git은 파일의 변경분(diff) 이 아니라 스냅샷(snapshot) 을 저장합니다. 커밋할 때마다 프로젝트 전체의 스냅샷을 찍고, 변경되지 않은 파일은 이전 스냅샷에 대한 참조만 저장합니다.
=== Diff 기반 (SVN 등) ===
파일 A:  v1 → Δ1 → Δ2 → Δ3
파일 B:  v1 → Δ1      → Δ2

=== 스냅샷 기반 (Git) ===
커밋 1: [A1] [B1] [C1]     ← 전체 스냅샷
커밋 2: [A2] [B1] [C1]     ← A만 변경, B/C는 참조
커밋 3: [A2] [B2] [C1]     ← B만 변경, A/C는 참조

3가지 영역

Git은 파일의 상태를 3가지 영역으로 관리합니다. 이 개념을 이해해야 add, commit, checkout 등의 명령어가 직관적으로 와닿습니다.
┌──────────────┐    git add    ┌──────────────┐   git commit   ┌──────────────┐
│  Working     │ ────────────► │  Staging     │ ─────────────► │  Repository  │
│  Directory   │               │  Area        │                │  (.git)      │
│  (작업 디렉터리) │             │  (스테이징 영역) │              │  (저장소)     │
│              │ ◄──────────── │              │ ◄───────────── │              │
│  파일 수정     │  git restore  │  커밋 준비     │  git reset     │  커밋 이력    │
└──────────────┘               └──────────────┘                └──────────────┘
영역설명파일 상태
Working Directory실제 파일이 있는 디렉터리Modified (수정됨), Untracked (미추적)
Staging Area다음 커밋에 포함될 변경사항Staged (스테이지됨)
Repository커밋된 이력이 저장되는 .git 디렉터리Committed (커밋됨)

HEAD와 브랜치 포인터

                   main


[C1] ← [C2] ← [C3] ← [C4]

                      feature

                       HEAD
  • HEAD: 현재 작업 중인 커밋을 가리키는 포인터. 보통 브랜치를 통해 간접 참조
  • 브랜치: 특정 커밋을 가리키는 이동 가능한 포인터. 새 커밋이 생기면 자동으로 이동
  • 태그: 특정 커밋을 가리키는 고정된 포인터. 릴리스 버전 등에 사용

초기 설정

1

사용자 정보 설정

Git 커밋에 기록될 이름과 이메일을 설정합니다. 모든 커밋에 이 정보가 포함됩니다.
git config --global user.name "홍길동"
git config --global user.email "gildong@example.com"
2

기본 설정

편집기, 기본 브랜치 이름, 줄바꿈 처리 등을 설정합니다.
# 기본 편집기 (커밋 메시지 작성 등)
git config --global core.editor "code --wait"   # VS Code
# git config --global core.editor "vim"          # Vim

# 기본 브랜치 이름 (main 권장)
git config --global init.defaultBranch main

# 줄바꿈 처리
git config --global core.autocrlf input   # macOS/Linux
# git config --global core.autocrlf true  # Windows

# 설정 확인
git config --list
3

SSH 키 설정

GitHub/GitLab 등 원격 저장소에 SSH로 인증하기 위한 키를 생성합니다.
# SSH 키 생성 (Ed25519 권장)
ssh-keygen -t ed25519 -C "gildong@example.com"

# 키 확인
cat ~/.ssh/id_ed25519.pub

# SSH 에이전트에 키 등록
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

# GitHub에 공개키 등록 후 연결 테스트
ssh -T git@github.com
4

유용한 추가 설정

# pull 시 rebase 사용 (merge commit 방지)
git config --global pull.rebase true

# diff 도구 설정
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'

# alias 설정
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.lg "log --oneline --graph --all --decorate"

워크플로우

1

저장소 복제 (clone)

원격 저장소를 로컬로 복제합니다. 전체 이력이 다운로드됩니다.
git clone git@github.com:team/ml-project.git
cd ml-project
2

브랜치 생성 (branch)

작업할 기능/실험을 위한 브랜치를 만들고 전환합니다.
# 브랜치 생성 + 전환 (한 번에)
git checkout -b feature/add-attention-layer

# 또는 (Git 2.23+)
git switch -c feature/add-attention-layer
3

변경사항 커밋 (commit)

코드를 수정하고, 의미 있는 단위로 커밋합니다.
# 변경 내용 확인
git status
git diff

# 스테이징 (커밋할 파일 선택)
git add src/model.py src/config.yaml

# 커밋 (Conventional Commits 형식)
git commit -m "feat: add multi-head attention layer to encoder"
4

원격에 푸시 (push)

로컬 커밋을 원격 저장소에 업로드합니다.
# 최초 푸시 (원격 브랜치 생성 + 업스트림 설정)
git push -u origin feature/add-attention-layer

# 이후 푸시
git push
5

Pull Request (PR) 생성

GitHub/GitLab에서 PR을 생성하여 코드 리뷰를 요청합니다.
# GitHub CLI로 PR 생성
gh pr create --title "feat: add multi-head attention layer" \
             --body "## 변경 사항\n- Encoder에 multi-head attention 추가\n- config에 num_heads 파라미터 추가"
6

머지 (merge)

코드 리뷰 후 main 브랜치에 머지합니다.
# main 브랜치로 전환
git checkout main

# 최신 변경사항 가져오기
git pull origin main

# 브랜치 머지
git merge feature/add-attention-layer

# 머지 완료 후 브랜치 삭제
git branch -d feature/add-attention-layer
git push origin --delete feature/add-attention-layer

브랜치 전략

전략브랜치 구조적합한 팀특징
Simplemain + feature/*1-3인 소규모간단하고 빠름, ML 실험에 적합
GitHub Flowmain + feature/* + PR3-10인PR 기반 리뷰, CI/CD 연동 용이
Git Flowmain + develop + feature/* + release/* + hotfix/*10인+ 대규모체계적이나 복잡, 릴리스 주기가 명확한 제품
Trunk-Basedmain + 매우 짧은 feature/*숙련된 팀짧은 브랜치 수명, 빈번한 머지, CI 필수
=== GitHub Flow (ML 팀 권장) ===

main ──────●──────●──────●──────●──────●──────
            \    /        \    /
feature/     ●──●          ●──●
attention    (PR + Review)  (PR + Review)
ML 프로젝트에서는 GitHub Flow가 가장 적합합니다. 실험 브랜치를 만들고, 결과가 좋으면 PR로 main에 머지합니다. Git Flow는 제품 릴리스가 필요한 MLOps 파이프라인에서 고려하세요.

커밋 품질

Conventional Commits

커밋 메시지에 일관된 형식을 부여하여, 변경 이력을 쉽게 파악할 수 있습니다.
<타입>(<범위>): <설명>

[본문]

[꼬리말]
타입설명예시
feat새 기능feat: add learning rate scheduler
fix버그 수정fix: resolve OOM in DataLoader with large batch
docs문서 변경docs: update training README with GPU setup
refactor리팩터링 (기능 변경 없음)refactor: extract data augmentation to separate module
test테스트 추가/수정test: add unit tests for tokenizer
chore빌드, 설정 등 유지보수chore: update PyTorch to 2.1.0
perf성능 개선perf: optimize batch collation with vectorized ops
style코드 스타일 (동작 변경 없음)style: apply black formatter to src/
ciCI/CD 설정 변경ci: add GPU test pipeline to GitHub Actions

원자적 커밋 원칙

하나의 커밋은 하나의 논리적 변경만 포함해야 합니다.
# 좋은 예: 각 변경을 별도 커밋으로
git add src/model.py
git commit -m "feat: add dropout layer to classifier head"

git add configs/training.yaml
git commit -m "chore: increase default batch size to 64"

git add tests/test_model.py
git commit -m "test: add output shape validation for classifier"

# 나쁜 예: 모든 변경을 한 커밋에
git add .
git commit -m "여러 가지 수정"
git add .이나 git add -A는 의도하지 않은 파일(데이터셋, 체크포인트, .env)까지 스테이징할 수 있습니다. 항상 git status로 확인하고, 파일을 명시적으로 지정하여 git add하세요.

.gitignore

Python + ML 프로젝트 .gitignore

# === Python ===
__pycache__/
*.py[cod]
*$py.class
*.so
*.egg-info/
dist/
build/
.eggs/

# === 가상환경 ===
.venv/
venv/
env/
.conda/

# === ML 산출물 ===
# 모델 체크포인트 (대용량)
*.pt
*.pth
*.ckpt
*.safetensors
*.bin
*.h5
*.pb

# 학습 로그와 출력
outputs/
runs/
logs/
wandb/
mlruns/
lightning_logs/

# === 데이터 ===
data/raw/
data/processed/
*.csv
*.tsv
*.parquet
*.arrow
*.jsonl
!data/.gitkeep

# === 환경변수 / 비밀값 ===
.env
.env.*
*.pem
*.key
secrets/

# === IDE 설정 ===
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store

# === Jupyter ===
.ipynb_checkpoints/
*.nbconvert.*

# === 기타 대용량 ===
*.zip
*.tar.gz
*.tar.bz2
*.7z
.gitignore에 추가하기 전에 이미 Git에 추적 중인 파일은 무시되지 않습니다. 이미 추적 중인 파일을 무시하려면 git rm --cached <파일>로 추적을 해제한 후 .gitignore에 추가하세요.

Git 명령어 테이블

기본 명령어

명령어설명사용 예시
git init새 저장소 초기화git init
git clone원격 저장소 복제git clone git@github.com:user/repo.git
git status작업 상태 확인git status
git add스테이징git add file.py
git commit커밋git commit -m "feat: add feature"
git log커밋 이력 조회git log --oneline --graph --all
git diff변경 내용 비교git diff, git diff --staged
git show커밋 상세 확인git show HEAD, git show abc1234

브랜치 명령어

명령어설명사용 예시
git branch브랜치 목록/생성git branch, git branch feature/x
git checkout브랜치 전환git checkout main
git switch브랜치 전환 (Git 2.23+)git switch main
git merge브랜치 머지git merge feature/x
git rebase커밋 이력 재배치git rebase main
git branch -d브랜치 삭제git branch -d feature/x

원격 명령어

명령어설명사용 예시
git remote원격 저장소 관리git remote -v
git fetch원격 변경사항 가져오기 (머지 안 함)git fetch origin
git pullfetch + mergegit pull origin main
git push로컬 커밋을 원격에 업로드git push origin feature/x
git push -u업스트림 설정 + 푸시git push -u origin feature/x

되돌리기 명령어

명령어설명영향 범위안전성
git restoreWorking Directory 파일 복원작업 디렉터리되돌릴 수 없음
git restore --staged스테이징 취소스테이징 영역안전
git reset --soft HEAD~1마지막 커밋 취소 (변경사항 유지)커밋만안전
git reset --mixed HEAD~1마지막 커밋 + 스테이징 취소커밋 + 스테이징안전
git reset --hard HEAD~1마지막 커밋 + 모든 변경사항 삭제전부위험
git revert커밋을 되돌리는 새 커밋 생성커밋 이력 유지매우 안전
git stash작업 중 변경사항 임시 저장작업 디렉터리안전
# 실수로 커밋한 대용량 파일 제거
git reset --soft HEAD~1      # 커밋 취소 (파일은 staged 상태로 유지)
git rm --cached large_model.pt  # 스테이징에서 제거
echo "*.pt" >> .gitignore    # .gitignore에 추가
git add .gitignore
git commit -m "chore: remove large model file and update gitignore"

# 작업 중 다른 브랜치로 긴급 전환
git stash                     # 현재 변경사항 임시 저장
git checkout hotfix/bug123    # 다른 브랜치로 전환
# ... 긴급 수정 ...
git checkout feature/my-work  # 원래 브랜치로 복귀
git stash pop                 # 임시 저장한 변경사항 복원

검사 명령어

명령어설명사용 예시
git blame줄별 마지막 수정자 확인git blame src/model.py
git bisect이진 탐색으로 버그 커밋 찾기git bisect start, git bisect good/bad
git reflogHEAD 이동 이력 (실수 복구용)git reflog

충돌 해결

충돌 발생 원인

두 브랜치가 같은 파일의 같은 부분을 서로 다르게 수정한 후 머지할 때 충돌이 발생합니다.
main:    learning_rate = 0.001
feature: learning_rate = 0.0001
→ 머지 시 충돌! (어떤 값을 선택해야 하는지 Git이 판단 불가)

충돌 해결 순서

1

충돌 상태 확인

git status
# "both modified:" 로 표시된 파일이 충돌 파일
2

충돌 파일 편집

충돌 파일을 열면 충돌 마커가 표시됩니다.
<<<<<<< HEAD
learning_rate = 0.001
=======
learning_rate = 0.0001
>>>>>>> feature/new-lr
원하는 내용으로 수정하고, 충돌 마커(<<<, ===, >>>)를 반드시 삭제합니다.
learning_rate = 0.0001  # feature 브랜치의 값 채택
3

해결 완료 후 커밋

git add src/config.py
git commit -m "fix: resolve merge conflict in learning rate config"
VS Code의 내장 Merge Editor를 사용하면 충돌을 시각적으로 해결할 수 있습니다. 충돌 파일을 열면 “Accept Current Change”, “Accept Incoming Change”, “Accept Both Changes” 버튼이 나타납니다.

ML 실험에서 Git 활용

실험 브랜치 전략

# 실험 브랜치 네이밍 규칙
git checkout -b exp/resnet50-cosine-lr
git checkout -b exp/vit-large-augmented
git checkout -b exp/bert-lora-rank8

# 실험 설정을 커밋에 기록
git commit -m "exp: ResNet50 with cosine LR schedule

Config:
- backbone: resnet50
- lr: 0.001 → 0 (cosine)
- epochs: 100
- batch_size: 64
- augmentation: RandAugment(2, 14)

Result:
- val_acc: 94.2% (epoch 87)
- val_loss: 0.231"

하이퍼파라미터 추적

# 설정 파일을 Git으로 관리하여 실험 재현성 확보
configs/
├── base.yaml           # 기본 설정 (Git 추적)
├── exp001_baseline.yaml # 실험별 설정 (Git 추적)
├── exp002_augmented.yaml
└── exp003_cosine_lr.yaml

# 실험 결과는 Git에 커밋하지 않음 (DVC 또는 MLflow로 관리)
outputs/               # .gitignore에 추가
├── exp001/
   ├── checkpoints/
   ├── logs/
   └── metrics.json

Git과 DVC/MLflow의 역할 분담

관리 대상GitDVCMLflow
소스 코드O--
설정 파일 (YAML, JSON)O-파라미터 로깅
데이터셋-O-
모델 체크포인트-O아티팩트 로깅
학습 메트릭 (loss, accuracy)--O
실험 비교커밋 이력파이프라인 비교UI 대시보드
# Git + DVC 연동 예시
# DVC로 대용량 데이터 관리 (실제 파일은 원격 스토리지에 저장)
dvc init
dvc add data/training_data.tar.gz
git add data/training_data.tar.gz.dvc data/.gitignore
git commit -m "data: add training dataset v1 via DVC"

# Git으로 코드 + DVC 메타데이터 관리
# DVC로 데이터 + 모델 아티팩트 관리
# MLflow로 실험 메트릭 + 하이퍼파라미터 관리
git rm --cached는 현재 상태에서만 제거합니다. 이력에서 완전히 지우려면 git filter-branch 또는 더 안전한 BFG Repo-Cleaner를 사용하세요. java -jar bfg.jar --strip-blobs-bigger-than 100M으로 100MB 이상 파일을 이력에서 제거할 수 있습니다. 이 작업은 이력을 재작성하므로, 팀원에게 알리고 force push가 필요합니다.
merge는 두 브랜치를 합치는 머지 커밋을 생성합니다. 이력에 분기와 합류가 보입니다. rebase는 현재 브랜치의 커밋을 대상 브랜치 끝에 재배치하여 직선적인 이력을 만듭니다. 팀에서는 git pull --rebase로 로컬 변경사항을 원격 위에 깔끔하게 재배치하는 것이 일반적입니다. 단, 이미 푸시한 커밋은 rebase하지 마세요 — 다른 팀원의 이력과 충돌합니다.
git reflog로 커밋 해시를 확인한 후, (1) 올바른 브랜치로 체리픽: git checkout correct-branch && git cherry-pick <hash>, (2) 잘못된 브랜치에서 제거: git checkout wrong-branch && git reset --hard HEAD~1. reflog는 30일간 모든 HEAD 이동을 기록하므로, 대부분의 실수를 복구할 수 있습니다.
이미 Git에 추적 중인 파일은 .gitignore가 무시됩니다. git rm --cached <파일>로 추적을 해제한 후 커밋하세요. 여러 파일을 한번에 처리하려면: git rm -r --cached .git add .git commit -m "chore: apply gitignore". 이 방법은 모든 파일의 추적을 해제했다가 .gitignore 규칙에 따라 다시 추가합니다.
(1) 설정 변경: 하이퍼파라미터, 데이터 전처리, 모델 구조 변경 시 커밋. (2) 코드 변경: 새로운 기능 추가, 리팩터링 시 커밋. (3) 실험 결과: 커밋 메시지 본문에 주요 메트릭을 기록. 체크포인트 파일 자체는 DVC/MLflow로 관리하고, Git에는 코드와 설정만 추적하세요. 이렇게 하면 특정 커밋으로 체크아웃하여 그 시점의 설정으로 실험을 재현할 수 있습니다.
Git LFS(Large File Storage)는 대용량 파일을 별도 스토리지에 저장하고, Git에는 포인터만 기록합니다. 100MB 이상의 바이너리 파일(모델, 데이터셋)이 반드시 Git으로 관리되어야 할 때 사용합니다. 하지만 ML 프로젝트에서는 DVC가 더 적합한 경우가 많습니다. DVC는 파이프라인 재현성까지 지원하고, S3/GCS 등 다양한 원격 스토리지를 백엔드로 사용할 수 있기 때문입니다.

체크리스트

  • Git의 스냅샷 기반 동작 원리를 설명할 수 있다
  • Working Directory, Staging Area, Repository의 역할을 구분할 수 있다
  • HEAD, 브랜치 포인터, 태그의 차이를 이해했다
  • git config로 사용자 정보와 SSH 키를 설정할 수 있다
  • clone → branch → commit → push → PR → merge 워크플로우를 수행할 수 있다
  • Conventional Commits 형식으로 커밋 메시지를 작성할 수 있다
  • ML 프로젝트에 적합한 .gitignore를 구성할 수 있다
  • merge conflict를 확인하고 해결할 수 있다
  • git stash, git reset, git revert를 상황에 맞게 사용할 수 있다
  • ML 실험에서 Git, DVC, MLflow의 역할 분담을 설명할 수 있다

다음 문서