코드 리뷰가 떨어지는데 세 파일이 반쯤 고쳐진 상태이고 움직일 수 있는 건 하나뿐이다. 전부 stash에 넣고 나머지 두 파일을 다시 타이핑하는 건 아무도 그리워하지 않는 의식이다.
TL;DR: git stash push -m "이유" -- <경로>는 지정한 경로만 stash에 넣고 더러운 트리의 나머지는 건드리지 않는다. 변경 사항은 git stash pop으로 되돌린다(또는 어떤 stash에서든 파일 하나만 git restore --source stash@{0} -- <경로>로 꺼낸다). pathspec 형식은 2017년 5월에 나온 git 2.13에 들어왔으니 — 최근 8년의 어떤 툴체인에도 있다.
git stash push -m "app.conf prod tweak" -- app.conf
git stash list
# stash@{0}: On main: app.conf prod tweak
git stash pop 트리 말고, 파일을 stash하라.
git에서 파일 하나만 stash하는 법?
맨 git stash는 작업 트리 전체를 쓸어 담는다 — 추적 중인 모든 변경이 stash로 가고 모든 게 HEAD로 돌아간다. 더러운 트리가 뒤섞여 있으면 잘못된 모양새다. 하나는 넘겨줄 준비가 됐고 나머지는 솔직히 미완성이다. 답은 pathspec을 붙인 push 동사다. git-stash 문서 기준:
# 이전: 더러운 파일 셋
$ git status --short
M app.conf
M notes.md
M main.py
# app.conf만 stash
$ git stash push -m "app.conf prod tweak" -- app.conf
Saved working directory and index state On main: app.conf prod tweak
$ git status --short
M notes.md
M main.py app.conf는 커밋된 상태로 돌아가 stash@{0}에 들어갔고, notes.md와 main.py는 꼼짝 않았다. -m 메시지는 선택 사항이지만 git stash list에 항목이 둘째가 늘어서는 순간 3초의 값어치가 있다 — “WIP”라는 세례명의 stash는 늙는 속도가 빠르다.
중요한 디테일 둘:
- pathspec은
--뒤에 온다. 이중 대시 뒤의 모든 것은 플래그가 아니라 경로다.git checkout -- <경로>와 같은 관례이며 장식이 아니다. 오래된 버전에서는git stash push -- main.py와git stash push main.py가 달랐고, 맨 경로는 오해될 수 있었다. - 추적되지 않는 파일은
-u가 필요하다. 갓 만든 파일은 stash할 추적 이력이 없어서 평범한push는 건너뛴다.git stash push -u -- newfile.py가 포함하고,-a는 한 발 더 나아가 무시되는 파일까지 쓸어 담는다.
파일 하나의 일부만 stash하려면?
파일 자체가 반쯤 준비됐을 때 — 좋은 hunk 셋과 하나의 창피한 것 — 대화형 흐름이 잘라낸다:
git stash -p # 또는: git stash push -p Git이 hunk마다 Stash this hunk [y,n,q,a,d,j,g,/,e,p,?]?를 묻는다. stash에 들어갈 hunk엔 y, 남을 것엔 n. 결과는 승인한 것만 담은 stash이고 파일의 나머지는 트리에 더러운 채 남는다. 같은 hunk 단위 기계가 git add -p도 굴리니 반사신경은 그대로 이식된다.
git stash push -- <경로> | git stash -p | |
|---|---|---|
| 입도 | 파일 단위 | 개별 hunk |
| 속도 | 명령 하나, 스크립트 가능 | 대화형, hunk마다 |
| CI 재현 가능 | 예 (경로를 인자로) | 아니오 — 프롬프트에 사람 필요 |
| 최적 용도 | “이 파일, 나머지는 아냐” | “이 변경, 저건 아니야” |
| 도입 | git 2.13 (2017년 5월) | 오래전부터 |
문서 자체의 모델에서 나온 실무 규칙: 경계가 파일이면 pathspec, 파일 안이면 -p.
stash에 넣은 파일을 되돌리려면?
git stash pop은 stash@{0}을 복원하고 항목을 지운다. 정공법이다 — 하지만 pop은 stash 하나에 전부 아니면 전무고, 충돌이 나면 항목을 남긴 채 중단된다. 더 가는 옵션 둘:
# 1. 지우지 않고 적용 (안전하게 반복 가능)
git stash apply stash@{0}
# 2. stash에서 파일 하나만 꺼내고 항목은 유지
git restore --source stash@{0} -- app.conf
# 같은 연산의 2.23 이전 표기:
git checkout stash@{0} -- app.conf restore/checkout 형식이 답하는 사례는 “세 변경을 함께 stash했는데 이제 하나만 필요하다”다 — 그 경로의 stash 내용을 작업 트리로 복사하고 stash@{0}은 그대로 선다. 주의: 작업 트리 사본을 덮어쓴다. 그 경로의 현재 수정이 소중하면 먼저 diff:
git diff stash@{0} -- app.conf stash는 reflog 같은 스택 위의 실제 커밋으로 저장된다. 그래서 stash@{0}는 어떤 commit-ish 문법이든 받고, 실수로 지운 stash도 GC가 먹어치우기 전엔 reflog에서 복구된다.
stash가 잘못된 도구일 때는?
stash는 브랜치가 아니라 스케치북이다: git branch에 이름 없고, 리뷰 없고, 기본으로 보이는 diff도 없고, 항목은 말없이 쌓여 잊힌다. 진행 중인 작업이 기계나 날짜를 넘는 컨텍스트 전환을 살아남아야 한다면 브랜치에 커밋하라 — 딸려온 히스토리가 이름 없는 스택보다 낫다. 주차된 커밋들을 나중에 다른 곳에 내려야 한다면 git cherry-pick이 옮겨준다. 되돌리기가 목적이면 직전 커밋 되돌리기의 결정 트리가 통한다.
문서화된 동작에서 뽑은 정직한 고장 장부:
| 증상 | 원인 | 처방 |
|---|---|---|
| stash 뒤에 파일이 없다 | 추적 안 되는 경로는 건너뜀 | git stash push -u -- <경로> |
pop에서 error: Your local changes ... would be overwritten | stash 이후 경로가 변했다 | 새 상태를 커밋하거나 stash, 그다음 pop |
| 꺼낸 변경이 사라졌다 | pop이 충돌로 중단됐다 | 해결 후 git stash apply |
| “어느 stash였지?” | 이름 없는 stash 더미 | 매번 -m 메시지 |
pathspec을 git stash push에 얹은 2017년 5월 릴리스 노트가 여덟 살이 됐고, git stash 근육 기억의 대부분은 그보다 나이 많다. 다시 배울 가치가 있다: 트리 전체 쓸어담기가 이제 특수 사례다, 기본값이 아니다.
FAQ
git에서 파일 하나만 stash하려면?
git stash push -m "메모" -- 경로/파일 — pathspec 형식은 지정한 경로만 stash하고 다른 변경된 파일은 그대로 둡니다. git 2.13 이상(2017년 5월)이 필요합니다.
stash에서 파일 하나만 꺼내려면?
git restore --source stash@{0} -- 경로/파일 (또는 이전 표기인 git checkout stash@{0} -- 경로/파일). stash 항목을 지우지 않고 stash된 버전을 작업 트리로 복사합니다.
git stash가 새 파일을 건너뛰는 이유는?
추적되지 않는(untracked) 파일은 일반 stash 대상이 아닙니다. -u를 붙이면 포함됩니다: git stash push -u -- 경로/파일. 무시되는(ignored) 파일은 -a가 필요합니다.
— mrsaynothing
— mrsaynothing
AI, Linux, 셀프 호스팅 필드 노트.
다음 how-to를 이메일로 받아보세요
포스트당 한 통. 고치고 넘어가세요.
이게 뭔가요?Field Notes #1: 에이전트가 돌리는 사이트. 기계가 배포하고 나는 승인한다.
글이 마음에 드셨나요? 제 본업이 바로 이런 일입니다. 저를 고용하세요