Git
git
- Git
Git
Commit message conventions
과거형, 진행형, 현재형
Git commit message를 작성할 때 과거형, 진행형, 현재형 중 뭐가 좋을까?
결론 : 현재형
근거
- 표준화
- Git 자체 명령어 및 행위가 모두 현재형으로 작성되어 있습니다. (ex. Pull request, Merge, Approve)
- 사용자 입장에서 이를 따라 Commit message를 작성할 경우 일관성을 띌 수 있습니다.
- 시간 독립성
- Git의 특성 상 과거에 작업한 Commit을 가져오는 일도 빈번합니다.
- 현재형의 Commit message인 경우, 과거 또는 현재에 작업한 이력을 적용하는 시점이 어느 때라도 ‘이 작업이 지금 반영된다‘라는 의미가 유지됩니다.
- 의미 전달의 능동성
- 과거형인 경우 ‘무슨 일이 일어났는지‘를 설명합니다.
- 현재형인 경우 ‘이 커밋이 무슨 일을 하는지’를 설명합니다.
웬만하면 현재형으로 작성하자.
ex) Feat: Separate API query scope between SuperAdmin and Admin
Commit type
- Feat : 새로운 기능을 추가
- Fix : 버그 수정
- Design : CSS 등 사용자 UI 디자인 변경
- !BREAKING CHANGE : 커다란 API 변경의 경우
- !HOTFIX : 급하게 치명적인 버그를 고쳐야하는 경우
- Style : 코드 포맷 변경, 세미 콜론 누락, 코드 수정이 없는 경우
- Refactor : 프로덕션 코드 리팩토링
- Comment : 필요한 주석 추가 및 변경
- Docs : 문서 수정
- Test : 테스트 코드, 리펙토링 테스트 코드 추가, Production Code 변경 없음
- Chore : 빌드/패키지 매니저/설정 업데이트, Production Code 변경 없음
- Rename : 파일 혹은 폴더명을 수정하거나 옮기는 작업만인 경우
- Remove : 파일을 삭제하는 작업만 수행한 경우
자주 쓰는 실전 설정
최초 글로벌 설정
git config --global user.name "your-name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
git config --global pull.rebase true
git config --global rebase.autoStash true
git config --global fetch.prune true
git config --global core.autocrlf input
추천 alias
git config --global alias.st "status -sb"
git config --global alias.lg "log --oneline --graph --decorate --all"
git config --global alias.co checkout
git config --global alias.sw switch
git config --global alias.br branch
git config --global alias.rb rebase
git config --global alias.cm "commit -m"
git config --global alias.unstage "restore --staged"
브랜치 운영
기본 흐름
- main 최신화
- feature 브랜치 생성
- 작은 단위로 commit
- push + PR
- merge 후 로컬 브랜치 정리
git switch main
git pull --rebase
git switch -c feature/login
# ... 작업 ...
git add .
git commit -m "Feat: Add login API"
git push -u origin feature/login
브랜치 정리
git branch -d feature/login
git fetch -p
Stage/Commit 고급 사용
부분 스테이징 (hunk 단위)
git add -p
직전 커밋 메시지/내용 수정
git commit --amend
커밋은 유지하고 index만 되돌리기
git reset --soft HEAD~1
Rebase / Cherry-pick / Revert / Reset
interactive rebase (커밋 정리)
git rebase -i HEAD~5
- squash/fixup: 커밋 합치기
- reword: 메시지 수정
- drop: 커밋 제거
특정 커밋만 가져오기
git cherry-pick <commit-hash>
공유 브랜치에서 안전한 되돌리기
git revert <commit-hash>
로컬 작업만 강하게 되돌리기 (주의)
git reset --hard <commit-hash>
충돌 해결 실전
rebase 중 충돌
# 충돌 해결 후
git add .
git rebase --continue
# 포기
git rebase --abort
merge 도구 사용
git mergetool
같은 충돌 반복 해결 자동화
git config --global rerere.enabled true
추적/디버깅에 강한 명령어
누가 이 줄을 바꿨는지
git blame path/to/file
파일 변경 히스토리 집중 보기
git log -- path/to/file
버그 유입 커밋 찾기
git bisect start
git bisect bad
git bisect good <known-good-hash>
# 테스트 반복 후
git bisect reset
잃어버린 커밋 복구
git reflog
git switch -c recovery <reflog-hash>
Stash 제대로 쓰기
# 현재 변경 임시 저장
git stash push -m "wip: login form"
# untracked 포함
git stash -u
# 목록/적용/삭제
git stash list
git stash apply stash@{0}
git stash drop stash@{0}
Git worktree
git worktree는 하나의 Git 저장소를 여러 작업 디렉토리로 동시에 체크아웃해서 쓰는 기능이다.
- 장점
- 브랜치 전환(stash) 없이 병렬 작업 가능
- hotfix / feature / release를 동시에 열어두기 쉬움
- CI 재현, 코드리뷰 대응, 긴급 패치 속도 향상
기본 개념
- 메인 저장소:
.git메타데이터를 가진 원본 디렉토리 - 워크트리: 같은 저장소를 참조하는 추가 작업 디렉토리
- 제약: 하나의 브랜치는 동시에 하나의 워크트리에서만 checkout 가능
자주 쓰는 명령어
# 1) 현재 연결된 worktree 목록 확인
git worktree list
# 2) 새 worktree 생성 (기존 브랜치)
git worktree add ../repo-feature feature/login
# 3) 새 worktree 생성 + 새 브랜치 생성 (-b)
git worktree add -b feature/payment ../repo-payment main
# 4) 새 worktree 생성 + 원격 브랜치 tracking
git worktree add --track -b feature/api ../repo-api origin/main
# 5) worktree 제거
git worktree remove ../repo-feature
# 6) 끊어진(worktree 폴더를 수동 삭제한) 메타데이터 정리
git worktree prune
실전 워크플로우
1) 기능 개발 분리
# 메인 저장소 위치: ~/workspace/my-repo
cd ~/workspace/my-repo
# 로그인 기능 작업용 worktree 생성
git worktree add -b feature/login ../my-repo-login main
# 결제 기능 작업용 worktree 생성
git worktree add -b feature/payment ../my-repo-payment main
my-repo-login,my-repo-payment폴더를 각각 IDE로 열어 독립 개발- 각 워크트리에서 별도 commit / push / PR 수행
2) 긴급 hotfix 병행
# 운영 브랜치 기준으로 hotfix worktree 생성
git worktree add -b hotfix/critical ../my-repo-hotfix release
- 기존 feature 작업을 건드리지 않고 즉시 패치 가능
브랜치/삭제 관련 주의점
- 워크트리가 붙어 있는 브랜치는 바로 삭제 안 됨
- 먼저 워크트리 제거 후 브랜치 삭제
git worktree remove ../my-repo-login
git branch -d feature/login
강제 삭제가 필요한 경우:
git worktree remove --force ../my-repo-login
git branch -D feature/login
이동/락(lock)
# worktree 경로 이동 (Git 메타데이터까지 같이 업데이트)
git worktree move ../my-repo-payment ../my-repo-payment-v2
# 실수 삭제 방지를 위한 잠금
git worktree lock ../my-repo-hotfix
# 잠금 해제
git worktree unlock ../my-repo-hotfix
장애 복구 팁
워크트리 폴더를 Finder/터미널에서 그냥 지웠다면:
git worktree prune
worktree 상태가 꼬였을 때 점검 순서:
git worktree list로 참조 경로 확인- 실제 디렉토리 존재 여부 확인
- 없는 경로 정리:
git worktree prune - 필요 시 다시 생성:
git worktree add ...
팀 운영 권장 규칙
- worktree 디렉토리는 저장소 옆에 규칙적으로 생성
- 예:
../my-repo-feature-xxx,../my-repo-hotfix-yyy
- 예:
- 브랜치명과 디렉토리명을 최대한 맞춘다
- 작업 종료 시 반드시
worktree remove로 정리 - 장기 방치 방지를 위해 주기적으로
git worktree list점검
원격/푸시 실수 방지
upstream 지정
git push -u origin feature/login
강제 푸시는 --force-with-lease
git push --force-with-lease
--force보다 안전하다. (원격이 예상과 다르면 푸시 거부)
원격 브랜치 정리
git fetch -p
태그/릴리즈
# annotated tag
git tag -a v1.2.0 -m "release v1.2.0"
# 태그 푸시
git push origin v1.2.0
# 전체 태그 푸시
git push origin --tags
파일/라인엔딩/대용량 관리
.gitignore 적용 누락 시
git rm -r --cached .
git add .
git commit -m "Chore: Re-apply .gitignore"
대용량 파일은 Git LFS 검토
- 바이너리/모델 파일/대형 아카이브를 일반 Git에 계속 쌓지 않는다.
- 필요시 Git LFS 사용.
팀 규칙 추천 (짧고 강하게)
- 커밋은 작고 의미 있게
- main에 직접 push 금지
- PR은 1개의 목적만 담기
- 리뷰 전
rebase로 히스토리 정리 - 머지 후 브랜치/워크트리 즉시 정리
Error
credential lock
fatal: unable to get credential storage lock in 1000 ms: File exists
해결 순서:
- 동시에 실행 중인 Git 프로세스 종료
- 잠금 파일 제거 (
~/.git-credential*계열 확인) - 필요시 터미널 재시작 후 재시도
push rejected (fetch first)
! [rejected] main -> main (fetch first)
git pull --rebase origin main
git push
detached HEAD
git switch -c fix/detached-head
현재 HEAD 상태를 브랜치로 고정한 뒤 작업 이어가면 된다.