【Git・GitHub操作ガイド】第4章 git stash・ git reset ・ git bisect:Git履歴を操るテクニック

本記事の目的

この記事では、Gitを使った開発でよくある「困った!」状況を解決するための、git stash, git reset, git bisectという3つの強力なコマンドを、初心者にも分かりやすく解説します。

開発の現場では、「作業の途中で、緊急の修正依頼が舞い込んできた」「間違ったファイルをコミットしてしまった」「いつの間にかバグが紛れ込んでいた」といった予期せぬ事態がつきものです。

これらのコマンドを使いこなせば、まるで時間を操るように、Gitの履歴を安全に整理したり、問題の原因を効率的に突き止めたりすることができるようになり、より安心して開発を進められるようになります。


目次

対象読者

本記事は、以下のような方を対象としています。

  • Gitの基本的な操作(add, commit, push)は覚えた、次のステップに進みたい方
  • 作業の中断やコミットの取り消しといった、実践的な操作にまだ自信がない方
  • 開発中に発生したバグの原因を、効率的に特定する方法を知りたい方

操作の概要

スタッシュ (stash): 「ちょっと待って!」という時に。

コミットはしたくないけれど、急用でブランチを切り替えたい。そんな時、やりかけの作業を一時的に「スタッシュ」に退避させて、作業ディレクトリを綺麗な状態に戻します。用事が済んだら、隠した作業を元通りに復元できます。

リセット (reset): 「今の、なし!」という時に。

直前のコミットに間違いを見つけた時など、コミットそのものを取り消して、過去の状態に戻るコマンドです。非常に強力ですが、歴史を書き換えるため、使い方には細心の注意が必要です。

バイセクト (bisect): 「原因は何処だ!」という時に。

いつの間にか発生したバグの原因が、どのコミットにあるのかを特定するためのデバッグツールです。Gitが「探偵」のように質問を繰り返して、原因となったコミットを自動で絞り込んでくれます。


コマンド別:使い方と利用シーン

1. git stash:作業の一時退避

概要

まだコミットしたくない変更を、一時的に退避させるためのコマンドです。作業ディレクトリとステージングエリアの変更を「スタッシュ(隠し場所)」に保存することで、ブランチをクリーンな状態に戻せます。これにより、現在の作業をコミットすることなく、別のブランチに切り替えて作業を続けることが可能になります。

利用シーン

機能Aの開発中に、緊急のバグ修正依頼が来た。Aの作業は中途半端でコミットしたくないが、バグ修正のためにブランチを切り替えたい。

実行手順

  1. 作業の途中で、変更が残っている状態だとします。
  2. git stash または git stash push -m "メモ" を実行して、現在の変更を退避させます。
# メッセージを付けてスタッシュする
git stash push -m "ユーザープロフィール画面の途中"

実行後、git status を見ると、作業ディレクトリが、直前のコミットの状態に戻っていることがわかります。

  1. これで心置きなくブランチを切り替え、緊急の作業を行えます。
# hotfixブランチに切り替える
git switch hotfix-branch
# ... バグ修正作業 ...
  1. 用事が済んだら、元のブランチに戻ります。
# 元のfeature/a-branchブランチに戻る
git switch feature/a-branch
  1. git stash list で退避させた作業の一覧を確認します。
stash@{0}: On feature/a-branch: ユーザープロフィール画面の途中
  1. git stash pop を実行して、退避させた作業を復元します。
# 最新のスタッシュを復元し、スタックから削除する
git stash pop

popは、復元と同時に退避リストからその内容を削除します。復元後もリストに残したい場合は git stash apply を使います。

コマンドの実行例:スタッシュを使った待避と復元

# feature/a-branchで作業中(index.htmlを編集中)
hogehoge@mac hello-world % git status   
On branch feature/a-branch
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:   index.html

no changes added to commit (use "git add" and/or "git commit -a")
hogehoge@mac hello-world %

# バグが発生したので、作業状態を待避
hogehoge@mac hello-world % git stash push -m "ホーム画面の途中"        
Saved working directory and index state On feature/a-branch: ホーム画面の途中

# 待避した内容を確認
hogehoge@mac hello-world % git stash list
stash@{0}: On feature/a-branch: ホーム画面の途中

# スタッシュしたファイルがないことを確認
hogehoge@mac hello-world % git status
On branch feature/a-branch
nothing to commit, working tree clean

# hotfix-branchをmainブランチをベースに作成
git branch hotfix-branch main
# hotifx-branchでの作業完了
... 中略
# 元のブランチに戻る
git branch feature/a-branch

