18. 고급 명령 모음 — 한 단계 위로

🎯 이 장의 목표
  • 특정 커밋만 골라 가져오는 cherry-pick을 익힌다
  • git log를 자유자재로 다듬어 본다
  • detached HEAD에서 안전하게 실험한다
  • squash로 커밋을 정리하고, GC·develop 워크플로우를 이해한다
💡 팁
앞서 reset/revert/reflog/stash(10·7장)는 다뤘습니다. 이 장은 거기에 더해 실무에서 자주 만나는 나머지 고급 기법을 모았습니다.

18.1 git log 자유자재로 보기

4장에서 기본 git log를 배웠습니다. 여기서는 실무에서 쓰는 강력한 옵션들을 정리합니다.

BASH
git log --oneline                  # 한 줄 요약
git log --oneline --graph --all    # 모든 브랜치를 그래프로
git log --stat                     # 커밋별 변경 파일 통계
git log -p                         # 각 커밋의 실제 변경(diff)
git log -3                         # 최근 3개만

필터링

BASH
git log --author="Gildong"         # 특정 작성자
git log --grep="bug"               # 메시지에 'bug' 포함
git log --since="2 weeks ago"      # 기간
git log --no-merges                # 병합 커밋 제외
git log -- path/to/file.js         # 특정 파일의 이력만

예쁘게 포맷팅 — --pretty

BASH
git log --pretty=format:"%h %an %s"
CODE
a1b2c3d Gildong  Add login feature
9f8e7d6 Younghee Fix typo
플레이스홀더의미
%h짧은 해시
%an작성자 이름
%ar상대 시간 (3 days ago)
%s커밋 메시지 제목

git shortlog — 작성자별 요약

BASH
git shortlog -sn        # 작성자별 커밋 수 (기여도 한눈에)
CODE
   42  Gildong
   17  Younghee

나만의 별칭 만들기 — git lg

긴 옵션을 매번 치기 번거로우니 별칭으로 등록합니다.

BASH
git config --global alias.lg "log --oneline --graph --all --decorate"

이후 git lg만 치면 됩니다. (강좌에서 자주 등장하는 git lg가 바로 이런 사용자 별칭입니다.)

18.2 cherry-pick — 특정 커밋만 골라오기

cherry-pick다른 브랜치의 커밋 하나(또는 몇 개)만 콕 집어 현재 브랜치에 복사합니다. 체리만 골라 따는 것처럼요.

gitGraph
    commit id: "X"
    commit id: "Y"
    branch feature
    checkout feature
    commit id: "A"
    commit id: "B"
    commit id: "C (이것만 필요!)" type: HIGHLIGHT
    checkout main
    cherry-pick id: "C (이것만 필요!)"
