당신을 마법사처럼 보이게 하는 7가지 Git 명령
Source: Dev.to
You know what actually separates the devs who look like they know what they’re doing from the ones who just Google “how to undo git commit” every other day?
It’s not knowing fancy algorithms or memorizing design patterns. It’s knowing your way around Git beyond add, commit, push, and panic‑googling merge conflicts.
I’m talking about the commands that make your pair‑programming partner stop and go, “wait, you can do that?” The deep cuts that turn a 30‑minute disaster recovery into a 10‑second flex.
1. git reflog – 몰랐던 되돌리기 버튼
모든 개발자는 그런 순간을 겪습니다: 잘못된 브랜치에 force‑push를 하거나, git reset --hard를 실행해 작업이 사라지는 것을 보거나, 리베이스를 해서 커밋 히스토리가 추상 미술처럼 보이는 경우 등.
그것이 사라졌다고 생각하지만, 사실은 그렇지 않습니다.
git reflog는 Git의 비행 기록 장치와 같습니다. HEAD가 가리켰던 모든 것을 추적합니다. 이제 어떤 브랜치에도 존재하지 않는 것들까지도 말이죠. 삭제된 커밋, 포기된 리베이스, force‑push로 사라진 커밋 등 모든 것이 여기 저장됩니다.
시나리오: 방금 git reset --hard HEAD~3를 실행했으며, 바로 잘못된 커밋을 삭제했음을 깨달았습니다. 가슴이 철렁합니다. 3시간짜리 작업이 사라졌죠.
# See everything HEAD has ever pointed to
git reflog
출력은 다음과 같습니다:
a1b2c3d HEAD@{0}: reset: moving to HEAD~3
f4e5d6c HEAD@{1}: commit: implement payment webhook
7g8h9i0 HEAD@{2}: commit: add Stripe integration
j1k2l3m HEAD@{3}: commit: refactor checkout flow
그냥… 되돌리면 됩니다.
git reset --hard f4e5d6c
그게 전부입니다. 커밋이 복구됩니다. 전혀 걱정되지 않죠. 다른 사람들은 당황해 새 레포를 복제하고 있을 때, 당신은 마치 시간 여행자처럼 여유롭게 히스토리를 복원하고 있습니다.
팁: 기본적으로 reflog 항목은 90 일 후에 만료됩니다. 따라서 3개월을 기다렸다가 복구가 필요하다는 것을 깨닫지 마세요.
2. git bisect – Git이 버그를 찾아줍니다
상황을 상상해 보세요: CI는 초록색이고 테스트는 통과하지만, 지난 47개의 커밋 중 어느 하나에서 로그인 페이지가 Firefox에서 거꾸로 렌더링되기 시작했습니다. 어떤 커밋이 문제를 일으켰는지 아무도 모릅니다.
각 커밋을 하나씩 체크아웃하면서 확인할 수도 있습니다. 아니면 Git에게 히스토리를 자동으로 이진 탐색하도록 맡길 수도 있습니다.
# 사냥 시작
git bisect start
# 현재(깨진) 상태를 나쁨(bad)으로 표시
git bisect bad
# 알려진 정상(good) 커밋을 표시(예: 지난 주 릴리스 태그)
git bisect good v2.3.1
Git이 중간 커밋을 체크아웃합니다. 테스트해 보세요.
# 깨졌다면:
git bisect bad
# 정상이라면:
git bisect good
반복합니다. Git은 log₂(n) 단계 안에 원인을 좁혀갑니다.
47개의 커밋? 약 6번의 검사이면 충분합니다. 47번을 일일이 할 필요가 없습니다.
좋은 상태와 나쁜 상태 사이에 1 000개의 커밋이 있다면, 약 10단계 안에 문제 커밋을 찾을 수 있습니다. 이것은 커밋 히스토리에서 실제로 이진 탐색을 수행하는 것입니다. 컴퓨터 과학™이 드디어 실용적으로 쓰이는 순간이죠.
다음 단계: 자동으로 정상/비정상을 판단할 수 있는 테스트 스크립트가 있다면:
git bisect start HEAD v2.3.1
git bisect run ./test-login-page.sh
커피 한 잔을 마시러 가세요. 당신이 없는 사이에 Git이 정확히 어느 커밋이 문제를 일으켰는지 찾아줄 것입니다. 돌아와서 그 커밋을 가리키면, 마치 터미널을 들고 있는 셜록 홈즈처럼 보일 겁니다.
Source:
3. git stash -p – 외과적 스태시
모두가 git stash를 알고 있습니다. 하지만 대부분은 망치처럼 사용합니다: 모든 것을 스태시하고, 다시 돌아오길 기도하죠.
-p 플래그(patch의 약자)는 어떤 청크를 스태시할지 인터랙티브하게 선택할 수 있게 해줍니다. 한 번에 두 가지 일을 하고 있을 때(부인하지 마세요) 하나만 커밋하고 싶을 때 유용합니다.
시나리오: 기능을 절반 정도 구현했는데, 그 과정에서 발견한 버그를 고쳤습니다. 이제 버그 수정을 바로 커밋하고, 기능 작업을 계속 진행하고 싶습니다.
# 인터랙티브하게 스태시할 항목 선택
git stash -p
Git이 변경 사항을 하나씩 보여줍니다:
Stash this hunk [y,n,q,a,d,s,e,?]?
y = stash this hunk
n = keep this hunk (don’t stash)
s = split into smaller hunks
q = quit (done selecting)
이제 작업 디렉터리에는 버그 수정만 남게 됩니다.
git add -A && git commit -m "fix: null check on user session"
기능 작업을 다시 가져옵니다:
git stash pop
s 옵션이 비밀 소스입니다: Git이 두 변화를 하나의 청크로 묶었을 때, 이를 더 작은 청크로 나눕니다. 작업 트리를 정밀하게 다듬는 수술 같은 기능이죠.
보너스 조합:
git stash -p -m "WIP: auth refactor"
선택적으로 스태시하면서 이름까지 붙일 수 있어, 며칠 뒤에 “어떤 스태시가 어떤 것이었지?” 라는 룰렛을 돌릴 필요가 없습니다.
4. git rebase -i – 의도한 대로 히스토리 재작성하기
인터랙티브 리베이스는 가장 강력한 Git 명령이자, 가장 많은 사람들이 두려워하는 명령입니다. 두려움을 버리세요. 그냥 TODO 리스트를 편집하는 것과 같습니다.
커밋을 squash 할 수도 있고, 순서를 바꿀 수도 있으며, 메시지를 다시 쓸 수도 있고, 커밋을 완전히 삭제하거나 그대로 편집할 수도 있습니다. 텍스트 편집기에서 보는 것이 여러분의 커밋 히스토리이며, 그 파일의 주인은 여러분입니다.
시나리오: 기능을 구현하면서 6개의 커밋을 만들었고, 그 중 세 개는 “fix typo”, “WIP”, “actually fix the thing I said I fixed” 입니다. 이 커밋들을 영구 기록에 남기고 싶지 않습니다.
# 마지막 6개의 커밋을 인터랙티브하게 리베이스
git rebase -i HEAD~6
편집기가 다음과 같이 열립니다:
pick a1b2c3d add user authentication
pick d4e5f6g WIP: trying stuff
pick h7i8j9k fix typo in auth middleware
pick l0m1n2o actually implement auth middleware
pick p3q4r5s add auth tests
pick t6u7v8w fix test assertion
이를 다음과 같이 변경합니다:
pick a1b2c3d add user authentication
squash d4e5f6g WIP: trying stuff
squash h7i8j9k fix typo in auth middleware
squash l0m1n2o actually implement auth middleware
pick p3q4r5s add auth tests
fixup t6u7v8w fix test assertion
저장하고 닫으면 깔끔하고 전문적인 히스토리가 만들어집니다.
squash는 커밋을 이전 커밋에 합치면서 메시지를 다시 작성할 수 있게 합니다.fixup은 새로운 메시지를 묻지 않고 합칩니다.
5. git cherry-pick: 다른 브랜치에서 가져오기
때때로 다른 브랜치에서 정확히 하나의 커밋만 필요할 때가 있습니다. 머지도, 리베이스도 아니라—동료가 develop에 푸시한 바로 그 수정 하나가 현재 작업 중인 피처 브랜치에 절실히 필요할 때 말이죠.
# 해시로 특정 커밋을 가져오기
git cherry-pick a1b2c3d
# 여러 커밋이 필요하나요? 물론 가능합니다.
git cherry-pick a1b2c3d f4e5d6c
# 커밋 없이 체리‑픽 (변경만 스테이징)
git cherry-pick --no-commit a1b2c3d
실제로 일어나는 상황: 프로덕션에 문제가 발생했습니다. 해당 수정은 develop 브랜치에 존재하지만, 아직 프로덕션에 올릴 준비가 되지 않은 30개의 다른 커밋 사이에 파묻혀 있습니다. 필요한 것은 그 수정뿐이고, 나머지 30개의 커밋은 원하지 않습니다.
git checkout main
git cherry-pick d4e5f6a # 바로 그 핫픽스 커밋만
git push origin main
주의: 체리‑픽은 동일한 변경 사항을 가진 새로운 커밋을 만들며 해시가 달라집니다. 나중에 원본 브랜치를 머지하면 Git이 보통 이를 자동으로 처리하지만, 가끔 중복된 것처럼 보이는 충돌이 발생할 수 있습니다. 이것이 트레이드‑오프이며, 충분히 가치가 있습니다.
6. git log -S: 모든 시점을 검색
git log만 사용하면 지루합니다. git log --oneline은 조금 덜 지루하지만, git log -S는 검색창이 달린 타임머신과 같습니다.
-S 옵션(일명 pickaxe)은 내용을 기준으로 히스토리의 모든 diff를 탐색합니다—커밋 메시지가 아니라 실제 코드 변경을 살펴봅니다. 특정 문자열이 추가되거나 제거된 커밋을 찾아줍니다.
시나리오: 누군가 validatePayment() 함수를 삭제했습니다. 언제, 왜 삭제됐는지 모른 채, 파일이 그 이후로 여섯 번이나 리팩터링돼 git blame으로는 원인을 찾을 수 없습니다.
# "validatePayment"가 추가되거나 제거된 모든 커밋 찾기
git log -S "validatePayment" --oneline
샘플 출력
f4e5d6c remove legacy payment validation
a1b2c3d refactor: extract payment validation
9z8y7x6 add payment validation to checkout
# 실제 diff를 보고 싶다면?
git log -S "validatePayment" -p
# 정규식으로 검색하기
git log -G "validate.*Payment" --oneline
-S는 출현 횟수가 변한 커밋을 찾습니다.-G는 문자열이 diff 어디에든 나타나는 커밋을 찾습니다(출현 횟수가 변하지 않아도).
대부분의 탐색 작업에서는 -S가 바로 원하는 옵션입니다.
아무도 말하지 않는 강력한 조합
git log --all --oneline --graph --decorate
터미널에서 바로 시각적인 브랜치 토폴로지를 보여줍니다. 이를 git lg라는 별칭으로 만들어 두면 GUI Git 클라이언트를 거의 사용할 필요가 없게 됩니다(가끔은 필요하지만 훨씬 적게).
7. git worktree: 한 번에 두 곳에 있기
이 기능은 정말 과소평가되고 있습니다. git worktree를 사용하면 동일한 .git 데이터를 공유하면서 여러 브랜치를 동시에 별도의 디렉터리에서 체크아웃할 수 있습니다. 이제 스태시를 만들 필요도, 레포를 두 번 복제할 필요도, 브랜치를 전환하기 위해 반쯤 완성된 작업을 커밋할 필요도 없습니다.
Scenario: 기능 브랜치에 깊이 파고들어 있는 상황. PM이 “main에 치명적인 버그가 있어 지금 바로 고쳐야 한다”고 알립니다. 아직 스테이징하지 않은 실험적인 변경 사항이 여기저기 흩어져 있고, 이를 모두 스태시하고 싶지 않습니다.
# 핫픽스를 위해 새로운 worktree를 만들고 main을 체크아웃
git worktree add ../hotfix-login main
이제 다음과 같은 구조가 됩니다:
/projects/myapp → 당신의 기능 브랜치 (그대로 유지)
/projects/hotfix-login → main 브랜치, 수정 준비 완료
cd ../hotfix-login
# 버그를 고치고, 커밋하고, 푸시합니다. 기능 브랜치는 전혀 방해받지 않습니다.
작업이 끝나면 정리합니다:
cd ../myapp
git worktree remove ../hotfix-login
컨텍스트 전환 시 git stash보다 훨씬 뛰어납니다. 기능 브랜치는 그대로 유지됩니다—더러운 파일, 열려 있는 에디터 탭 등 모든 것이 그대로 남아 있습니다. 핫픽스는 완전히 별도 디렉터리에서 이루어집니다.
저는 코드 리뷰를 할 때도 거의 매일 이 방법을 사용합니다. 팀원의 브랜치를 별도의 worktree에 체크아웃해 실행하고 살펴보면서, 제 작업은 전혀 건드리지 않으니까요. 게임 체인저입니다.
실제 마법사 움직임
이 명령어들은 어느 하나도 “고급”이 아닙니다. 모두 문서에 적혀 있고 수년간 존재해 왔습니다. 이 명령어들이 여러분을 마법사처럼 보이게 하는 이유는 대부분의 개발자가 add, commit, push, pull 정도만 배우고 머지 충돌을 패닉‑구글링하는 데서 그치기 때문입니다.
오늘 당장 모든 것을 외울 필요는 없습니다. 하나만 골라 보세요. 다음에 Git이 엉망이 되었을 때, 레포를 완전히 삭제하고 새로 클론하는 대신 그것을 시도해 보세요. 이렇게 하면 한 번에 하나씩 “아, 안돼” 순간을 넘어 성장할 수 있습니다.
당신에게 도움이 된 Git 트릭이 있나요? 댓글에 남겨 주세요. 저는 언제나 새로운 마법을 찾고 있습니다. 🧙♂️