Gitの「戻す」には似た名前のコマンドがいくつもあり、間違えると作業が消えます。AIが直した内容を取り消したいときも、調べるほど reset や --force のような強そうな言葉が出てきて手が止まります。この記事では、料金表の修正を例に、状況ごとにどのコマンドを使うかを、実際に動かした表示つきで順に確かめます。読み終わると、今の状況で安全に戻す方法を自分で選べて、消えない操作と消える操作を区別できます。
この記事の内容
先に答えると
判断の分かれ目は「pushしたかどうか」です。pushはGitHubに送る操作で、送ったあとは他の人の手元にも同じ履歴が届いている可能性があります。送る前なら履歴を巻き戻してかまいません。送ったあとは、打ち消す変更を新しく足します。
- コミット前の変更を捨てるのは
git restore。捨てた変更は戻せません - pushしていないコミットを直すのは
git commit --amendとgit reset - pushしたコミットを取り消すのは
git revert。履歴が残るので安全です - 間違って消したコミットや枝は
git reflogで探して取り戻せます - Gitで戻るのはGitが管理しているファイルだけで、公開中のサイトやデータベースは別に反映が要ります
状況別の早見表
| 戻したいこと | 使うコマンド | 消えるもの | push後 |
|---|---|---|---|
| 保存(コミット)前の変更を捨てる | git restore menu.html | その変更。戻せない | 関係なし |
git add を取り消す | git restore --staged menu.html | なし | 関係なし |
| 直前のコミットを直す | git commit --amend | なし。作り直しになる | 使わない |
| 前のコミットを打ち消す | git revert コミット | なし。履歴に足す | 使える |
| 手元のコミットを取り消して変更は残す | git reset --soft HEAD~1 | なし | 使わない |
| 手元のコミットを変更ごと捨てる | git reset --hard HEAD~1 | コミット前の変更すべて | 使わない |
| 特定のファイルだけ昔に戻す | git restore --source コミット menu.html | そのファイルのコミット前の変更 | 使える |
| 消した枝を取り戻す | git reflog のあと git switch -c | なし | 手元のみ |
HEAD は今いる場所のコミット、HEAD~1 はその1つ前です。例の料金表 menu.html は、次の履歴から始めます。
$ git log --oneline
908a31b 料金表を修正
06b31a7 問い合わせの電話番号を修正
e36e910 最初の版
先に3つの置き場所を知っておく
Gitの変更には手元の中だけで3つの段階があります。作業中のファイル、git add で選んだ「次のコミットに入れるもの」の置き場(ステージ)、コミットした履歴です。それぞれのコマンドは、どの段階を戻すかが違います。

