작업 중 임시저장 -> Git Stash
Git Stash 완전 정리: 작업 중 변경사항을 잠시 보관하고 다시 꺼내는 방법
Git을 사용하다 보면 현재 브랜치에서 작업 중인데 갑자기 다른 브랜치로 이동해야 할 때가 있다. 아직 작업이 끝나지 않아 커밋하기는 애매하고, 그렇다고 수정 내용을 버릴 수도 없다. 이럴 때 사용하는 기능이 git stash다.
git stash를 가장 쉽게 이해하면 다음과 같다.
1. git stash는 언제 사용하는가
예를 들어 현재 feature 브랜치에서 다음과 같이 작업 중이라고 하자.
<h1>스태시를 실습합니다.</h1>
<h2>새로운 기능을 시작합니다.</h2>
새로운 기능이 너무 복잡하네요. 시간이 많이 걸릴 것 같습니다.
아직 기능 개발이 끝난 것은 아니어서 커밋하기는 애매하다. 그런데 갑자기 master 브랜치에서 버그를 수정해야 한다면 현재 작업을 임시로 보관할 수 있다.
git stash
이 명령을 실행하면 Git은 현재 변경사항을 stash에 보관하고 작업 디렉터리를 이전 커밋 상태로 되돌린다. VS Code에서 보고 있던 파일도 마지막 커밋 상태로 돌아간다.
작업 내용이 삭제된 것이 아니라 stash에 따로 보관된 것이다.
2. stash를 저장하면 실제로 무슨 일이 일어나는가
마지막 커밋 상태를 A라고 하자.
A
그 뒤 파일을 수정했다.
A + 작업 중인 수정내용
여기서:
git stash
를 실행하면 수정내용은 stash로 이동하고 작업 디렉터리는 다시 A 상태가 된다.
작업 중 수정내용
↓
stash
작업 디렉터리
↓
A
그래서 git status를 실행하면 보통:
nothing to commit, working tree clean
이라고 나온다.
3. 저장된 stash 확인하기
git stash list
예를 들어 다음과 같이 나타날 수 있다.
stash@{0}: WIP on feature: 6f63293 new feature start
이 한 줄을 하나씩 해석해보자.
stash@{0}
가장 최근에 저장한 stash다. 번호는 0부터 시작한다.
stash@{0} → 가장 최근 stash
stash@{1} → 두 번째로 최근 stash
stash@{2} → 세 번째로 최근 stash
WIP
Work In Progress, 즉 “작업 중이던 내용”이라는 뜻이다.
on feature
stash를 만들 당시 feature 브랜치에서 작업하고 있었다는 뜻이다.
6f63293
stash 자체의 해시값이 아니다. stash를 만들 당시 feature 브랜치의
HEAD가 가리키던 기준 커밋의 짧은 해시다.
new feature start
6f63293 커밋의 커밋 메시지다.
4. stash 자체에도 커밋 해시가 있다
Git 내부적으로 stash도 커밋 객체 형태로 관리된다.
Windows CMD에서는 다음 명령으로 최신 stash가 가리키는 해시를 볼 수 있다.
type .git\refs\stash
예:
a3829fda87d15664e6d1ceca35b0684647f80fa3
여기서:
6f63293 → stash를 만들 당시의 기준 커밋
a3829fda… → stash 자체가 가리키는 커밋
둘은 서로 다른 값이다.
5. Windows CMD에서는 cat 대신 type
Linux/macOS에서는 보통:
cat .git/refs/stash
를 사용한다.
PowerShell에서도 cat을 사용할 수 있는데, 실제로는 Get-Content의 별칭이다.
cat .git/refs/stash
Get-Content .git/refs/stash
Windows CMD에서는:
type .git\refs\stash
를 사용한다.
type은 Git 명령이 아니다.
단순히 .git\refs\stash 파일의 내용을 화면에 출력하는 Windows CMD 명령이다.
Git에게 직접 물어보고 싶다면:
git rev-parse refs/stash
를 사용할 수 있다.
6. stash 내부 기록 확인하기
stash 참조의 변경 이력은 다음 파일에서 볼 수 있다.
type .git\logs\refs\stash
예:
0000000000000000000000000000000000000000 a3829fda87d15664e6d1ceca35b0684647f80fa3 ...
첫 번째 0000...은 이전 stash 참조가 없었다는 뜻이고, 두 번째 해시는 새로 생성된 stash가 가리키는 커밋이다.
.git\refs\stash
→ 현재 최신 stash를 가리키는 참조
.git\logs\refs\stash
→ stash 참조가 어떻게 변경되어 왔는지 기록
7. stash 안에 무엇이 들어 있는지 확인하기
변경 내용을 간단히 요약해서 보려면:
git stash show stash@{0}
예:
stash.htm | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
실제 어떤 줄이 바뀌었는지까지 보고 싶다면:
git stash show -p stash@{0}
여기서:
show: 내용을 보여줘-p: patch 형태, 즉 실제 diff까지 자세히 보여줘stash@{0}: 가장 최근 stash를 지정
전체적으로는 다음 의미다.
8. 같은 문장이 삭제되고 다시 추가된 것으로 보이는 이유
다음과 같은 diff가 나타날 수 있다.
-<h2>새로운 기능을 시작합니다.</h2>
\ No newline at end of file
+<h2>새로운 기능을 시작합니다.</h2>
+새로운 기능이 너무 복잡하네요. 시간이 많이 걸릴 것 같습니다.
\ No newline at end of file
문장은 똑같은데 Git은 왜 기존 줄을 삭제하고 새로 추가했다고 판단했을까?
이유는 마지막 줄의 줄바꿈 문자 때문이다.
기존:
<h2>새로운 기능을 시작합니다.</h2>[파일 끝]
변경:
<h2>새로운 기능을 시작합니다.</h2>\n
새로운 기능이 너무 복잡하네요...
기존에는 마지막 줄 끝에 줄바꿈이 없었지만 새 문장을 추가하면서 줄바꿈이 생겼다. Git 입장에서는 “줄바꿈이 없는 줄”과 “줄바꿈이 있는 줄”이 동일하지 않다.
그래서:
1 deletion
2 insertions
으로 표시될 수 있다.
9. No newline과 LF/CRLF는 같은 문제인가
관련은 있지만 서로 다른 개념이다.
| 구분 | 의미 |
|---|---|
| No newline at end of file | 파일 마지막 줄 끝에 줄바꿈 자체가 없음 |
| LF | 줄바꿈을 \n으로 표현 |
| CRLF | 줄바꿈을 \r\n으로 표현 |
일반적으로 Linux/macOS에서는 LF, Windows에서는 CRLF를 많이 사용한다.
10. stash 복원하기: apply와 pop
git stash apply
git stash apply
stash 내용을 현재 작업 디렉터리에 다시 적용하지만 stash 목록에서는 제거하지 않는다.
변경사항 복원
+
stash 유지
git stash pop
git stash pop
stash를 현재 작업 디렉터리에 적용하고, 성공적으로 적용되면 stash 목록에서 제거한다.
변경사항 복원
+
stash 제거
성공하면 다음과 같은 메시지를 볼 수 있다.
Dropped refs/stash@{0}
11. 다른 브랜치에서 작업한 내용과 stash
예를 들어 feature에서 stash를 만든 뒤 master로 이동해 버그를 수정하고 커밋했다고 하자.
git commit -am "bug fix master"
그 뒤:
git checkout feature
git stash pop
을 실행하면 예전에 feature에서 stash해 둔 작업이 다시 나타난다.
이때 master에서 영문으로 바꿨던 내용이 사라진 것처럼 보일 수도 있다. 하지만 실제로는 사라진 것이 아니라 master 브랜치의 커밋에 그대로 저장되어 있다.
12. stash와 merge는 별개의 개념이다
예를 들어:
6f63293 ← feature
|
d2af869 ← master
처럼 master만 앞으로 나가 있고 feature에는 별도 커밋이 없다면:
git checkout feature
git merge master
를 실행했을 때 feature가 master 위치까지 그대로 이동할 수 있다.
6f63293
|
d2af869 ← master, feature
이것이 fast-forward다. 이 경우 새로운 merge commit은 생기지 않는다.
13. 양쪽 브랜치 모두 커밋이 있다면
B ← master
/
A -------
\
C ← feature
이 상태에서 feature 브랜치에 서서:
git merge master
를 실행하면 일반적으로 새로운 merge commit이 만들어진다.
B ← master
/ \
A ------- M ← feature
\ /
C
여기서 M은 새로운 merge commit이고, feature 브랜치가 M을 가리킨다.
master는 여전히 B를 가리킨다.
14. merge 방향은 현재 브랜치가 결정한다
git merge 대상브랜치
의 의미는:
예를 들어:
git checkout master
git merge feature
이면 feature의 변경사항을 master에 합친다.
반대로:
git checkout feature
git merge master
이면 master의 변경사항을 feature에 합친다.
15. master나 main도 결국 하나의 브랜치다
Git을 처음 배우면 master나 main이 특별한 중심 저장소처럼 느껴질 수 있다.
하지만 Git 내부에서 이들도 결국 하나의 브랜치 이름이다.
필요하다면 feature를 계속 기준 브랜치로 사용하거나:
git branch -m feature main
처럼 이름을 바꿔 새로운 기준 브랜치로 삼을 수도 있다.
실무에서 main/master를 중심으로 사용하는 이유는 프로젝트의 기준선을 하나 정해 협업하기 편하게 하기 위해서다.
16. 병합 후 feature 브랜치 정리하기
feature의 작업이 master에 정상적으로 병합됐다면 보통 다음처럼 삭제한다.
git branch -d feature
-d는 안전 삭제다. 병합되지 않은 커밋이 남아 있으면 Git이 삭제를 막는다.
강제로 삭제하려면:
git branch -D feature
를 사용할 수 있지만, 병합되지 않은 작업까지 잃을 수 있으므로 주의해야 한다.
브랜치를 삭제한다고 이미 병합된 커밋이 없어지는 것은 아니다. 브랜치 삭제는 커밋 이력을 삭제하는 것보다 “그 이력을 가리키던 이름표를 제거하는 것”에 가깝다.
17. 어느 쪽에서 병합했느냐에 따라 마무리가 달라진다
병합 방향에 따라 브랜치를 정리하는 흐름이 조금 다르다.
① master에서 feature를 병합한 경우
병합이 끝났다면 feature 브랜치는 역할을 다한 것이므로 바로 삭제하면 된다.
git checkout master
git merge feature
git branch -d feature
② feature에서 master를 병합해 새 merge commit이 생긴 경우
이때 merge commit M은 master가 아니라 feature 쪽에 생긴다.
A---B ← master
\ \
C---M ← feature
master는 아직 B에 머물러 있으므로, master로 돌아가 feature를 병합해 준다. 이때 master가 M까지 fast-forward로 앞으로 이동한다.
git checkout master
git merge feature
A---B
\ \
C---M ← master, feature
master와 feature가 같은 커밋을 가리키게 되었으니 이제 feature를 삭제해 정리한다.
git branch -d feature
B에 그대로 있을 때 가능하다.
feature에서 master를 병합한 뒤 master에 다른 커밋이 더 생겼다면 fast-forward가 아니라 새로운 merge commit이 만들어질 수 있다.
18. git status에서는 stash가 보이지 않는다
중요한 점이 하나 있다.
git status
만 실행해서는 stash가 존재하는지 알 수 없다.
git status는 현재 작업 디렉터리, staging area, 브랜치 상태 등을 확인하는 명령이고, stash 목록은 별도로:
git stash list
를 실행해야 한다.
따라서 stash를 만들어놓고 오랫동안 사용하지 않으면 존재 자체를 잊어버릴 수 있다.
19. stash에 이름 붙이기
여러 stash가 쌓일 가능성이 있다면 메시지를 붙이는 편이 좋다.
git stash push -m "로그인 화면 수정 중"
그 후:
git stash list
를 실행하면 어떤 작업을 저장했는지 훨씬 알아보기 쉬워진다.
20. 오래 보관할 작업이라면 stash보다 커밋
stash는 기본적으로 잠깐 보관하는 작업에 적합하다. 며칠 또는 몇 주 동안 보관해야 할 중요한 작업이라면 별도의 브랜치에서 WIP 커밋을 만드는 편이 관리하기 쉽다.
git add .
git commit -m "WIP: feature 작업 중"
잠깐 보관 → stash
장기간 보관 → 브랜치 + WIP 커밋
21. git commit -am의 의미
git commit -am "bug fix master"
에서:
-a: 이미 Git이 추적 중인 파일의 수정·삭제 내용을 자동 staging-m: 커밋 메시지 지정
다만 새로 생성한 untracked 파일은 -a에 포함되지 않는다.
git add 새파일명
git commit -m "메시지"
처럼 처음에는 git add가 필요하다.
22. Git의 추적 상태
| 목적 | 명령 |
|---|---|
| 추적 시작 | git add 파일명 |
| 추적 해제, 실제 파일은 유지 | git rm --cached 파일명 |
| 파일 삭제 + 추적 해제 | git rm 파일명 |
23. Windows CMD에서 테스트 파일 만들기
echo "this is temp" > temp.htm
이 명령은 temp.htm 파일을 만들고 그 안에 "this is temp"라는 내용을 저장한다.
파일이 이미 존재하면 덮어쓴다.
기존 내용 뒤에 추가하려면:
echo "this is temp" >> temp.htm
를 사용한다.
> → 새로 쓰기 / 덮어쓰기
>> → 기존 내용 뒤에 추가
24. git stash 핵심 명령어 정리
| 명령어 | 역할 |
|---|---|
git stash | 현재 변경사항 임시 저장 |
git stash push -m "메시지" | 설명을 붙여 stash 저장 |
git stash list | stash 목록 확인 |
git stash show stash@{0} | stash 변경사항 요약 |
git stash show -p stash@{0} | 실제 diff까지 자세히 확인 |
git stash apply | stash 적용, stash는 유지 |
git stash pop | stash 적용 후 성공하면 제거 |
git stash drop stash@{0} | 특정 stash 삭제 |
git stash clear | 모든 stash 삭제 |
25. 한 문장으로 정리하는 git stash
git stash는 단순히 파일을 임시 폴더에 복사하는 기능이 아니다.
Git 내부에서는 변경사항을 커밋 객체 형태로 저장하고 refs/stash라는 참조를 통해 관리한다.
하지만 실제 사용할 때는 다음처럼 이해하면 가장 쉽다.
그리고 나중에 git stash pop 또는 git stash apply로 다시 꺼내 작업을 이어간다.
stash를 공부하다 보면 자연스럽게 Working Directory, Staging Area, Commit, HEAD, Branch, Merge, Fast-forward, refs 같은 Git의 핵심 구조까지 함께 이해하게 된다.
마무리
처음에는 stash가 단순한 “임시 저장” 기능처럼 보이지만, 실제로는 브랜치를 이동하면서 작업 흐름을 안전하게 유지하는 데 매우 유용하다.
특히 git stash list를 습관적으로 확인하고, 장기간 보관할 작업은 브랜치와 커밋으로 관리하면 stash를 잊어버리는 문제도 줄일 수 있다.
예제 환경: Windows CMD · Git · VS Code