인프라 팀에서 배포 후 문제가 생겼습니다. 어젯밤 누군가 main 브랜치에 직접 push한 커밋이 있었고, 오늘 오전 배포에서 그 코드가 올라갔습니다. 롤백 요청이 왔는데 팀원들은 "revert해야 하나 reset해야 하나"로 논쟁 중입니다. 릴리즈 태그도 없어서 "정확히 어느 버전까지 돌아가야 하나"도 불분명합니다.
이 모듈은 그런 상황에서 당황하지 않도록, Git을 형상관리 도구로 제대로 쓰는 방법을 다룹니다. 브랜치 전략, 태그 릴리즈, 안전한 롤백 절차를 실무 중심으로 정리합니다.
- 1GitFlow 브랜치 전략(main/develop/feature/release/hotfix)의 흐름을 설명할 수 있다
- 2git tag로 릴리즈 기준점을 만들고 배포 이력을 추적할 수 있다
- 3커밋 메시지에 이슈 번호를 포함해 GitLab에서 이슈-커밋 연결을 활용할 수 있다
- 4긴급 hotfix 절차(main merge → develop merge)를 순서대로 실행할 수 있다
- 5잘못된 커밋에 git revert를 안전하게 적용하고 reset과의 차이를 설명할 수 있다
브랜치 전략 — GitFlow
GitFlow 브랜치 구조
브랜치 전략은 팀이 코드를 어떻게 나누고 합치는가의 규칙입니다. 규칙이 없으면 누가 어디에 무엇을 push했는지 파악이 어렵고, 긴급 수정이 필요할 때 경로가 없어 혼란이 생깁니다.

