stash
는 '안전한 곳에 넣어두다'라는 의미를 가진다. 즉, code를 안전한 곳에 넣어두겠다는 것이다.
우리가 A
라는 branch에서 개발을 진행하고 있다고 하자. 그 와중에 B
라는 branch에서 특정 부분을 수정해달라는 요청을 받았다고 하자. 이는 일반적으로 A
branch의 변경 사항들을 commit한 후에 B
branch로 가는데, 아직 A
branch에서의 작업이 안 끝났다고 하자. 따라서, B
branch로 가기위해서 commit을 만들기는 모호하고, 그렇다고 commit을 하지 않으면 branch간 이동이 안되므로 난감한 상황에 걸릴 수 있다.
이 때 사용하는 것이 바로 git stash
이다. git stash
를 사용하면 commit은 하지 않고 A
branch의 code 내용들을 안전하게 저장한 다음, B
branch로 갈 수 있다. 이는 필수적인 기능은 아니지만, 알고있으면 굉장히 큰 도움이 된다.
다음의 두 경우를 알아보도록 하자.
먼저 첫번째는 '충돌이 안나고 branch이동이 가능한 경우'이다. 이 경우를 test해보기 위해서 다음과 같이 환경을 설정해보도록 하자
mkdir ./gitstash
cd ./gitstash
git init
환경 설정이 끝났다면, file을 하나 만들어보도록 하자.
echo -n "html css javascript" >> ./html.txt
cat ./html.txt
html css javascript
이제 commit을 해보도록 하자.
git add ./html.txt
git commit -m "add html.txt"
다음으로 ts
branch를 만들고, html.txt
파일을 수정하도록 하자.
git switch -c ts
echo -n " typescript" >> ./html.txt
cat ./html.txt
html css javascript typescript
성공한 것을 볼 수 있다. 이제 git add
, git commit
을 하지 않고, master
branch로 다시 넘어간다고 하자. 그럼 ts
branch에 있던 working directory file들이 어떻게 되는 지 보도록 하자.
git switch master
cat ./html.txt
html css javascript typescript
놀랍게도 master
branch로 이동했는데 typescript
가 남아있다. 이는 다른 branch에 있는 working directory가 이동하는 branch와 충돌하지 않으면 그대로 있다는 것을 알려준다.
master
branch에 html.txt
를 다음과 같이 수정하도록 하자.
html css javascript php
commit
을 해주도록 하자.
git add ./html.txt
git commit -m "update html.txt"
다시 ts
brach로 돌아와서 html.txt
를 다음과 같이 바꿔보도록 하자.
git switch ts
html css typescript
javascript
를 typescript
로 변경하였다. 이 상태로 commit없이 master
branch로 이동해보도록 하자.
git switch master
error: Your local changes to the following files would be overwritten by checkout:
html.txt
Please commit your changes or stash them before you switch branches.
Aborting
다음과 같이 실패한다. 이것은 ts
branch에 있는 working directory가 master의 commit 내용과 충돌하기 때문에 발생하는 문제이다.
log를 잘보면 Please commit your changes or stash
라는 말이 있다. commit을 하던지 stash
를 하라는 말이다.
일반적으로 대부분 commit
을 하지만, 완성도 안된 code를 가지고 commit
을 하기에는 무리가 있으므로, 이 경우 잠시 data를 보관하는 stash
를 사용하는 것이다. 이것이 git stash를 사용하는 가장 큰 이유이다.
git stash
는 commit하지 않은 변경사항들을 임시 저장하도록 해주고 불필요한 commit으로 이력이 더러워지지 않도록 해준다. 즉, 아직 완성되지 않았거나 commit할 준비가 되지 않은 것에 대해서 git stash
를 하는 것이다.
git stash
git stash
를 사용하면 commit하지 않은 모든 변경사항, stage area에 있는 변경 사항을 모두 stash한다. 즉, 변경사항을 기억했다가 working directory의 변경 사항을 되돌리는 것이다.
그리고 다시 되돌리때는 git stash pop
을 사용하면 된다.
git stash pop
git stash를 사용하면 다음과 같이 동작한다고 생각하면 된다.
branch: bugfix
---Working Directory--- ---Staging Area--- ---Repository---
| temp.html | | index.html | | 0026... |
| temp.css | | index.css | | bb43... |
----------------------- ------------------ ----------------
bugfix
라는 branch에서 master
branch로 가기 위해, 변경 사항들을 임시 저장하는 git stash
를 사용하면 다음과 같이 된다.
branch: bugfix
---Working Directory--- ---Staging Area--- ---Repository---
| | | | | 0026... |
| | | | | bb43... |
----------------------- ------------------ ----------------
-----------The Stash----------
| temp.html , index.html |
| temp.css , index.css |
------------------------------
working directory, staging area에 있는 data들이 모두 stash로 임시 보관되는 것이다.
이 다음 master
branch로 가서 작업을 한다음, 끝나면 bugfix
branch로 가서 git stash pop
을 해주면 된다.
branch: bugfix
---Working Directory--- ---Staging Area--- ---Repository---
| temp.html | | index.html | | 0026... |
| temp.css | | index.css | | bb43... |
----------------------- ------------------ ----------------
-----------The Stash----------
| |
| |
------------------------------
다시 원래의 영역으로 file들이 돌아간다.
이제 ts
branch에서 git stash
를 사용해보도록 하자.
git stash
Saved working directory and index state WIP on ts: 5757ff1 add html.txt
성공적으로 stashing되었다. 다음으로 master
branch로 넘어가보도록 하자.
git switch master
Switched to branch 'master'
문제없이 master branch로 이동되었고, html 파일도 다음과 같이 원래의 master branch 값이다.
html css javascript php
다시 ts
branch로 돌아가서 html.txt
를 살펴보도록 하자.
git switch ts
cat ./html.txt
html css javascript
재밌게도, 이전에 html.txt
를 수정했던 내용들이 없다. 이는 git stash로 인해서 workding directory, staging area에 있던 data들이 안전하게 보관되어있기 때문이다. 따라서, local에는 data가 남아있지 않아, 이전 commit의 data로 돌아가게 된 것이다.
따라서, 다시 stash된 data를 local로 가져오도록 하자.
git stash pop
On branch ts
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: html.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (54a2e40a53f202ca99b27d61973f38afb5b2a551)```
html.txt
파일이 복구되었는 지 확인해보도록 하자.
cat ./html.txt
html css typescript
복구된 것을 볼 수 있다. 참고로 git stash pop
은 stash에서 data를 가져오고, stash안에 있는 data들을 모두 삭제한다.
재밌는 것은 stash
영역은 git stash
를 호출한 branch에만 종속적이게 동작하지 않는다. 따라서, ts
branch에서 stash한 정보를 master
branch에 가서 적용이 가능하다.
git stash apply
는 git stash pop
과 비슷한데, 단 변동사항들을 stash에서 가져오지만 삭제하진 않는다. 이는 다른 branch에 있던 내용을 stash하여 현재 branch에 적용할 때 좋은 방식이다.
현재 ts
branch이므로 ts
branch의 변동사항을 stash
로 담아두기로 하자.
git stash
Saved working directory and index state WIP on ts: 5757ff1 add html.txt
다음으로 master
branch로 가서 html.txt
파일의 내용을 확인해보도록 하자.
git switch master
cat ./html.txt
html css javascript php
이제 git stash apply
를 사용하여 ts
에서의 변동사항을 master
에도 적용해보도록 하자.
git stash apply
Auto-merging html.txt
CONFLICT (content): Merge conflict in html.txt
CONFLICT
가 발생하는 것을 볼 수 있다. html.txt
파일을 확인해보도록 하자.
cat ./html.txt
<<<<<<< Updated upstream
html css javascript php
=======
html css typescript
>>>>>>> Stashed changes
어떤 것을 해야할 지, 결정해야한다. 우리의 경우는 stash에 있는 내용을 적용하도록 하자.
html css typescript
다음으로 commit
을 해주도록 하자.
git add ./html.txt
git commit -m "merge ts"
다음으로 ts
branch로 넘어가서 html.txt
파일을 보도록 하자.
git switch ts
cat ./html.txt
html css javascriptg
이전의 내용이 적용된 것을 알 수 있다. stash
에 있는 내용을 적용하기 위해서 git stash pop
을 사용해보도록 하자. 이전에 사용했던 git stash apply
는 stash 영역을 비워두지 않기 때문에, 남아있을 것이다.
git stash pop
On branch ts
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: html.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (dc58f920be02b1fadbaa460d6675665693dc76d5)
성공하였다. 다음으로 html.txt
의 내용을 보도록 하자.
cat ./html.txt
html css typescript
이전 stash 내용이 적용되어있다.
참고로, 여러 번 stashing하여 stack처럼 사용할 수 있다. 즉, 변경 사항을 적용한 순서대로 stack에 적재되어, pop을 할 수 있는 것이다. 단, 이 정도로 git stash
를 어렵게 쓰는 사람은 많이 없긴하다.
먼저 현재 ts
branch에 있는 html.txt
을 확인해보도록 하자.
html css javascript ruby
현재 ts
branch에 있는 html.txt
을 stash
에 넣어보도록 하자.
git stash
Saved working directory and index state WIP on ts: 5757ff1 add html.txt
다음으로 html.txt
code를 바꿔보도록 하자.
html css javascript ruby
ruby
를 추가한 것을 볼 수 있다. 이 내용을 stash
에 넣도록 하자.
git stash
이제 stash에 stack처럼 변동사항들이 쌓였을 것이다.
git stash list
stash@{0}: WIP on ts: 5757ff1 add html.txt
stash@{1}: WIP on ts: 5757ff1 add html.txt
한 번 pop을 하고 html.txt
파일을 열어봐.
git stash pop
at ./html.txt
html css javascript ruby
가장 최근에 넣은 stash data에 복구된 것을 볼 수 있다.
git stash list
stash@{0}: WIP on ts: 5757ff1 add html.txt
마지막으로 남은 stash를 복구해보도록 하자.
git stash pop
error: Your local changes to the following files would be overwritten by merge:
html.txt
Please commit your changes or stash them before you merge.
Aborting
The stash entry is kept in case you need it again.
충돌이 발생해서 실패한 것을 알 수 있다.
왜냐하면 현재의 html.txt
정보가 사라질 수 있기 때문이다. 이번 경우는 merge하지 않고, 이전 stash를 drop시켜버리도록 하자.
drop시키는 명령어는 git stash drop
을 사용하면 된다.
git stash drop
Dropped refs/stash@{0} (3a3d2189e34021cf7bc326d6ed380af69de41569)