feature ブランチで作業中、リモートの develop が進んでしまった。
手元に未コミットの変更があるから git switch develop できない——この状況を git stash で切り抜ける手順の整理。
状況
ローカルの feature/foo で作業中。ワークツリーに未コミットの変更がある。
一方リモートの develop には他のメンバーのコミットが積まれていて、ローカルの develop は古いまま。
$ git status
On branch feature/foo
Changes not staged for commit:
modified: src/api/handler.ts
modified: src/utils/logger.ts
Untracked files:
src/api/newFile.ts
この状態で git switch develop すると怒られる。
$ git switch develop
error: Your local changes to the following files would be overwritten by checkout:
src/api/handler.ts
Please commit your changes or stash them before you switch branches.
手順
1. git stash で退避する
git stash -u -m "feat: handler refactoring WIP"
| オプション | 意味 |
|---|---|
-u (--include-untracked) |
新規作成ファイル(untracked)も退避対象に含める |
-m "..." |
stash にメッセージをつける。後で何の作業か分からなくなるのを防ぐ |
-uを忘れると新規ファイルがワークツリーに残る。develop に switch したとき意図しないファイルが紛れ込む原因になるので注意。
退避できたか確認する。
$ git stash list
stash@{0}: On feature/foo: feat: handler refactoring WIP
2. develop を最新にする
git switch develop
git pull origin develop
3. feature ブランチに戻って develop をマージ
git switch feature/foo
git merge develop
マージコンフリクトが起きたらこの時点で解消してコミットする。stash を戻すのはマージが完了してからにすること。順番を逆にするとコンフリクトが二重になって地獄を見る。
4. stash を戻す
git stash pop
pop は適用と同時に stash から削除する。適用だけして stash を残したい場合は git stash apply。
戻した時点でコンフリクトが起きることもある。その場合は手動で解消し、解消後に stash が自動削除されないので明示的に消す。
# コンフリクト解消後
git stash drop stash@{0}
stash 周りでよく使うコマンド
| やりたいこと | コマンド |
|---|---|
| 一覧を見る | git stash list |
| 中身を確認する | git stash show -p stash@{0} |
| 特定の stash を戻す | git stash pop stash@{1} |
| 全部消す | git stash clear |
rebase 派の場合
merge ではなく rebase で develop の最新を取り込みたい場合、stash を戻すタイミングは同じ。
git stash -u -m "WIP"
git switch develop
git pull origin develop
git switch feature/foo
git rebase develop # merge の代わり
git stash pop
rebase はコミット履歴が直線になる代わりに、push 済みのブランチだと --force-with-lease が必要になる。チームの運用ルール次第。
stash を使わない別解
退避せずに済ませたいなら、未コミットの変更を WIP コミットにしてしまう方法もある。
git add -A
git commit -m "WIP"
git switch develop
git pull origin develop
git switch feature/foo
git merge develop
git reset HEAD~1 # WIP コミットを取り消してワークツリーに戻す
git reset HEAD~1 で直前のコミットだけ巻き戻せるので、stash と実質同じことができる。こちらのほうが「今どのブランチに何が退避されてるか」を気にしなくて済む。