git stashでお困りですか?「一時保存した変更が消えた」「複数のstashの管理が難しい」「適用時にコンフリクト」といった悩みを抱えるエンジニアは多いものです。
実は、git stashは作業の中断と再開を自在にコントロールできる強力なコマンドです。この記事では、実務で本当に使えるgit stashの活用法を、豊富な実例とともに徹底解説します。
最後まで読むことで、git stashをマスターし、コンテキストスイッチ時間80%削減できるようになります。
🎯 この記事で学べること
- git stashの基本的な使い方と動作原理
- 実務で使える実践的なオプションとテクニック
- よくあるエラーの解決方法とトラブルシューティング
- チーム開発で役立つベストプラクティス
- 複雑な状況での応用的な使い方
📋 前提知識
- Gitの基本概念(リポジトリ、コミット、ブランチ)の理解
- コマンドラインの基本操作
- git add、git commit、git checkoutの基本的な使い方
読了時間: 約15分
難易度: (中級)
🚀 git stashとは?基本概念の理解
概要と役割
git stashは、現在の作業中の変更を一時的に退避(stash)するGitのコマンドです。コミットする準備ができていない変更を一時的に保存し、クリーンな作業ディレクトリに戻すことができます。
開発中によくある「今の作業を中断して別の作業をしなければならない」という状況で威力を発揮します。例えば、新機能の開発中に緊急のバグ修正が入った場合、現在の作業を一時退避してバグ修正を行い、その後元の作業に戻ることができます。
動作原理の図解
他のコマンドとの関係
関連コマンド | 役割 | 使い分け |
---|---|---|
git commit | 変更を履歴に記録 | 作業が完了した時 |
git checkout | ブランチ切り替え | stash後のクリーンな状態で実行 |
git reset | 変更を取り消し | 完全に破棄したい時 |
git branch | ブランチ操作 | stashからブランチ作成も可能 |
📝 基本的な使い方
コマンドの基本構文
git stash [サブコマンド] [オプション]
最もシンプルな使用例
# 基本形
git stash
# 実行例
$ git stash
Saved working directory and index state WIP on main: abc1234 Latest commit message
解説:
Saved working directory and index state
: 作業ディレクトリとインデックスの状態が保存されたことを示すWIP on main
: Work In Progress(作業中)を意味し、mainブランチでの作業であることを示すabc1234
: 退避時点の最新コミットのハッシュ値
よく使うオプション一覧
オプション | 説明 | 使用例 |
---|---|---|
-u, --include-untracked | 未追跡ファイルも含める | git stash -u |
-a, --all | 無視ファイルも含める | git stash -a |
-m, --message | メッセージを付ける | git stash -m "認証機能の途中" |
-p, --patch | 対話的に選択 | git stash -p |
🔧 実践的な使用例
ケース1: 緊急のバグ修正への対応
シナリオ: 新機能の開発中に、本番環境で緊急のバグが発見され、すぐに修正が必要になった。
# 1. 現在の状態を確認
$ git status
On branch feature/user-auth
Changes not staged for commit:
modified: src/auth.js
modified: src/components/LoginForm.js
Untracked files:
src/utils/validation.js
# 2. 作業を退避(未追跡ファイルも含む)
$ git stash -u -m "認証機能の実装途中"
Saved working directory and index state On feature/user-auth: 認証機能の実装途中
# 3. mainブランチに切り替えてバグ修正
$ git checkout main
Switched to branch 'main'
# 4. バグ修正を実施
$ vim src/api/users.js
$ git add src/api/users.js
$ git commit -m "fix: ユーザーAPI の null pointer エラーを修正"
# 5. 元のブランチに戻る
$ git checkout feature/user-auth
# 6. 退避した作業を復元
$ git stash pop
On branch feature/user-auth
Changes not staged for commit:
modified: src/auth.js
modified: src/components/LoginForm.js
Untracked files:
src/utils/validation.js
Dropped refs/stash@{0} (5d3e1f4...)
ポイント:
-u
オプションで未追跡ファイルも退避できる- メッセージを付けることで、複数のstashがある場合に識別しやすい
pop
を使うと適用と同時にstashから削除される
ケース2: 複数の作業を管理
シナリオ: 複数の機能開発を並行して進めており、それぞれの作業を切り替えながら進める必要がある。
# 1. 機能Aの作業を退避
$ git stash push -m "機能A: データベース接続部分"
# 2. 機能Bの作業を退避
$ git stash push -m "機能B: UIコンポーネントの実装"
# 3. stashリストを確認
$ git stash list
stash@{0}: On main: 機能B: UIコンポーネントの実装
stash@{1}: On main: 機能A: データベース接続部分
# 4. 特定のstashの内容を確認
$ git stash show stash@{1}
src/db/connection.js | 25 +++++++++++++++++++++++++
src/db/models.js | 15 +++++++++++++++
2 files changed, 40 insertions(+)
# 5. 詳細な差分を確認
$ git stash show -p stash@{1}
diff --git a/src/db/connection.js b/src/db/connection.js
index abc1234..def5678 100644
--- a/src/db/connection.js
+++ b/src/db/connection.js
@@ -1,3 +1,28 @@
+const mongoose = require('mongoose');
+
+const connectDB = async () => {
+ try {
+ await mongoose.connect(process.env.MONGODB_URI, {
+ useNewUrlParser: true,
+ useUnifiedTopology: true
+ });
+ console.log('MongoDB connected successfully');
+ } catch (error) {
+ console.error('MongoDB connection error:', error);
+ process.exit(1);
+ }
+};
...
# 6. 機能Aの作業を再開
$ git stash apply stash@{1}
ポイント:
- 複数のstashを管理する際は必ずメッセージを付ける
show
コマンドで内容を確認してから適用するapply
を使えばstashを残したまま適用できる
ケース3: 部分的なstash(対話モード)
シナリオ: 複数のファイルを変更しているが、一部の変更だけを退避したい。
# 1. 対話モードでstashを開始
$ git stash -p
diff --git a/src/app.js b/src/app.js
index abc1234..def5678 100644
--- a/src/app.js
+++ b/src/app.js
@@ -10,6 +10,8 @@ const app = express();
app.use(express.json());
app.use(cors());
+// 新しいミドルウェアを追加
+app.use(authMiddleware);
+
app.get('/', (req, res) => {
res.send('Hello World');
Stash this hunk [y,n,q,a,d,/,e,?]? y
diff --git a/src/config.js b/src/config.js
index bcd5678..efg9012 100644
--- a/src/config.js
+++ b/src/config.js
@@ -5,4 +5,5 @@ module.exports = {
port: process.env.PORT || 3000,
database: process.env.DATABASE_URL,
+ secretKey: process.env.SECRET_KEY,
};
Stash this hunk [y,n,q,a,d,/,e,?]? n
# 2. 結果を確認
$ git status
On branch main
Changes not staged for commit:
modified: src/config.js
対話モードのオプション:
y
– この変更をstashするn
– この変更をstashしないq
– 終了a
– このファイルの残りの変更をすべてstashd
– このファイルの残りの変更をすべてスキップ?
– ヘルプを表示
🔍 トラブルシューティング
エラー1: マージコンフリクト
エラー内容:
error: Your local changes to the following files would be overwritten by merge:
src/components/Header.js
Please commit your changes or stash them before you merge.
原因:
- stashを適用しようとした時に、現在の作業ディレクトリの変更と競合が発生
- 同じファイルの同じ箇所が変更されている
解決方法:
# 解決手順1: 現在の変更も退避
$ git stash
# 解決手順2: 元のstashを適用
$ git stash apply stash@{1}
# 解決手順3: コンフリクトが発生した場合は手動で解決
$ git status
On branch main
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: src/components/Header.js
# 解決手順4: ファイルを編集してコンフリクトを解決
$ vim src/components/Header.js
# 解決手順5: 解決したらaddする
$ git add src/components/Header.js
# 解決手順6: 最初に退避した変更を適用
$ git stash pop
エラー2: stashが適用できない
エラー内容:
error: cannot apply to a dirty working tree, please stage your changes
原因:
- 作業ディレクトリに未コミットの変更がある
- インデックスに追加された変更がある
解決方法:
# 方法1: 現在の変更をコミット
$ git add .
$ git commit -m "WIP: 一時的なコミット"
$ git stash apply
$ git reset HEAD~ # 必要に応じてコミットを取り消し
# 方法2: 現在の変更も退避
$ git stash
$ git stash apply stash@{1} # 目的のstashを適用
$ git stash apply # 先ほど退避した変更を再適用
エラー3: 誤ってstashを削除してしまった
エラー内容:
$ git stash drop
Dropped refs/stash@{0} (abc1234...)
# あっ、間違えた!
原因:
git stash drop
やgit stash clear
を誤って実行- 重要な変更が含まれていたstashを削除
解決方法:
# 解決手順1: 削除されたstashのハッシュを探す
$ git fsck --no-reflogs | grep commit
dangling commit abc1234567890abcdef1234567890abcdef12345
dangling commit def5678901234567890abcdef1234567890abcd
# 解決手順2: 各コミットの内容を確認
$ git show abc1234567890abcdef1234567890abcdef12345
# 解決手順3: 目的のstashが見つかったら復元
$ git stash apply abc1234567890abcdef1234567890abcdef12345
エラー4: インデックスの状態が復元されない
エラー内容:
$ git stash pop
# インデックスに追加していた変更が、追加されていない状態で復元される
原因:
- デフォルトではstashはインデックスの状態を保持しない
git add
した状態が失われる
解決方法:
# stash作成時に--indexオプションを使用
$ git stash --index
# または適用時に--indexオプションを使用
$ git stash apply --index
トラブル予防のチェックリスト
- [ ] stash前に必ず
git status
で状態を確認 - [ ] 重要な変更には必ず意味のあるメッセージを付ける
- [ ] 定期的に
git stash list
で不要なstashを整理 - [ ] 複数人で作業する場合はstashではなくブランチを使用
- [ ] 長期間放置されるような変更はコミットを検討
💡 ベストプラクティス
1. 意味のあるメッセージを付ける
推奨される方法:
# Good ✅
git stash push -m "feat: ユーザー認証機能の実装途中(バリデーション部分)"
git stash push -m "fix: API エラーハンドリングの改善(レスポンス形式統一前)"
避けるべき方法:
# Bad ❌
git stash
git stash push -m "WIP"
git stash push -m "一時保存"
理由: 複数のstashがある場合、メッセージがないと内容を把握するのが困難。後で見返した時に何の作業だったか分からなくなる。
2. チーム開発での活用法
- ルール1: stashは個人の作業管理ツールとして使用し、共有が必要な場合はブランチを作成
- ルール2: 1日以上放置されるような変更はstashではなくWIPコミットを推奨
- ルール3: ペアプログラミングやモブプログラミング時は、ドライバー交代時にstashを活用
3. 自動化とエイリアス設定
# ~/.gitconfig に追加する便利なエイリアス
[alias]
# stash関連のエイリアス
s = stash
sp = stash pop
sl = stash list
ss = stash save
sa = stash apply
sd = stash drop
# メッセージ付きstash
sm = "!f() { git stash push -m \"$1\"; }; f"
# stashの内容を確認してから適用
sshow = "!f() { git stash show -p stash@{${1:-0}}; }; f"
# 使用例
$ git sm "認証機能の実装途中"
$ git sl
$ git sshow 0 # stash@{0}の内容を表示
$ git sa stash@{0}
4. stashブランチの活用
# stashから新しいブランチを作成
$ git stash branch feature/new-feature
# これは以下の操作と同等
$ git checkout -b feature/new-feature
$ git stash pop
メリット:
- stashの内容を安全にブランチ化できる
- コンフリクトのリスクを減らせる
- チームメンバーと共有しやすくなる
📊 コマンドオプション完全リファレンス
主要オプション詳細
オプション一覧を展開
オプション | 長い形式 | 説明 | 使用例 |
---|---|---|---|
-u | --include-untracked | 未追跡ファイルも含める | git stash -u |
-a | --all | 無視ファイルも含める | git stash -a |
-m | --message | 説明メッセージを追加 | git stash -m "説明" |
-p | --patch | 対話的に選択 | git stash -p |
-k | --keep-index | インデックスを保持 | git stash -k |
-q | --quiet | 静かに実行 | git stash -q |
--index | – | インデックスの状態も復元 | git stash apply --index |
サブコマンド一覧:
サブコマンド | 説明 | 使用例 |
---|---|---|
push | 新しいstashを作成(デフォルト) | git stash push |
pop | stashを適用して削除 | git stash pop |
apply | stashを適用(削除しない) | git stash apply |
list | stashの一覧表示 | git stash list |
show | stashの内容表示 | git stash show |
drop | stashを削除 | git stash drop |
clear | すべてのstashを削除 | git stash clear |
branch | stashから新規ブランチ作成 | git stash branch <name> |
オプションの組み合わせパターン
目的 | コマンド例 | 効果 |
---|---|---|
完全な退避 | git stash -u -m "説明" | 未追跡ファイルも含めてメッセージ付きで退避 |
選択的退避 | git stash -p -k | 対話的に選択し、インデックスは保持 |
確認してから適用 | git stash show -p && git stash pop | 内容を確認してから適用 |
安全な適用 | git stash apply --index | インデックスの状態も含めて適用 |
🎯 実践演習
演習1: 基本操作の練習
課題: 複数のファイルを変更し、一部だけをstashして、別の作業を行った後に復元する
解答を見る
# 準備
$ echo "変更1" >> file1.txt
$ echo "変更2" >> file2.txt
$ echo "新規ファイル" > file3.txt
# 解答例
$ git add file1.txt # file1.txtだけをインデックスに追加
$ git stash -k -m "file2.txtとfile3.txtの変更を退避" # インデックスを保持してstash
$ git commit -m "file1.txtを更新" # file1.txtをコミット
$ git stash pop # 退避した変更を復元
解説:
-k
オプションでインデックスの内容(file1.txt)はstashされない- これにより、一部の変更だけを選択的に退避できる
- 実務では、関連性の低い変更を分離する際に有用
演習2: コンフリクト解決
課題: stash適用時にコンフリクトが発生した場合の対処
解答を見る
# 準備(コンフリクトを意図的に発生させる)
$ echo "元の内容" > conflict.txt
$ git add conflict.txt
$ git commit -m "conflict.txtを追加"
$ echo "stashする変更" > conflict.txt
$ git stash -m "conflict.txtの変更"
$ echo "別の変更" > conflict.txt
# 解答例
$ git stash apply
Auto-merging conflict.txt
CONFLICT (content): Merge conflict in conflict.txt
$ cat conflict.txt
<<<<<<< Updated upstream
別の変更
=======
stashする変更
>>>>>>> Stashed changes
# コンフリクトマーカーを手動で編集
$ vim conflict.txt # 適切な内容に修正
$ git add conflict.txt # 解決済みとしてマーク
$ git status # 状態確認
解説:
- コンフリクトは通常のマージと同じ方法で解決
- 解決後は必ず
git add
でマークする - 複雑な場合は、一度現在の変更もstashしてから対処する方法も有効
演習3: 高度なstash管理
課題: 複数のstashを作成し、特定のstashだけを選んで適用する
解答を見る
# 複数のstashを作成
$ echo "機能A" > featureA.txt
$ git stash push -m "機能A: 初期実装"
$ echo "機能B" > featureB.txt
$ git stash push -m "機能B: UI部分"
$ echo "バグ修正" > bugfix.txt
$ git stash push -m "緊急: バグ修正"
# stashリストを確認
$ git stash list
stash@{0}: On main: 緊急: バグ修正
stash@{1}: On main: 機能B: UI部分
stash@{2}: On main: 機能A: 初期実装
# 特定のstashの詳細を確認
$ git stash show -p stash@{2}
# 機能Aのstashだけを適用(削除しない)
$ git stash apply stash@{2}
# 不要なstashを削除
$ git stash drop stash@{0}
# または番号を指定して複数削除
$ git stash drop stash@{1}
$ git stash drop stash@{0}
解説:
- stashは新しいものから
stash@{0}
として番号付けされる - 特定のstashを操作する際は番号を指定
- 定期的な整理でstashスタックをクリーンに保つ
🔗 関連リソース
公式ドキュメント
関連記事
- git fetchの使い方完全ガイド2025年版
- git pullの使い方完全ガイド2025年版
- git pushの使い方完全ガイド2025年版
- git branchの使い方完全ガイド2025年版
- git mergeの使い方完全ガイド2025年版
- git rebaseの使い方完全ガイド2025年版
- Gitワークフロー戦略完全ガイド2025年版
次に学ぶべきコマンド
- git cherry-pick: 特定のコミットだけを取り込む
- git rebase -i: インタラクティブなリベースで履歴を整理
- git reflog: 操作履歴を確認して復元
📌 まとめ
この記事で学んだこと
- ✅ git stashの基本的な使い方と動作原理
- ✅ 実践的なオプションの活用方法
- ✅ よくあるエラーの解決方法
- ✅ チーム開発でのベストプラクティス
- ✅ 高度なstash管理テクニック
重要なポイントの再確認
- 基本: stashは一時的な退避のためのツール、長期保存には向かない
- 応用: メッセージ付きstashと選択的stashで効率的な作業管理
- 注意: コンフリクトに備えて、適用前に内容確認を習慣化
実務での活用チェックリスト
- [ ] 基本的な使い方をマスターした
- [ ] よく使うオプションを覚えた
- [ ] エラー対処法を理解した
- [ ] チームでのルールを確認した
- [ ] エイリアスを設定した
🚀 次のステップ
git stashをマスターしたら、次は他のGitコマンドとの組み合わせを学んでいきましょう。特にブランチ操作やマージ戦略と組み合わせることで、より柔軟な開発フローを構築できます。
実際のプロジェクトで積極的に使って、体で覚えていくことが上達への近道です。困ったときはこの記事に戻って、トラブルシューティングセクションを参照してください。
Happy Git Life! 🎉