変更の取り消しと修正
git restore・git revert・git reset・git stash を使って、さまざまな段階の変更を安全に取り消す方法を演習問題で学びます。
このチュートリアルでは、「変更を取り消したい」というさまざまな場面に対応する Git コマンドを演習形式で学びます。取り消したい対象がどの段階にあるか(作業ツリー・ステージング・コミット済み)によって、正しいコマンドが変わります。
前提:
git initでリポジトリを作成済みで、基本的なコミット操作ができることを前提とします。
取り消しコマンドの全体像
作業ツリー ステージング コミット済み履歴
┌──────────┐ add ┌──────────┐ commit ┌──────────┐
│ 変更中 │ ────→ │ ステージ済 │ ────→ │ コミット │
└──────────┘ └──────────┘ └──────────┘
↑ git restore ↑ git restore --staged ↑ git revert / git reset
段階ごとに使うコマンドが異なる点を意識しながら進めましょう。
演習 1:ステージング前の変更を取り消す(git restore)
ファイルを編集したものの、やはり編集前の状態に戻したくなったとします。
問題: app.js を編集した後、git add する前に編集内容をすべて破棄して直前のコミット状態に戻すコマンドを書いてください。
答えを見る
git restore app.js出力例(git status で確認):
On branch main
nothing to commit, working tree cleangit restore <ファイル> は、作業ツリー上の変更を破棄し、直近のコミット(または後述の --source で指定したコミット)の内容に戻します。破棄した変更は元に戻せませんので、本当に不要な変更かを確認してから実行してください。
演習 2:ステージング済みの変更を取り消す(git restore —staged)
git add してしまった後に、やはりステージングを取り消したくなった場合を扱います。
問題: app.js を git add した後、ステージングだけを取り消して(作業ツリーの変更内容は残したまま)未ステージ状態に戻すコマンドを書いてください。
答えを見る
git restore --staged app.jsgit status で確認すると:
On branch main
Changes not staged for commit:
modified: app.js--staged を付けると、作業ツリーのファイル内容には触れず、ステージングエリアの状態だけを1つ前のコミット時点に戻します。ファイルの編集内容自体は消えません。
演習 3:直前のコミットを安全に取り消す(git revert)
すでにコミットして push もしてしまった変更を取り消したい場合を扱います。
問題: 直前のコミットの内容を打ち消す新しいコミットを作成するコマンドを書いてください(履歴は書き換えない)。
答えを見る
git revert HEADエディタが開き、自動生成されたコミットメッセージ(Revert "元のコミットメッセージ")を確認・保存すると、打ち消しコミットが作成されます。
a1b2c3d (HEAD -> main) Revert "ログイン機能を追加"
e4f5g6h 元のコミット: ログイン機能を追加git revert は既存の履歴を書き換えず、変更を打ち消す新しいコミットを追加します。すでに他の人と共有しているブランチでも安全に使えます。
演習 4:git reset の3モードを比較する
git reset にはブランチのポインタだけを動かす --soft、ステージングも戻す --mixed(デフォルト)、作業ツリーまで戻す --hard の3つのモードがあります。
問題: 以下の表の空欄(A・B・C)を埋めてください。
| モード | ブランチのポインタ | ステージングエリア | 作業ツリー(ファイルの中身) |
|---|---|---|---|
--soft | 移動する | (A) | 変わらない |
--mixed(デフォルト) | 移動する | 直前コミット時点に戻る | (B) |
--hard | 移動する | 直前コミット時点に戻る | (C) |
答えを見る
| モード | ブランチのポインタ | ステージングエリア | 作業ツリー(ファイルの中身) |
|---|---|---|---|
--soft | 移動する | 変わらない(コミット内容がそのままステージ済みとして残る) | 変わらない |
--mixed(デフォルト) | 移動する | 直前コミット時点に戻る | 変わらない(変更内容はファイルに残る) |
--hard | 移動する | 直前コミット時点に戻る | 直前コミット時点に戻る(変更内容は消える) |
# コミットは取り消すが、変更内容はステージ済みのまま残したい
git reset --soft HEAD~1
# コミットもステージングも取り消すが、ファイルの変更は残したい(デフォルト)
git reset HEAD~1
# コミットもステージングもファイルの変更もすべて取り消したい
git reset --hard HEAD~1⚠️
git reset --hardは変更を完全に失う危険な操作です
--hardを実行すると、コミットしていない変更やコミット自体が作業ツリーから消えます。実行前に本当に不要な内容か必ず確認してください。 誤って実行してしまった場合はgit reflogから復元できることがあります(詳しくは 08-recovery で扱います)。
演習 5:作業を一時退避する(git stash push / pop)
作業途中でコミットしたくないが、他の作業に切り替えたい場面を扱います。
問題: 現在の未コミットの変更(ステージング済み・未ステージング両方)を、メッセージ「ログイン機能の途中」付きで退避するコマンドと、退避した内容を最新の状態から復元するコマンドをそれぞれ書いてください。
答えを見る
# 退避する
git stash push -m "ログイン機能の途中"
# 一覧を確認する
git stash list
# stash@{0}: On main: ログイン機能の途中
# 最新の退避内容を復元する(リストからも削除される)
git stash popgit stash は変更を一時的にスタックへ積む仕組みです。コミットするほどではないが、作業ツリーをきれいな状態に戻したいときに使います。
演習 6:stash を使ってブランチを切り替えてから復元する
演習5をさらに発展させ、実際の業務でよくある「作業途中に別ブランチで緊急対応が必要になった」状況を再現します。
問題: 以下の手順を実行するコマンド列を書いてください。
- 現在の変更を退避する
hotfix/urgentブランチに切り替える- (緊急対応が終わったとして)元の作業ブランチ
feature/loginに戻る - 退避した変更を復元する
答えを見る
# 1. 現在の変更を退避
git stash push -m "feature/login の途中"
# 2. 緊急対応ブランチに切り替え
git switch hotfix/urgent
# ... 緊急修正してコミット ...
# 3. 元のブランチに戻る
git switch feature/login
# 4. 退避した変更を復元
git stash popこのように git stash を使うことで、コミットせずに未完成の変更を安全に保持したまま、別のブランチで作業できます。
まとめ
取り消したい対象の段階によって使うコマンドを整理します。
作業ツリーの変更を破棄したい → git restore <file>
ステージングだけ取り消したい → git restore --staged <file>
コミットを安全に打ち消したい → git revert <commit>
コミット自体をなかったことにしたい → git reset --soft/--mixed/--hard
作業を一時退避したい → git stash push / pop
「共有ブランチに push 済みかどうか」で revert(安全)と reset --hard(履歴改変)のどちらを使うべきかが変わる点を意識しましょう。