feature의 커밋 C만 콕 집어 main에 복사합니다. main에는 같은 내용이 새 해시(C')로 들어갑니다.
BASH
git switch main
git cherry-pick a1b2c3d           # 그 커밋의 변경을 현재 브랜치에 적용

# 여러 개
git cherry-pick a1b2c3d 9f8e7d6

# 범위
git cherry-pick a1b2c3d..9f8e7d6
💡 팁
언제 쓸까? "feature 브랜치에서 만든 버그 수정 커밋 하나를, 브랜치 전체 병합 없이 급히 main(또는 릴리스 브랜치)에도 반영"하고 싶을 때. 핫픽스 전파에 자주 쓰입니다.

충돌이 나면 병합처럼 해결한 뒤 이어갑니다.

BASH
# 충돌 해결 후
git add .
git cherry-pick --continue

# 취소
git cherry-pick --abort
⚠️ 흔한 실수
cherry-pick은 커밋을 복제(다른 해시로)합니다. 같은 변경이 두 브랜치에 중복으로 들어가니, 나중에 그 두 브랜치를 병합할 때 혼란을 줄 수 있습니다. 남용하지 말고 꼭 필요할 때만.

18.3 amend — 마지막 커밋 고치기

4장에서 잠깐 봤지만, 자주 쓰니 정리합니다. --amend마지막 커밋을 새 커밋으로 교체합니다.

BASH
# 메시지만 고치기
git commit --amend -m "올바른 메시지"

# 빠뜨린 파일을 마지막 커밋에 추가
git add forgotten-file.js
git commit --amend --no-edit       # 메시지는 그대로 두고 파일만 추가
⚠️ 흔한 실수
황금률 반복: amend는 해시를 바꿉니다. 이미 push한 커밋에는 쓰지 마세요(9장 리베이스 황금률과 같은 이유). 로컬에만 있는 마지막 커밋을 다듬을 때만 사용합니다.

18.4 squash — 여러 커밋을 하나로

지저분한 커밋(WIP, 오타, 다시 수정...)을 의미 있는 하나로 합치는 것이 squash입니다. 두 가지 방법이 있습니다.

방법 A — 대화형 리베이스 (로컬, 9장 복습)

BASH
git rebase -i HEAD~3
CODE
pick a1b2c3d Add login form
squash b2c3d4e WIP
squash c3d4e5f fix typo

squash(또는 fixup)로 바꾸면 3개가 1개로 합쳐집니다.

방법 B — GitHub PR에서 Squash and merge (16장 복습)

PR 병합 시 "Squash and merge"를 고르면, 브랜치의 모든 커밋이 main에는 하나로 들어갑니다. 로컬에서 따로 정리할 필요 없이 GitHub이 처리해주므로 팀에서 가장 흔히 씁니다.

💡 팁
로컬 squash vs PR squash: 혼자 다듬을 땐 대화형 리베이스, 팀 협업에선 PR의 Squash and merge. 둘 다 결과는 "깔끔한 단일 커밋"입니다.

18.5 detached HEAD — 분리된 머리 상태

6장에서 잠깐 봤던 detached HEAD를 제대로 다룹니다. 브랜치가 아니라 특정 커밋·태그에 직접 체크아웃하면 이 상태가 됩니다.

BASH
git checkout a1b2c3d        # 또는 git switch --detach a1b2c3d
CODE
You are in 'detached HEAD' state...
flowchart LR
    subgraph N["정상 상태"]
        direction LR
        H1(["🔖 HEAD"]) -.-> M1(["🏷️ main"]) -.-> C1["커밋"]
    end
    subgraph D["detached HEAD 상태"]
        direction LR
        H2(["🔖 HEAD"]) -.->|"브랜치를 거치지 않고<br/>커밋을 직접 가리킴"| C2["커밋"]
    end
    classDef head fill:#fde68a,stroke:#d97706,color:#92400e
    classDef ptr fill:#fed7aa,stroke:#ea580c,color:#9a3412
    classDef commit fill:#dcfce7,stroke:#16a34a,color:#166534
    class H1,H2 head
    class M1 ptr
    class C1,C2 commit

여기서 실험 커밋을 하면?

detached 상태에서도 커밋할 수 있습니다. 하지만 그 커밋은 어느 브랜치에도 연결되지 않습니다.

BASH
# detached 상태에서 실험
echo "experiment" > test.txt
git add test.txt
git commit -m "Experimental change"     # 커밋되지만 브랜치 없음!

다른 곳으로 이동하면 이 커밋은 "미아"가 되어, 나중에 GC(18.6)로 삭제될 수 있습니다.

실험 결과를 살리려면 — 새 브랜치로 안착

BASH
# 실험이 마음에 들면, 그 자리에서 브랜치를 만들어 보존
git switch -c experiment-branch

이러면 방금 한 실험 커밋이 experiment-branch에 안전하게 담깁니다.

💡 팁
detached HEAD는 "과거 시점을 잠깐 둘러보거나, 거기서 가지를 칠 출발점"으로 유용합니다. 실수로 들어갔다면 그냥 git switch main으로 빠져나오면 됩니다. 커밋을 안 했다면 잃을 것도 없습니다.

18.6 가비지 컬렉션(GC) — 객체 청소

14장에서 배운 객체들은 시간이 지나며 쌓입니다. 어디에서도 참조하지 않는 객체(연결 끊긴 detached 커밋 등)는 가비지(쓰레기)입니다. Git은 이를 정리하고 저장소를 압축합니다.

BASH
git gc                  # 가비지 컬렉션 실행 (객체 압축·정리)
git gc --aggressive     # 더 강하게 압축 (느리지만 효과적)
💡 팁
평소엔 Git이 자동으로 GC를 수행하므로 직접 칠 일은 드뭅니다. 다만 GC가 돌면 reflog(10장)에서 만료된 미아 커밋이 영영 삭제될 수 있다는 점은 알아두세요. 그래서 "잃어버린 커밋 복구"는 GC 전에 빠를수록 좋습니다.

18.7 일반적인 개발 워크플로우 정리

지금까지 배운 것을 실무 흐름으로 묶으면 이렇습니다.

CODE
main (항상 배포 가능한 안정 상태)
  │
  ├─ feature/login   ← 기능마다 브랜치
  ├─ feature/payment
  └─ bugfix/cart

각 브랜치에서:
  1. main 최신화 → 브랜치 생성
  2. 작업 + 커밋 (작고 의미 있게)
  3. push → PR 생성
  4. CI 통과 + 리뷰 승인
  5. Squash and merge → 브랜치 삭제
  6. 필요시 태그(v1.2.0)로 릴리스
상황도구
기능 단위 분리브랜치(6장)
합치기PR + merge/squash(16장)
급한 수정 전파cherry-pick(18.2)
이력 정리rebase -i / amend / squash
되돌리기reset(로컬) / revert(공유) (10장)
잠깐 치우기stash(7장)
버전 표시tag(11장)

18.8 이 장에서 배운 것 (요약)

  • git log 고급: --graph --all, --author/--grep/--since, --pretty, shortlog, 별칭 git lg
  • cherry-pick: 특정 커밋만 골라 복사 (핫픽스 전파), 충돌은 --continue/--abort
  • amend: 마지막 커밋 교체 (push 전에만)
  • squash: 대화형 리베이스 또는 PR의 Squash and merge로 커밋 정리
  • detached HEAD: 커밋 직접 체크아웃 → 실험 후 git switch -c로 안착
  • git gc: 미아 객체 정리·압축 (보통 자동)
  • 실무 워크플로우: main 안정 + 기능 브랜치 + PR + 태그

✍️ 확인 문제

  1. 다른 브랜치의 커밋 하나만 현재 브랜치로 가져오는 명령은?
  2. detached HEAD에서 한 실험 커밋을 잃지 않으려면?
  3. git lg는 Git 기본 명령인가요? 아니라면 무엇인가요?
다음 장에서는 커밋·푸시 시점에 자동 검사를 거는 Git 훅(Hooks)을 배웁니다. → 19_Git훅.md