Git を1からやり直す(stash編)

Gitを1からやり直す(目次)

stash とは、「隠す」という意味。

作業中、まだコミットしていない状態で他のブランチで作業したいことがある。そういうとき、stashを使えば変更内容を一時的に退避させることができる。

コマンド 動作など
git stash 作業ツリーとインデックスをスタックに隠す(Untracked filesは含まれない)
git stash -u Untracked filesも含め、スタックに隠す
git stash apply (stash@{数字}) スタックに格納したものを取り出す
git stash pop (stash@{数字}) スタックに格納したものを取り出してスタックから削除
git stash list スタックのリストを表示
git stash drop (stash@{数字}) スタックの中の一つを削除
git stash clear スタックを空にする
git stash branch ブランチ名 (stash@{数字}) スタックに格納したものを取り出して新しいブランチを作る

Untracked files とは、作成してから一度も add されていないファイル。(stash@{数字})は、省略すると一番新しいものが選択されたことになる。

実際にやってみる。Gitリポジトリを作って、hello.txt というファイルを作り、'A' と書き込む。

$ git init
Initialized empty Git repository in /Users/略/stash/.git/

$ touch hello.txt
$ echo 'A' > hello.txt 

add して、 commit。

$ git add hello.txt 
$ git commit -m 'Initial commit'
[master (root-commit) 72b74fb] Initial commit
 1 file changed, 1 insertion(+)
 create mode 100644 hello.txt

新しく develop ブランチを切り、hello.txt に 'B' を追記。

$ git checkout -b develop
Switched to a new branch 'develop'
$ echo 'B' >> hello.txt 

新しいファイル new.txt を作成。

$ touch new.txt

$ git status
On branch develop
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:   hello.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    new.txt

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

変更が add されていない hello.txt と、Untracked files の new.txt がある状態。ここで、stash を実行。

$ git stash
Saved working directory and index state WIP on develop: 72b74fb Initial commit

$ git status
On branch develop
Untracked files:
  (use "git add <file>..." to include in what will be committed)

    new.txt

nothing added to commit but untracked files present (use "git add" to track)

$ git stashでは Untracked files は隠されないので、new.txt は残ったままになった。これも隠したいので、-uオプションをつけて実行。

$ git stash -u
Saved working directory and index state WIP on develop: 72b74fb Initial commit

$ git status
On branch develop
nothing to commit, working tree clean

作業ツリーがきれいになった。stash を2回やったので、リストはこうなっている。

$ git stash list
stash@{0}: WIP on develop: 72b74fb Initial commit
stash@{1}: WIP on develop: 72b74fb Initial commit

これをまた取り出すことは簡単だが、あえて違うブランチで取り出してみる。

新しく topic ブランチを切って、applyで取り出す。

$ git checkout -b topic
Switched to a new branch 'topic'

$ git stash apply
Already up to date!
On branch topic
Untracked files:
  (use "git add <file>..." to include in what will be committed)

    new.txt

nothing added to commit but untracked files present (use "git add" to track)

これで、new.txt が戻ってきた。次に、最初に隠した hello.txt への追記の方を取り出す。

$ git stash apply stash@{1}
On branch topic
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:   hello.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    new.txt

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

これで元通りになった。

このように、スタックに格納したものは違うブランチから取り出すこともできる。ただしコンフリクトが発生すると取り出すことができない。コンフリクトが起きそうなときは、stash したものを別ブランチに切り出すとよいだろう。

stash はたくさんやるとわかりにくくなるため、できれば stash したら忘れないうちに pop して、リストがあまり増えないようにしたい。


(参考)