운영 장애가 났습니다. 누군가 main에 직접 push한 커밋이 테스트 없이 배포됐고, 롤백하려니 "어느 커밋으로 돌아가야 하나"부터 막힙니다. 릴리즈 태그도 없고, 누가 무엇을 바꿨는지 추적할 방법이 없습니다. 브랜치 전략이 없는 팀은 긴급 상황에서 이렇게 무너집니다. 규칙 없이 모두가 한 브랜치에 push하면, 운영 코드와 개발 코드가 뒤섞이고 장애 원인을 찾는 데 배포 복구보다 더 많은 시간이 걸립니다. GitFlow는 소규모~중규모 팀에서 검증된 전략입니다. 브랜치별 역할이 명확하게 분리됩니다.
main ─────────────────────────────────────────── (운영 배포 기준)
│ ↑ release/1.2 merge ↑ hotfix/login-bug merge
│
develop ──────────────────────────────────────── (통합 개발 기준)
│ ↑ feature/login merge ↑ feature/dashboard merge
│
feature/login ─────── (기능 개발)
feature/dashboard ─── (기능 개발)
브랜치 역할 요약:
| 브랜치 | 역할 | 직접 push 여부 |
|---|---|---|
main | 운영 배포 기준. 항상 배포 가능 상태 | 금지 (MR only) |
develop | 다음 릴리즈 통합 브랜치 | 금지 (MR only) |
feature/* | 기능 단위 개발 | 개인 작업 가능 |
release/* | 릴리즈 준비 (QA, 버그픽스) | 제한적 |
hotfix/* | 운영 긴급 수정 | main에서 분기 |
# feature 브랜치 생성 및 작업
git checkout develop
git pull origin develop
git checkout -b feature/user-logout
# 작업 후 커밋
git add .
git commit -m "feat: 사용자 로그아웃 기능 구현 (#45)"
# develop으로 MR(Merge Request) 요청
git push origin feature/user-logout
# GitLab에서 develop 대상 MR 생성
Trunk-Based Development — GitFlow의 대안
팀 규모가 작거나 배포 주기가 짧은 경우, 더 단순한 전략이 유리할 수 있습니다.
| 비교 항목 | GitFlow | Trunk-Based |
|---|---|---|
| 브랜치 수 | 많음 (5종) | 적음 (main + 단기 feature) |
| 릴리즈 주기 | 주/월 단위 | 수시(하루 여러 번 가능) |
| 팀 규모 | 중~대규모 | 소~중규모 |
| 적합한 상황 | 명확한 버전 관리 필요 | CI/CD 자동화가 잘 된 팀 |
이 모듈에서는 인프라 운영 팀에서 더 자주 보이는 GitFlow를 기준으로 다룹니다.

태그 기반 릴리즈
git tag 로 배포 기준점 만들기
배포 기준점이 없으면 "어제 배포본으로 롤백해줘"라는 요청을 받았을 때 정확히 어느 커밋인지 찾기가 어렵습니다. git tag는 특정 커밋에 이름을 붙이는 방법입니다. 한 번 붙이면 브랜치와 달리 이동하지 않습니다.
# annotated tag 생성 (메시지 포함, 배포 이력에 남김)
git tag -a v1.2.0 -m "Release v1.2.0 — 로그아웃 기능 추가, 성능 개선"
# 원격 저장소에 push
git push origin v1.2.0
# 전체 태그 목록 확인
git tag -l
# 특정 버전 두 태그 사이의 커밋 목록
git log --oneline v1.1.0..v1.2.0
a3f9c21 feat: 사용자 로그아웃 기능 구현 (#45)
b82e1d3 fix: 세션 만료 시 리다이렉트 오류 수정 (#43)
c11a027 perf: 쿼리 캐시 레이어 추가 (#40)
배포 이력 추적 루틴:
# 가장 최근 태그 확인
git describe --tags --abbrev=0
# 특정 커밋이 어느 태그 기준인지 확인
git describe --tags a3f9c21
# 날짜 기준 배포 이력
git log --oneline --since="2026-01-01" --until="2026-06-01" --decorate | grep "tag:"
실습
태그 생성은 현재 브랜치의 최신 커밋에 붙습니다. main 브랜치에서 실행해야 운영 기준점으로 사용할 수 있습니다. 먼저 main 브랜치에 있는지 확인합니다.
# main 브랜치 확인
git branch --show-current
# 또는
git status | head -1
# main이 아니라면 이동
git checkout main
git pull origin main
# 태그 생성 및 push
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0
git tag -a v1.0.0 -m 'Release v1.0.0' && git push origin v1.0.0- git tag -l 에 v1.0.0 이 보이는가
- git show v1.0.0 에서 태그 메시지와 커밋 정보가 함께 출력되는가
- git push origin v1.0.0 이후 GitLab 저장소 Tags 탭에서 확인 가능한가
- git log --oneline --decorate | head -5 에서 HEAD -> main, tag: v1.0.0 이 같은 커밋에 표시되는가
두 태그 사이의 변경 내역을 확인합니다. 릴리즈 노트 작성이나 롤백 범위 파악에 사용합니다. 이전 태그(v0.9.0)가 없는 경우 첫 커밋부터 확인하려면 git log --oneline v1.0.0을 씁니다.
# 이전 릴리즈 이후 커밋 목록
git log --oneline v0.9.0..v1.0.0
# 변경된 파일 목록
git diff --name-only v0.9.0..v1.0.0
# 작성자별 기여 요약
git shortlog v0.9.0..v1.0.0
a3f9c21 feat: 사용자 로그아웃 기능 구현 (#45)
b82e1d3 fix: 세션 만료 시 리다이렉트 오류 수정 (#43)
c11a027 perf: 쿼리 캐시 레이어 추가 (#40)
git log --oneline v0.9.0..v1.0.0- 두 태그 사이의 커밋 목록이 예상한 기능/수정 내역과 일치하는가
- 커밋 메시지에 feat/fix/perf 같은 타입 prefix와 이슈 번호(#N)가 포함돼 있는가
- git diff --name-only 로 변경 파일 목록이 릴리즈 범위와 일치하는가
이슈-커밋 연결
커밋 메시지 컨벤션과 이슈 연결
커밋 메시지를 일관된 형식으로 작성하면, 나중에 "이 변경이 왜 생겼나"를 추적하기 쉬워집니다. GitLab은 커밋 메시지의 #이슈번호를 자동으로 해당 이슈와 연결합니다.
# 커밋 메시지 형식 권장
# <type>: <요약> (#이슈번호)
#
# type 종류:
# feat — 새 기능
# fix — 버그 수정
# docs — 문서
# refac — 리팩터링
# chore — 빌드/배포/설정 변경
# 예시
git commit -m "fix: 로그인 후 세션 쿠키 누락 수정 (#78)"
git commit -m "feat: Prometheus 메트릭 엔드포인트 추가 (#82)"
git commit -m "chore: application-prod.yml 로그 레벨 WARN으로 변경"
# 특정 이슈 번호가 언급된 커밋 찾기
git log --oneline --all | grep "#78"
# 최근 30개 커밋 확인
git log --oneline -30
# 특정 작성자 커밋만 확인
git log --oneline --author="minjun" --since="1 week ago"
# 특정 파일이 언제 마지막으로 변경됐는지
git log --oneline -5 -- src/main/resources/application-prod.yml
트러블슈팅
상황: 장애를 일으키는 커밋이 main에 merge됐고, 빠르게 되돌려야 합니다. git revert와 git reset 중 어느 것을 써야 하는지 판단 기준이 핵심입니다.
# 문제 커밋 SHA 확인
git log --oneline main | head -10
# 예: d9a3f1c feat: 캐시 로직 변경 (#91) ← 이 커밋이 문제
# 방법 1: git revert (공유 브랜치에서 항상 이 방법 사용)
# 문제 커밋을 취소하는 새 커밋을 만든다 — 이력 보존
git revert d9a3f1c
# 에디터가 열리면 커밋 메시지 확인 후 저장
git push origin main
# 방법 2: git reset --hard (주의: 공유 브랜치에서 사용 금지)
# 이 방법은 혼자 쓰는 feature 브랜치에서만
git reset --hard d9a3f1c~1 # 해당 커밋 이전으로 되돌림
# force push 필요 → 다른 팀원 이력 꼬임 발생 가능
판단 기준:
| 상황 | 사용할 명령 | 이유 |
|---|---|---|
| main/develop 등 공유 브랜치 | git revert | 이력 보존, force push 불필요 |
| 혼자 쓰는 feature 브랜치 | git reset 가능 | 아직 다른 사람이 pull하지 않음 |
| 이미 force push한 상황 | 팀에 알리고 revert | 이력 복구 시도보다 revert가 안전 |
원인: feature 브랜치와 develop 브랜치가 동일한 파일의 같은 부분을 각자 수정했습니다. Git이 자동으로 합칠 수 없어 충돌 마커를 삽입하고 멈춥니다.
# 충돌 파일 목록 확인
git status | grep "both modified"
# 충돌 마커 확인 (파일 안에 삽입됨)
grep -n "<<<<<<" src/main/resources/application.yml
# 충돌 마커 해석:
# <<<<<<< HEAD ← 현재 브랜치(develop)의 내용
# spring.datasource.url=jdbc:mysql://develop-db:3306/mydb
# =======
# spring.datasource.url=jdbc:mysql://localhost:3306/mydb_dev
# >>>>>>> feature/new-db-config ← merge하려는 브랜치 내용
# 직접 편집해서 올바른 내용만 남김 (마커 줄 포함 삭제)
vi src/main/resources/application.yml
# 수정 후 해결 완료 표시
git add src/main/resources/application.yml
# merge 완료
git commit
# (merge 커밋 메시지가 자동으로 채워짐)
# 충돌이 많으면 GUI 도구 활용
git mergetool # vimdiff, VS Code 등 설정에 따라 실행
충돌 예방 습관:
- feature 브랜치 작업이 길어지면 주기적으로
git merge develop으로 최신화 - 설정 파일 같이 충돌 잦은 파일은 MR 전 팀에 알리고 작업
실제 업무에서 이 지식이 쓰이는 상황:
인프라/운영 엔지니어에게 형상관리가 실질적으로 필요한 세 장면입니다.
1. 긴급 핫픽스 절차 (운영 버그 발생 시):
# main 기반으로 hotfix 브랜치 생성
git checkout main
git pull origin main
git checkout -b hotfix/session-null-pointer
# 수정 후 커밋
git add .
git commit -m "fix: 세션 null 시 NPE 수정 (#101)"
# main에 merge (운영 배포)
git checkout main
git merge hotfix/session-null-pointer
git tag -a v1.2.1 -m "Hotfix v1.2.1 — 세션 NPE 긴급 수정"
git push origin main
git push origin v1.2.1
# develop에도 반영 (재발 방지)
git checkout develop
git merge hotfix/session-null-pointer
git push origin develop
# hotfix 브랜치 삭제
git branch -d hotfix/session-null-pointer
git push origin --delete hotfix/session-null-pointer
2. 배포 이력 추적:
# "3주 전 배포본으로 돌아가야 한다" 요청이 오면
git log --oneline --decorate | grep "tag: v"
# 릴리즈 태그가 있어야 정확한 기준점으로 배포 가능
# 특정 날짜 이전 마지막 태그 확인
git log --tags --simplify-by-decoration --pretty="format:%d %ai" | grep "v1\." | head -5
3. 설정 파일 변경 추적: 운영 서버 설정이 언제, 누가, 왜 바뀌었는지 조회합니다.
git log --oneline --follow -- config/application-prod.yml
git show <커밋SHA>:config/application-prod.yml
형상관리가 잘 된 팀은 장애 발생 시 "어떤 버전에서 문제가 생겼나"를 5분 안에 파악합니다. 다음 모듈에서는 이 코드를 실제 배포 산출물로 만드는 빌드 도구 실무를 다룹니다.