コミット前に戻す:restore
和食の基本の料金を、手元で間違えて9,999円にした場面です。git restore は、作業中の変更を捨てて直前の状態に戻します。
$ git diff
diff --git a/menu.html b/menu.html
index f9030d7..a62f4e1 100644
--- a/menu.html
+++ b/menu.html
@@ -1,6 +1,6 @@
<h1>料金表</h1>
<table>
-<tr><td>和食の基本</td><td>6,200円</td></tr>
+<tr><td>和食の基本</td><td>9,999円</td></tr>
<tr><td>家庭の洋食</td><td>6,500円</td></tr>
</table>
<p>お問い合わせ: 03-0000-1111</p>
$ git restore menu.html
$ grep -n 和食 menu.html
3:<tr><td>和食の基本</td><td>6,200円</td></tr>
確認の表示は出ません。一度捨てると戻せないので、git diff で中身を見てから実行します。
古い記事では git checkout -- menu.html と書かれていることがあります。今でも動き、同じ結果になります。
addを取り消す:restore –staged
git add . を実行したら、入れてはいけない .env(APIキーなどの設定ファイル)まで選ばれた場面です。--staged をつけると選択だけが外れ、ファイルは消えません。
$ git status
On branch main
Your branch is up to date with 'origin/main'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: .env
modified: menu.html
$ git restore --staged .env
$ git status
On branch main
Your branch is up to date with 'origin/main'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: menu.html
Untracked files:
(use "git add <file>..." to include in what will be committed)
.env
直前のコミットを直す:commit –amend
コミットの題名を間違えた、ファイルを入れ忘れたというときに使います。pushする前に限ります。
$ git log --oneline -2
9df5a2a 洋食のなまえをなおす
908a31b 料金表を修正
$ git commit --amend -m "家庭の洋食の名前を修正"
[main 6c42cca] 家庭の洋食の名前を修正
Date: Sat Nov 7 09:33:10 2026 +0900
1 file changed, 1 insertion(+), 1 deletion(-)
$ git add style.css
$ git commit --amend --no-edit
[main 411a411] 家庭の洋食の名前を修正
Date: Sat Nov 7 09:33:10 2026 +0900
2 files changed, 2 insertions(+), 1 deletion(-)
create mode 100644 style.css
番号が 9df5a2a から 6c42cca、411a411 と変わりました。amendは元のコミットを書き換えるのではなく、新しいコミットを作って差し替えています。pushのあとに使えない理由はここにあり、送った履歴と手元の履歴が食い違います。
本題:revertとresetの違い
一番間違えやすいところです。2つとも「コミットを取り消す」と説明されますが、していることは逆方向です。
| revert | reset | |
|---|---|---|
| していること | 打ち消すコミットを足す | 枝の先端を前に動かす |
| 履歴 | 全部残る | 消えたように見える |
| pushしたあと | そのままpushできる | 拒否される |
| 向いている場面 | 共有済みのコミット | まだ手元だけのコミット |
revert:打ち消しを足す
洋食の料金を7,000円にしてpushしたあと、間違いに気づいた場面です。git revert は逆向きの変更をコミットにして足します。実行すると既定のメッセージの編集画面が開くので、そのまま保存して閉じます。
$ git log --oneline -3
9f963e8 洋食の料金を7,000円に修正
411a411 家庭の洋食の名前を修正
908a31b 料金表を修正
$ git revert HEAD
[main a617bd7] Revert "洋食の料金を7,000円に修正"
Date: Sat Nov 7 09:33:10 2026 +0900
1 file changed, 1 insertion(+), 1 deletion(-)
$ git log --oneline -3
a617bd7 Revert "洋食の料金を7,000円に修正"
9f963e8 洋食の料金を7,000円に修正
411a411 家庭の洋食の名前を修正
$ git push
To ../website.git
9f963e8..a617bd7 main -> main
間違えたコミットも、打ち消したコミットも残ります。To の行の ../website.git は、この記事で動かすために手元に作った練習用の送り先です。
GitHubのプルリクエスト(Pull Request、PR。枝を本筋に入れる確認依頼)でマージしたものなら、画面の下のほうにある「Revert」を押すと、打ち消しのプルリクエストが新しく作られます。それをマージすれば同じことになります。

reset:枝の先端を動かす
git reset は、枝の先端を前のコミットに動かします。3種類あり、違いは「捨てたコミットの変更をどこに残すか」です。
| 種類 | 履歴 | ステージ | 作業中のファイル | 使う場面 |
|---|---|---|---|---|
--soft | 戻る | 残る | 残る | コミットだけやり直す |
--mixed | 戻る | 空になる | 残る | 選び直してコミットする。指定なしのときもこれ |
--hard | 戻る | 空になる | 消える | 変更ごと捨てる |
「夏の教室を追加」をコミットした状態から、それぞれ動かします。--soft は変更がステージに残ります。
$ git log --oneline -2
19bef1e 夏の教室を追加
4f04141 和食の料金を6,300円に修正
$ git reset --soft HEAD~1
$ git status
On branch main
Your branch is up to date with 'origin/main'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: menu.html
コミットし直してから --mixed を試すと、変更はステージから外れて作業中のファイルに残ります。
$ git reset --mixed HEAD~1
Unstaged changes after reset:
M menu.html
--hard は変更も消えます。先に枝を作っておきます。
$ git branch backup-before-reset
$ git reset --hard HEAD~1
HEAD is now at 4f04141 和食の料金を6,300円に修正
$ grep -c 夏の教室 menu.html
0
$ git log --oneline -1 backup-before-reset
19bef1e 夏の教室を追加

pushしたあとにresetすると
pushしたコミットを手元でresetしてからpushすると、拒否されます。
$ git reset --hard HEAD~1
HEAD is now at 4f04141 和食の料金を6,300円に修正
$ git push
To ../website.git
! [rejected] main -> main (non-fast-forward)
error: failed to push some refs to '../website.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. If you want to integrate the remote changes,
hint: use 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Gitは「手元の履歴のほうが古い」と判断しています。ここで --force をつけて押し通す方法が検索で出てきますが、次の節のとおり危険です。pushしたものを取り消すならrevertを使います。
–hard と –force が危ない理由
git reset --hard は、コミットしていない変更を確認なしで消します。git push --force は、送り先の履歴を手元の内容で上書きします。外注エンジニアBが先にpushしたコミットがあっても消えます。
動かすと次のようになります。Bが「夏の教室を追加(Bの作業)」をpushしたあとに、それを知らない代表が強制的に送った場面です。
$ git push --force-with-lease
To ../website.git
! [rejected] main -> main (stale info)
error: failed to push some refs to '../website.git'
$ git push --force
To ../website.git
+ f09079d...4f04141 main -> main (forced update)
$ git log --oneline origin/main -2
4f04141 和食の料金を6,300円に修正
a617bd7 Revert "洋食の料金を7,000円に修正"
送り先からBのコミットが消えました。--force-with-lease は、最後に受け取ったあとで他の人がpushしていれば止める指定で、1回目はこれが効いています。ただし git fetch で受け取ったあとなら通ってしまうので、中身を見ずに実行すれば同じことです。
Bの手元にはコミットが残っていて、次にBがpushすると戻ってきます。
$ git fetch
From ../website
+ f09079d...4f04141 main -> origin/main (forced update)
$ git status -sb
## main...origin/main [ahead 2]
$ git push
To ../website.git
4f04141..f09079d main -> main
消したはずのコミットが他の人の手元から戻ることがあり、上書きされた人の作業はその人の手元にしか残りません。共有している枝を上書きする怖さはここにあります。やる前にすることは次の4つです。
- 枝を作る(
git branch backup-before-reset)。これだけで元の場所に戻れます git statusでコミットしていない変更がないか見る- 共有している枝なら、他の人に一言伝える
mainには使わない。自分だけの枝に限る
GitHubのブランチ保護を入れていれば、保護した枝へのforce pushは既定で止まります。ただしFreeの Organization の非公開リポジトリでは使えません(2026年11月時点)。
reflogで戻せる範囲
git reflog は、手元で枝の先端やHEADが動いた記録です。git log に出なくなったコミットも、ここには残っています。
$ git reflog -4
4f04141 HEAD@{0}: reset: moving to HEAD~1
19bef1e HEAD@{1}: commit: 夏の教室を追加
4f04141 HEAD@{2}: reset: moving to HEAD~1
19bef1e HEAD@{3}: commit: 夏の教室を追加
$ git reset --hard 19bef1e
HEAD is now at 19bef1e 夏の教室を追加
$ git log --oneline -2
19bef1e 夏の教室を追加
4f04141 和食の料金を6,300円に修正
消した枝も同じです。枝の先端だったコミットを探して、枝を作り直します。
$ git branch -D add-summer-class
Deleted branch add-summer-class (was 5b5a968).
$ git reflog -3
4f04141 HEAD@{0}: checkout: moving from add-summer-class to main
5b5a968 HEAD@{1}: commit: 夏の教室のお知らせを追加
4f04141 HEAD@{2}: checkout: moving from main to add-summer-class
$ git switch -c add-summer-class 5b5a968
Switched to a new branch 'add-summer-class'
戻せる範囲は次のとおりです。
| 状況 | 戻せるか |
|---|---|
| コミットしたあとresetやamendで見えなくなった | 戻せる |
| 枝を消した | 手元でコミットしていれば戻せる |
| コミットしていない変更を捨てた | 戻せない |
git add までしていた変更を捨てた | 運がよければ拾える |
| 別のPCでした操作 | 戻せない。reflogはそのフォルダだけの記録で、cloneしても引き継がれない |
| 記録が古い | 既定で90日、今の枝から外れたものは30日を過ぎると消える対象になる |
コミットしていない変更はreflogに残らないので、git reset --hard のあとは探す先がありません。例外は git add まで済んでいた内容で、次のように残っていることがあります。ファイル名も分からない断片なので、頼りにはしないでください。
$ git fsck --lost-found
dangling blob f9f844eaf1cd2e2719bb34112c83acb7d56bb290
$ git show f9f844e
<h1>サンプル料理教室</h1>
<p>addだけした案内文</p>
作業中のものは、捨てる前にコミットしておくのが一番の保険です。
ファイル1つだけ昔の版に戻す
料金表だけ以前の内容に戻したいときは、まず昔の版を git show コミット:ファイル名 で見ます。何も変わらないので安心して試せます。
$ git log --oneline -- menu.html
4f04141 和食の料金を6,300円に修正
a617bd7 Revert "洋食の料金を7,000円に修正"
9f963e8 洋食の料金を7,000円に修正
411a411 家庭の洋食の名前を修正
908a31b 料金表を修正
06b31a7 問い合わせの電話番号を修正
e36e910 最初の版
$ git show 06b31a7:menu.html
<h1>料金表</h1>
<table>
<tr><td>和食の基本</td><td>6,000円</td></tr>
<tr><td>家庭の洋食</td><td>6,500円</td></tr>
</table>
<p>お問い合わせ: 03-0000-1111</p>
合っていたら、--source でそのファイルだけ持ってきます。他のファイルと履歴はそのままです。
$ git restore --source 06b31a7 menu.html
$ git status --short
M menu.html
$ git add menu.html
$ git commit -m "料金表を電話番号の修正の時点に戻す"
[main 261d11a] 料金表を電話番号の修正の時点に戻す
1 file changed, 2 insertions(+), 2 deletions(-)
古い版に上書きしたのではなく、「古い内容にした」という新しいコミットを足す形なので、pushしたあとでも使えます。
Gitで戻るのは手元のファイルだけ
ここを勘違いすると、戻したつもりで何も戻っていないことになります。
| 対象 | Gitの操作で戻るか | 別に必要なこと |
|---|---|---|
| 手元のファイル | 戻る | なし |
| GitHubのリポジトリ | pushすれば戻る | revertしてpush |
| 公開中のホームページ | 戻らない | 反映の仕組みを動かす。手で置いているなら置き直す |
| データベースの予約データ | 戻らない | 別に取ったバックアップから戻す |
send_mail.py が送ったメール | 戻らない | お詫びと訂正を送る |
| GitHubに入れたAPIキー | 戻らない | キーを無効にして作り直す |
実際に運用していると、自動で反映されるサイトでも、反映が終わるまでは古い表示のままです。戻したあとは公開中の画面を開いて確かめます。

できないことと、その代わり
| できないこと | その代わり |
|---|---|
| コミットしていない変更を戻す | こまめにコミットする。捨てる前に枝を作ってコミットする |
| revertで履歴から内容を消す | 履歴に残るので、秘密の情報は別の対応が要る |
| 他の人の手元の履歴を消す | 消せない。共有した時点で手が届かないと考える |
| 別のPCのreflogを見る | そのPCで見る。GitHubのプルリクエストの枝なら「Restore branch」 |
.env をコミットしてからrevertしても、ファイルが消えるだけで中身は読めます。
$ git revert --no-edit HEAD
[main aa80234] Revert "設定を追加"
Date: Sat Nov 7 09:33:11 2026 +0900
1 file changed, 1 deletion(-)
delete mode 100644 .env
$ git show HEAD~1:.env
API_KEY=xxxxxxxx
よく詰まるところ
| 症状 | 原因 | 直し方 |
|---|---|---|
git restore で did not match any file(s) known to git | まだ一度も git add していない新しいファイル | git clean -n で確かめ、git clean -f で消す。消したファイルは戻せないので、必ず -n の一覧を見てから |
git reset --hard のあとも新しいファイルが残る | Gitが管理していないファイルは対象外 | 同じく git clean |
amendのあと ! [rejected] と出る | pushしたコミットを作り直した | 他の人が使っていない枝に限り、「–hard と –force が危ない理由」の4つを確かめてから git push --force-with-lease。main なら git reset --soft origin/main で変更を残して戻し、新しいコミットにする |
is a merge but no -m option was given | 合流のコミットはどちら側に戻すか指定が要る | git revert -m 1 コミット で、合流前の main 側に戻す |
revertしたマージをもう一度入れても Already up to date. | Gitは取り込み済みと判断する | 先に出したrevertをrevertしてから入れる |
古いコミットのrevertで CONFLICT | 後のコミットが同じ行か隣の行を変えた | 直すか git revert --abort でやめる |
最後の場合は、次のように出ます。
$ git revert 908a31b
Auto-merging menu.html
CONFLICT (content): Merge conflict in menu.html
error: could not revert 908a31b... 料金表を修正
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git revert --continue".
hint: You can instead skip this commit with "git revert --skip".
hint: To abort and get back to the state before "git revert",
hint: run "git revert --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
$ git revert --abort
AIに戻す作業を頼むときは、実行前に「どのコマンドを、なぜ使うか」を聞きます。--hard か --force が入っていたら、先に枝を作らせてから進めます。
次に読む
add、commit、pushの段階の話は「git add・commit・pushの違い:保存して送るまでの流れ」にあります。revertで出た競合は「コンフリクトの直し方:起きる理由と、解消の手順」で直せます。秘密の情報を入れてしまったときは「APIキーやパスワードをGitHubにpushしてしまったときの対応」を開きます。AIに作業させるときの進め方は「GitHub CopilotとClaude Code:AIでコードを書くときのGitの使い方」に続きます。