Git 고급 기능

bisect, submodule, worktree, hooks, alias

Git의 고급 기능들을 소개한다. git bisect로 버그 커밋 찾기, submodule로 외부 저장소 관리, worktree로 동시 브랜치 작업, hooks로 자동화, alias로 명령어 단축까지 실무에서 유용한 기능들을 다룬다.

Engineering
Git
DevOps
저자

Kwangmin Kim

공개

2023년 05월 14일

이 글이 다루는 내용:

1 Git Bisect: 버그 커밋 찾기

git bisect이진 탐색을 사용하여 버그가 도입된 커밋을 빠르게 찾아낸다. 100개의 커밋 중에서도 7번의 확인만으로 원인 커밋을 찾을 수 있다.

1.1 기본 사용법

# 1. bisect 시작
git bisect start

# 2. 현재 (버그 있는) 커밋을 bad로 표시
git bisect bad
Bisecting: 30 revisions left to test after this (roughly 5 steps)
[m2a3b4c] feat: Add payment processing

Git이 bad/good 범위의 중간 커밋으로 자동 체크아웃한다. 30 revisions left, roughly 5 steps 로 남은 탐색 횟수를 알려준다.

# 3. 버그가 없던 과거 커밋을 good으로 표시
git bisect good v1.0.0
Bisecting: 14 revisions left to test after this (roughly 4 steps)
[x7y8z9a] refactor: Optimize database queries
# 4. 해당 커밋에서 버그 테스트 후 판정 반복
git bisect bad    # 또는 git bisect good
Bisecting: 7 revisions left to test after this (roughly 3 steps)
[n1o2p3q] feat: Update user authentication
# ... 반복 후 최종 결과
abc1234 is the first bad commit
commit abc1234
Author: 홍길동 <hong@example.com>
Date:   Mon Jan 15 14:00:00 2024 +0900

    feat: Add new payment logic

 src/payment.js | 23 +++++++++++++++++++++++

is the first bad commit 메시지가 나오면 버그가 처음 도입된 커밋을 찾은 것이다.

# 5. bisect 종료 (원래 브랜치로 복귀)
git bisect reset
Previous HEAD position was abc1234 feat: Add new payment logic
Switched to branch 'main'

1.2 자동 bisect

테스트 스크립트가 있다면 자동으로 bisect를 실행할 수 있다:

# 테스트 스크립트의 exit code로 판단
# exit 0 = good, exit 1 = bad
git bisect start HEAD v1.0.0
git bisect run python test_payment.py

2 Git Submodule: 외부 저장소 포함

Submodule은 Git 저장소 안에 다른 Git 저장소를 포함시키는 기능이다. 공통 라이브러리, 공유 컴포넌트 등을 관리할 때 사용한다.

2.1 서브모듈 추가

# 외부 저장소를 서브모듈로 추가
git submodule add https://github.com/org/shared-lib.git libs/shared-lib
Cloning into '/project/libs/shared-lib'...
remote: Enumerating objects: 156, done.
remote: Counting objects: 100% (156/156), done.
Receiving objects: 100% (156/156), 45.23 KiB | 2.14 MiB/s, done.

자동으로 shared-lib 를 클론하고 .gitmodules 파일을 생성한다.

2.2 서브모듈이 포함된 저장소 Clone

# 방법 1: clone 시 서브모듈도 함께
git clone --recurse-submodules https://github.com/username/project.git

# 방법 2: clone 후 서브모듈 초기화
git clone https://github.com/username/project.git
cd project
git submodule init
git submodule update
# 또는 한번에
git submodule update --init --recursive

2.3 서브모듈 업데이트

# 모든 서브모듈을 원격의 최신 커밋으로 업데이트
git submodule update --remote

# 특정 서브모듈만 업데이트
git submodule update --remote libs/shared-lib

# 변경사항 커밋
git add libs/shared-lib
git commit -m "chore: Update shared-lib to latest"

2.4 서브모듈 제거

# 1. 서브모듈 등록 해제
git submodule deinit libs/shared-lib

# 2. .git/modules에서 제거
git rm libs/shared-lib

# 3. 커밋
git commit -m "chore: Remove shared-lib submodule"
노트

Submodule은 강력하지만 관리가 복잡하다. 단순한 의존성 관리라면 패키지 매니저(npm, pip 등)를 사용하는 것이 더 적합할 수 있다.

3 Git Worktree: 동시 브랜치 작업

Worktree를 사용하면 하나의 Git 저장소에서 여러 브랜치를 동시에 다른 디렉토리에 열어놓고 작업할 수 있다. 브랜치 전환 없이 여러 브랜치를 동시에 작업할 때 유용하다.

3.1 기본 사용법

# 새 worktree 생성 (기존 브랜치)
git worktree add ../project-hotfix hotfix/critical-bug

# 새 worktree 생성 (새 브랜치 생성과 동시에)
git worktree add -b feature/new-ui ../project-new-ui

# worktree 목록 확인
git worktree list

/home/user/project abc1234 [main] /home/user/project-hotfix def5678 [hotfix/critical-bug] /home/user/project-new-ui ghi9012 [feature/new-ui]

각 항목은 `경로 / 해시 / [브랜치명]` 형식이다.

# worktree 제거
git worktree remove ../project-hotfix
성공 시 아무 출력도 없다.

# 사용하지 않는 worktree 정리
git worktree prune

3.2 활용 시나리오

# 메인 디렉토리에서 feature 작업 중
# 긴급 버그 수정이 필요할 때

