콘텐츠로 이동

버전 관리 — Git으로 협업하기

왜 버전 관리가 필요한가?

혼자 개발할 때도, 팀으로 개발할 때도 이런 상황이 생깁니다.

"어제 코드로 돌아가고 싶어."
"누가 이 코드를 바꿨지?"
"A가 기능 추가하는 동안 B가 버그를 고치려면?"
"테스트 중에 실수로 파일을 지워버렸어."

Git은 이 모든 문제를 해결하는 버전 관리 시스템입니다.

Git 기본 개념

저장소 (Repository)

프로젝트의 전체 변경 이력을 담는 공간입니다.

로컬 저장소:  내 컴퓨터에 있는 저장소
원격 저장소:  GitHub 같은 서버에 있는 저장소

커밋 (Commit)

특정 시점의 코드 상태를 저장하는 행위입니다.

커밋 1: "프로젝트 초기화"
커밋 2: "로그인 기능 추가"
커밋 3: "버그 수정: 빈 제목 허용 오류"
커밋 4: "테스트 코드 추가"

각 커밋에는 누가, 언제, 무엇을 바꿨는지 기록됩니다.

기본 명령어

저장소 설정

# 현재 디렉토리를 Git 저장소로 초기화
git init

# 원격 저장소(GitHub) 연결
git remote add origin https://github.com/username/repo.git

변경사항 저장

# 현재 상태 확인
git status

# 변경된 파일 확인
git diff

# 파일 스테이징 (커밋할 파일 선택)
git add main.py
git add .          # 모든 변경 파일

# 커밋 (메시지와 함께 저장)
git commit -m "로그인 API 구현"

# 원격 저장소에 올리기
git push origin main

이력 확인

# 커밋 이력 보기
git log
git log --oneline   # 한 줄로 요약

# 특정 파일의 변경 이력
git log main.py

# 누가 이 줄을 바꿨는지
git blame main.py

되돌리기

# 마지막 커밋 이후 변경사항 취소 (파일 복원)
git restore main.py

# 특정 커밋 시점으로 파일 복원
git checkout abc1234 -- main.py

# 커밋을 되돌리는 새 커밋 생성 (안전)
git revert abc1234

브랜치 (Branch) — 병렬 작업의 핵심

브랜치는 코드의 분기점입니다.
메인 코드를 건드리지 않고 새 기능을 개발할 수 있습니다.

main  ──●──●──●──────────────●──
               \            /
feature/login   ●──●──●──●
# 브랜치 목록 확인
git branch

# 새 브랜치 생성 + 이동
git checkout -b feature/login

# 또는 (최신 방식)
git switch -c feature/login

# 브랜치 이동
git switch main

# 브랜치 삭제
git branch -d feature/login

팀 협업 워크플로우

GitHub Flow (가장 단순)

1. main 브랜치에서 새 브랜치 생성
   git switch -c feature/my-feature

2. 변경사항 커밋
   git add .
   git commit -m "새 기능 추가"

3. 원격 저장소에 올리기
   git push origin feature/my-feature

4. GitHub에서 Pull Request(PR) 생성
   → 팀원이 코드 리뷰

5. 승인 후 main에 병합 (Merge)

6. 로컬에서 최신 main 받기
   git switch main
   git pull origin main

Pull Request (PR) / Merge Request (MR)

PR은 "이 브랜치를 main에 합쳐도 되나요?" 하고 팀에 묻는 과정입니다.

PR에서 확인하는 것:
- 코드가 올바르게 동작하는가
- 코드 품질이 기준에 맞는가
- 테스트가 통과하는가

충돌 (Conflict) 해결

같은 파일의 같은 부분을 두 사람이 동시에 수정하면 충돌이 생깁니다.

# Git이 표시하는 충돌 내용
<<<<<<< HEAD
def greet(name):
    return f"안녕, {name}"
=======
def greet(name):
    return f"Hello, {name}!"
>>>>>>> feature/english
<<<<<<< HEAD      : 내 브랜치의 내용
=======           : 구분선
>>>>>>> feature/  : 합치려는 브랜치의 내용

해결 방법: 두 코드 중 원하는 버전을 선택하고 표시 기호를 제거합니다.

# 충돌 해결 후
def greet(name):
    return f"안녕, {name}!"  # 두 내용을 합치거나 하나를 선택
# 해결 후 커밋
git add main.py
git commit -m "merge conflict 해결"

.gitignore — 추적하지 않을 파일

# .gitignore
.env              ← 환경 변수 (비밀 키 포함)
*.db              ← 데이터베이스 파일
__pycache__/      ← Python 캐시
*.pyc
node_modules/     ← JavaScript 패키지
.DS_Store         ← macOS 시스템 파일

.gitignore에 포함된 파일은 git status에 나타나지 않고, 커밋에 포함되지 않습니다.

좋은 커밋 메시지 작성법

나쁜 예:
  fix
  수정
  asdfasdf

좋은 예:
  feat: JWT 인증 기능 추가
  fix: 빈 제목으로 todo 생성 시 500 오류 수정
  refactor: get_db() 함수 중복 제거
  docs: API 엔드포인트 목록 문서화
타입 접두사 (선택):
  feat:     새 기능
  fix:      버그 수정
  refactor: 기능 변경 없는 코드 개선
  docs:     문서만 수정
  test:     테스트 관련
  chore:    빌드, 설정 등 기타

자주 쓰는 명령어 한눈에 보기

git status                    # 현재 상태
git add .                     # 전체 스테이징
git commit -m "메시지"        # 커밋
git push origin main          # 올리기
git pull origin main          # 받기
git switch -c feature/xxx     # 새 브랜치
git switch main               # 브랜치 이동
git log --oneline             # 이력 보기
git diff                      # 변경사항 보기

실습 미션

미션 1: 기본 흐름

1. 새 디렉토리에 git init 하세요.
2. main.py 파일을 만들고 커밋하세요.
3. main.py를 수정하고 git diff로 차이를 확인하세요.
4. 두 번째 커밋을 만드세요.
5. git log --oneline으로 이력을 확인하세요.

미션 2: 브랜치 실습

1. feature/hello 브랜치를 만드세요.
2. 해당 브랜치에서 greet() 함수를 추가하고 커밋하세요.
3. main 브랜치로 돌아와 다른 수정을 커밋하세요.
4. feature/hello를 main에 병합(merge)하세요.

미션 3: GitHub 연동

1. GitHub에서 새 저장소를 만드세요.
2. 로컬 저장소와 연결하세요.
3. push해서 코드를 올리세요.
4. GitHub에서 커밋 이력을 확인하세요.

미션 4 (심화): 충돌 해결

같은 파일을 두 브랜치에서 동시에 수정하고
merge 시 충돌을 의도적으로 만들어 직접 해결해 보세요.

핵심 요약

개념 설명
저장소 프로젝트의 전체 변경 이력
커밋 특정 시점의 코드 스냅샷
브랜치 독립적인 작업 공간
merge 두 브랜치를 하나로 합치기
PR 코드 리뷰 후 main에 병합 요청
.gitignore Git이 추적하지 않을 파일 목록
충돌 같은 부분을 두 브랜치가 다르게 수정

코드보다 커밋을 먼저 생각하세요.
"이 변경이 왜 필요한가?"가 커밋 메시지에 담겨야 합니다.