본문 바로가기

책/프로 Git

Git 도구-3 - Stashing

Stashing

Stash 명령을 사용하면 워킹 디렉터리에서 수정한 파일 만 저장한다.  다음 파일들을 보관한다.

  • Modified 이면서 Tracked 상태인 파일
  • Staging Area에 있는 파일

아직 끝나지 않은 수정사항을 스택에 잠시 저장했다가 나중에 다시 적용할 수 있다.

하던 일을 Stash하기

파일 두 개 수정하고 그 중 하나는 Staging Area에 추가한다.

$ git status
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  modified:   index.html

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   lib/simplegit.rb

 

이제 브랜치를 변경해야 하는데, 위 사항을 임시로 스택에 저장하기 위해 모두 Stash한다.

$ git stash
Saved working directory and index state \
  "WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")

 

위 명령을 한 후 git status를 하면 깨끗해졌다.

$ git status
# On branch master
nothing to commit, working directory clean

 

git stash list로 저장한 Stash를 확인한다. (  이 상태에서 다른 브랜치로 이동이 가능하다. )

$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log

git stash apply 명령을 하면 가장 최근의 Stash(stash@{0}) 로 적용된다.

  • git stash apply stash@{2} 와 같이 적용할 stash를 명시할 수 있다.
$ git stash apply
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   index.html
  modified:   lib/simplegit.rb

no changes added to commit (use "git add" and/or "git commit -a")

 

Git은 Stash에 저장할 때 수정하던 파일을 복원해준다. 복원할 때의 워킹 디렉터리는 Stash할 때의 그 브랜치이고 워킹 디렉터리도 깨끗한 상태였다. 

 

하지만 항상 위의 상태가 아니더라도 Stash를 적용할 수 있다.

  • 어떤 브랜치에서 Stash하고 다른 브랜치로 옮기고서 거기에 Stash를 적용할 수 있다.
  • 워킹 디렉터리에 수정하고 커밋하지 않은 파일들이 있을 때에도 Stash를 적용할 수 있다. 만약 충돌이 나면 알려준다. 

Git은 Stash를 적용할 때 Staged 상태였던 파일을 자동으로 다시 Staged 상태로 만들어 주지 않는다. 그래서 git stash apply 명령을 실행할때 --index 옵션을 주어야 Staged 상태까지 적용한다. 

$ git stash apply --index
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  modified:   index.html

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   lib/simplegit.rb

 

apply 옵션은 단순히 Stash를 적용하는 것 뿐이다. Stash는 여전히 스택에 남아 있다.

 

git stash drop 명령을 사용하여 해당 Stash를 제거한다. 

$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
$ git stash drop stash@{0}
Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43)

 

그리고 git stash pop 이라는 명령도 있는데, Stash를 적용하고 나서 바로 스택에서 제거해준다.

Stash 되돌리기

Stash를 적용하고 나서 아차 싶을 때에는 다시 되돌려 놓아야 한다. Git은 stash unapply 같은 명령을 제공하지는 않는다. 하지만, Stash를 이용해서 패치를 만들고 그것을 거꾸로 적용할 수 있다.

$ git stash show -p stash@{0} | git apply -R

 

Stash를 명시하지 않으면 Git은 가장 최근의 Stash를 사용한다.

$ git stash show -p | git apply -R

 

stash-unapply라는 alias를 만들고 편리하게 할 수도 있다.

$ git config --global alias.stash-unapply '!git stash show -p | git apply -R'
$ git stash
$ #... work work work
$ git stash-unapply

Stash를 적용한 브랜치 만들기

보통 Stash에 저장하면 한동안 그대로 놔두고 그 브랜치에서는 계속 새로운 일을 한다. 그러면 저장한 Stash를 적용하는 것에 문제가 될 수 있다. 

  • 수정한 파일에 Stash를 적용하면 충돌이 날 수 있다.
  • 충돌이 나면 해결해야 한다. 
  • 그리고 Stash한 것은 다시 테스트해야 한다. 

git stash branch : Stash할 당시의 커밋을 Checkout한 후 새로운 브랜치를 만들고 여기에 적용한다. 이 모든 것이 성공하면 Stash를 삭제한다. 

$ git stash branch testchanges
M index.html
M lib/simplegit.rb
Switched to a new branch 'testchanges'
On branch testchanges
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  modified:   index.html

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   lib/simplegit.rb

Dropped refs/stash@{0} (29d385a81d163dfd45a452a2ce816487a6b8b014)