# スタッシュしたファイルを復元する
hogehoge@mac hello-world % git stash pop 
On branch feature/a-branch
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:   index.html

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (2895c22c7b5e3fc8e4c7f350477e9cc9e02d9b7d)

# git statusでも確認
hogehoge@mac hello-world % git status
On branch feature/a-branch
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:   index.html

no changes added to commit (use "git add" and/or "git commit -a")
hogehoge@mac hello-world %

2. git reset:コミットの取り消しと履歴の書き換え

概要

ブランチのHEADを指定した過去のコミットまで移動させることで、コミットを取り消すコマンドです。オプションによって、取り消したコミットの変更をどのように扱うかが異なります。
  • 【重要】利用上の注意
    git resetはコミット履歴を書き換える(消し去る)破壊的な操作です。リモートリポジトリにプッシュしてチームで共有したコミットに対しては、原則として使用してはいけません。
    共有済みのコミットを打ち消す場合は、履歴を書き換えずに対象のコミットを打ち消す新しいコミットを作成する git revert を使用します。git resetは、まだプッシュしていないローカルのコミットを整理する目的で利用するのが安全です。

git reset --soft HEAD~1

概要: 直前のコミットを1つだけ取り消しますが、変更内容はステージングエリアに残します
利用事例:
  • コミットメッセージを間違えた。
  • セーブに含めるのを忘れたファイルがあった。
実行手順:
# 直前のコミットを取り消し、変更をステージングエリアに残す
git reset --soft HEAD~1

この後、ファイルを追加したり、正しいメッセージで再度コミット (git commit -m "正しいメッセージ") し直すことができます。

git reset --hard HEAD~1

概要:

直前のコミットを1つ取り消し、さらにそのセーブでの変更内容もすべてゴミ箱に捨ててしまいます

利用事例:
  • お試しで加えてみた変更が全く不要になったので、コミットごと綺麗さっぱり消したい。
実行手順:
# (危険) 直前のコミットと、その変更内容を完全に削除する
git reset --hard HEAD~1
【警告】

このコマンドは、取り消しができません。ファイルが完全に消えてしまうため、実行する前に本当にその変更が不要か、十分に確認してください。


3. git bisect:二分探索によるバグの特定

概要

「いつの間にかバグが入り込んでしまったけど、どのコミットが原因か分からない…」そんな時に、Gitが探偵のように犯人(バグの原因となったコミット)を見つける手伝いをしてくれるコマンドです。

利用シーン

  • 「昨日は動いていたのに、今日は動かない。この数十個のコミットのうち、どれが原因だろう?」という状況。

実行手順

  1. git bisect start で、特定プロセスを開始します。
  2. git bisect bad で、現在のコミット(バグがある状態)を「悪い」とマークします。
  3. git logなどで正常に動作していたコミットIDを調べ、git bisect good <コミットID> で「良い」とマークします。
# bisectセッションを開始
git bisect start

# 現在のコミットを"bad"(問題あり)とマーク
git bisect bad

# 正常だったことが分かっているコミットを"good"(問題なし)とマーク
git bisect good f4a1b2c
  1. Gitは自動で範囲内の中間地点のコミットに移動します。ここで、プログラムの動作を確認します。
  • もしバグが再現したら git bisect bad を実行。
  • もしバグが再現しなければ git bisect good を実行。
  1. 上記4.を何度か繰り返すと、Gitが自動で範囲を半分に狭めていき、最終的に「このコミットが最初にバグを発生させた」と原因のコミットを突き止めてくれます。
  2. 調査が終わったら、git bisect reset で元の状態に戻ります。

参考資料


まとめ

今回は、Gitを使った開発を効率化し、いざという時のトラブルに対応するための3つの便利なコマンドを紹介しました。

  • git stash: コミットにはまだ早い変更を一時的に退避させ、急なブランチ切り替えを可能にします。
  • git reset: まだ共有していないローカルコミットの間違いを、綺麗にやり直せます。
  • git bisect: いつの間にか紛れ込んだバグの原因を、Gitとの対話を通じて素早く特定できます。

これらのコマンドは非常に強力ですが、特にgit resetは履歴を書き換える操作であるため、チーム開発で使う際には注意が必要です。本記事で解説した利用シーンと注意点をしっかり守り、安全に使いこなしていきましょう。

さあ、あなたのMacを快適な開発環境にしましょう!!

SNSでもご購読できます。

コメントを残す

*