# 1. 별도 디렉토리에 hotfix worktree 생성
git worktree add ../project-hotfix -b hotfix/bug main

# 2. hotfix 디렉토리에서 버그 수정
cd ../project-hotfix
# ... 버그 수정 ...
git add .
git commit -m "fix: Critical bug"
git push

# 3. 원래 디렉토리로 돌아가서 feature 작업 계속
cd ../project
# 기존 작업 상태 그대로 유지되어 있음
힌트

Worktree는 git stash의 대안이 될 수 있다. stash는 변경사항을 숨겼다가 꺼내야 하지만, worktree는 여러 브랜치를 동시에 열어둘 수 있어 컨텍스트 전환이 더 빠르다.

4 Git Hooks: 자동화

Git Hooks는 특정 Git 이벤트(커밋, 푸시 등) 발생 시 자동으로 스크립트를 실행하는 기능이다.

4.1 Hook 종류

4.1.1 클라이언트 측 Hook

Hook 실행 시점 용도
pre-commit 커밋 직전 린트, 포맷팅 검사
commit-msg 커밋 메시지 작성 후 메시지 형식 검증
pre-push push 직전 테스트 실행
post-commit 커밋 완료 후 알림 발송
post-merge merge 완료 후 의존성 설치

4.1.2 서버 측 Hook

Hook 실행 시점 용도
pre-receive push 수신 전 정책 검증
post-receive push 수신 후 배포 트리거

4.2 Hook 설정 방법

Hook 스크립트는 .git/hooks/ 디렉토리에 저장한다.

# pre-commit hook 예시: Python 코드 린트
# 파일: .git/hooks/pre-commit (실행 권한 필요)

#!/bin/bash
echo "Running linter..."

# Python 린트 실행
python -m flake8 --max-line-length=120
if [ $? -ne 0 ]; then
    echo "Lint errors found. Commit aborted."
    exit 1
fi

echo "Lint passed!"
exit 0
# 실행 권한 부여 (Linux/macOS)
chmod +x .git/hooks/pre-commit

4.3 pre-commit 프레임워크 (권장)

직접 hook 스크립트를 작성하는 대신, pre-commit 프레임워크를 사용하면 더 쉽게 관리할 수 있다.

# 설치
pip install pre-commit

프로젝트 루트에 .pre-commit-config.yaml 생성:

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.5.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files

  - repo: https://github.com/psf/black
    rev: 24.1.1
    hooks:
      - id: black

  - repo: https://github.com/pycqa/flake8
    rev: 7.0.0
    hooks:
      - id: flake8
# hook 설치 (팀원 모두 실행)
pre-commit install

# 이후 git commit 시 자동으로 검사 실행
힌트

.pre-commit-config.yaml은 저장소에 포함되므로 팀 전체가 동일한 검사를 적용받는다. .git/hooks/에 직접 넣는 방식보다 관리가 편하다.

5 Git Alias: 명령어 단축

자주 사용하는 긴 명령어를 짧게 줄일 수 있다.

5.1 별칭 설정

# 기본 별칭
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.sw switch

# 복합 명령어 별칭
git config --global alias.graph "log --oneline --graph --all --decorate"
git config --global alias.last "log -1 HEAD"
git config --global alias.unstage "restore --staged"
git config --global alias.amend "commit --amend --no-edit"

# 상태 요약
git config --global alias.ss "status -s"

5.2 사용 예시

git st           # git status
git co main      # git checkout main
git br -a        # git branch -a
git graph        # git log --oneline --graph --all --decorate
git last         # git log -1 HEAD
git unstage .    # git restore --staged .
git ss           # git status -s

5.3 별칭 확인 및 삭제

# 설정된 모든 별칭 확인
git config --global --get-regexp alias
alias.st status
alias.co checkout
alias.br branch
alias.graph log --oneline --graph --all --decorate
alias.last log -1 HEAD
alias.unstage restore --staged

6 Git Blame: 라인별 작성자 확인

특정 파일의 각 줄을 누가, 언제, 어떤 커밋에서 수정했는지 확인한다.

# 파일의 각 줄의 작성자 확인
git blame src/app.py
abc1234 (홍길동 2024-03-01 10:30:00 +0900  1) def main():
def5678 (김영희 2024-03-05 14:22:15 +0900  2)     print("Hello")
ghi9012 (홍길동 2024-03-10 09:15:45 +0900  3)     return True

커밋해시 (작성자 날짜 줄번호) 코드 형식이다. 어떤 줄이 언제 누구에 의해 수정됐는지 한눈에 파악할 수 있다.

7 Git Clean: 추적되지 않는 파일 삭제

# 삭제될 파일 미리 확인 (dry run)
git clean -nd

# 추적되지 않는 파일 삭제
git clean -fd

# 무시된 파일도 포함하여 삭제
git clean -fdx

# 대화형 모드
git clean -id
경고

git clean되돌릴 수 없다. 반드시 -n 옵션으로 먼저 확인하고 실행하자.

8 요약

기능 명령어 용도
Bisect git bisect start/bad/good 버그 커밋 이진 탐색
Submodule git submodule add/update 외부 저장소 포함
Worktree git worktree add/remove 동시 브랜치 작업
Hooks .git/hooks/ 또는 pre-commit 자동화
Alias git config alias.<name> 명령어 단축
Blame git blame <file> 라인별 작성자 확인
Clean git clean -fd 미추적 파일 삭제

Subscribe

Enjoy this blog? Get notified of new posts by email: