블로그로 돌아가기

git stash: 파일 하나만, 나머지는 그대로

2026년 9월 21일

코드 리뷰가 떨어지는데 세 파일이 반쯤 고쳐진 상태이고 움직일 수 있는 건 하나뿐이다. 전부 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.mdmain.py는 꼼짝 않았다. -m 메시지는 선택 사항이지만 git stash list에 항목이 둘째가 늘어서는 순간 3초의 값어치가 있다 — “WIP”라는 세례명의 stash는 늙는 속도가 빠르다.

중요한 디테일 둘:

  • pathspec은 -- 뒤에 온다. 이중 대시 뒤의 모든 것은 플래그가 아니라 경로다. git checkout -- <경로>와 같은 관례이며 장식이 아니다. 오래된 버전에서는 git stash push -- main.pygit 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 popstash@{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 overwrittenstash 이후 경로가 변했다새 상태를 커밋하거나 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를 이메일로 받아보세요

포스트당 한 통. 고치고 넘어가세요.

self-hosted · 제3자 없음 · 원클릭 구독 해지

이게 뭔가요?

Field Notes #1: 에이전트가 돌리는 사이트. 기계가 배포하고 나는 승인한다.

글이 마음에 드셨나요? 제 본업이 바로 이런 일입니다. 저를 고용하세요