「あっ、コミットを間違えた」「変更を取り消したい」……でも、git reset と git revert のどちらを使えばいいのか分からない。そんなときに読んでほしい記事です。
この記事では、ブランチの切り方と、状況別の「戻し方」の使い分けを、実際に動かした出力つきで、一緒に整理していきましょう。実際に実行した出力をそのまま載せているので、安心して真似してみてください。所要時間は、読むだけなら約10分、練習用リポジトリで試すなら+15分が目安です。
この記事は、この1週間続けてきた連載の最終回です。これまでの記事は、記事一覧から読み返せます。
- 「戻したい」ときに最初に確認する3つの質問
- ブランチを切って、安全に試す手順
-
restore・revert・resetの違いと使い分け - 実行前に立ち止まりたい、危険なコマンド
まず結論:3つの質問で戻し方が決まる
| 質問 | 状況 | 使うコマンド |
|---|---|---|
| 1 | まだコミットしていない変更を捨てたい | git restore |
| 2 | コミットしたが、まだ自分の手元だけ(push前) | git reset |
| 3 | すでにpushして、他の人も見られる | git revert |
覚え方は、「履歴を書き換えてよいのは、自分しか知らないときだけ」です。共有済みの履歴を書き換えると、他の人の手元とずれて混乱の元になります。共有済みのときは、「取り消した」という新しいコミットを足す revert を使います。
準備:練習用リポジトリを作る
本番のリポジトリで試す前に、練習用で動きを確認しましょう。練習用なら、失敗しても何も困りません。次のコマンドで準備できます。
- 1
- 2
- 3
- 4
- 5
- 6
mkdir my-project && cd my-project
git init -b main
echo '# my-project' > README.md
echo 'print("Hello")' > app.py
git add .
git commit -m "初回コミット"この記事のコマンド出力は、Git 2.47.3 で実際に実行した結果です。出力は英語で表示していますが、日本語の環境では日本語で表示されることがあります。また、本記事で使う git switch と git restore は Git 2.23 以降のコマンドです。
ブランチを切る:本流を汚さずに試す
ブランチは、作業用の枝です。木の枝をイメージしてみてください。本流(main)から枝を分けておけば、失敗しても main には影響しません。新機能や「ちょっと試したい変更」は、先にブランチを切るのが基本です。
- 1
- 2
$ git switch -c feature/greeting
Switched to a new branch 'feature/greeting'switch -c の -c は create(作成)の意味で、作成と切り替えを同時にやってくれます。次は、ブランチの一覧と切り替えを試してみましょう。
- 1
- 2
- 3
- 4
- 5
- 6
$ git branch -v
* feature/greeting 3f15869 初回コミット
main 3f15869 初回コミット
$ git switch main
Switched to branch 'main'* が付いているのが、今いるブランチです。git switch - と書くと、直前のブランチに戻れます。
ブランチ名は、feature/greeting(機能追加)、fix/login-error(不具合修正)のように、種類/内容の形にしておくと一覧で分かりやすくなります。
戻し方①:restore(コミット前の変更を戻す)
ファイルを編集したけれど、やっぱり元に戻したい。そんなときの手段です。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
$ git diff
diff --git a/app.py b/app.py
index 2f9a147..f6ee80e 100644
--- a/app.py
+++ b/app.py
@@ -1 +1,2 @@
print("Hello")
+print("こんにちは")
$ git restore app.py
$ git status
On branch feature/greeting
nothing to commit, working tree cleangit diff で変更内容を確認してから、git restore app.py で戻しています。
コミットしていない変更は、Gitの履歴に残っていません。git restore で捨てたら、取り戻せません。実行前に、必ず git diff で中身を確認しましょう。
git add したファイルを「add前の状態」に戻したいときは、--staged を付けます。こちらは変更自体は消えません。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
$ git status -s
M app.py
$ git restore --staged app.py
$ git status -s
M app.pygit status -s の左の列がステージ済み、右の列が未ステージを表します。M が M に変わり、ステージだけが外れたことが分かります。
戻し方②:revert(取り消しの履歴を足す)
push済みのコミットを取り消すときは、revert を使います。履歴は消さず、「そのコミットを打ち消す新しいコミット」を足します。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
$ git log --oneline
ae1ff8f さようならを追加
65068e2 あいさつを日本語で追加
3f15869 初回コミット
$ git revert --no-edit HEAD
[feature/greeting e4be890] Revert "さようならを追加"
1 file changed, 1 deletion(-)
$ git log --oneline
e4be890 Revert "さようならを追加"
ae1ff8f さようならを追加
65068e2 あいさつを日本語で追加
3f15869 初回コミット--no-edit は、メッセージを自動で付ける指定です。さようならを追加 のコミットは残ったまま、その内容を打ち消す Revert コミットが追加されました。履歴が増えるだけなので、他の人の手元とずれる心配がありません。
戻し方③:reset(履歴を巻き戻す)
reset は、ブランチの位置を過去のコミットまで戻すコマンドです。戻した後の変更をどこに残すかで3種類あります。ここがいちばん混乱しやすいところなので、表と一緒に見ていきましょう。
| オプション | コミット | ステージ | ファイルの中身 |
|---|---|---|---|
--soft | 取り消す | 残る | 残る |
--mixed(既定) | 取り消す | 外れる | 残る |
--hard | 取り消す | 外れる | 消える |
練習用に、practice ブランチで「実験1」「実験2」の2コミットを作り、それぞれ試しました。HEAD~1 は「1つ前のコミット」の意味です。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
$ git log --oneline -3
2462be4 実験2を追加
d6a2f3d 実験1を追加
e4be890 Revert "さようならを追加"
$ git reset --soft HEAD~1
$ git status -s
M app.py--soft は、コミットだけを取り消し、変更はステージ済みのまま残します。「コミットメッセージを書き直したい」ときに便利です。
- 1
- 2
- 3
- 4
- 5
- 6
$ git reset HEAD~1
Unstaged changes after reset:
M app.py
$ git status -s
M app.pyオプションなしの --mixed は、ステージも外し、ファイルの変更だけを残します。
- 1
- 2
$ git reset --hard HEAD~1
HEAD is now at d6a2f3d 実験1を追加--hard は、ファイルの変更ごと消します。実験2の内容は、作業フォルダからも消えました。本番でやるとヒヤッとします。
間違えて reset --hard したときの救出方法
コミット済みの内容であれば、git reflog(HEADの移動履歴)から取り戻せます。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
$ git reflog -4
d6a2f3d HEAD@{0}: reset: moving to HEAD~1
2462be4 HEAD@{1}: commit: 実験2を追加
...
$ git reset --hard HEAD@{1}
HEAD is now at 2462be4 実験2を追加HEAD@{1} は「1つ前の位置」です。実験2が復活しました。ただし、これが使えるのはコミット済みの変更だけです。コミットしていない変更は、reflogにも残りません。
実行前に立ち止まりたい危険なコマンド
| コマンド | 何が起きるか | 実行前の確認 |
|---|---|---|
git reset --hard | 未コミットの変更が消える | git status で変更の有無を見る |
git restore ファイル名 | そのファイルの未コミット変更が消える | git diff で中身を確認する |
git clean -fd | Gitが管理していないファイルが消える | 先に git clean -n で確認する |
git branch -D | マージ前のブランチを強制削除する | ブランチ名とコミットを確認する |
git push --force | 共有ブランチの履歴を上書きする | 共有ブランチでは使わない |
git clean は、-n(ドライラン)なら実際には消しません。
- 1
- 2
$ git clean -n
Would remove memo.txtWould remove は「消すことになります」という意味で、まだ何も消えていません。
AIに編集を任せる前に、ブランチを切る
CursorなどのAIエージェントにファイルの編集を任せるときも、先にブランチを切って、今の状態をコミットしておくと安心です。Cursorのチェックポイントは、Gitとは別にローカルへ保存される仕組みです。やり直しの土台は、Gitの履歴に残しておきましょう。コミットメッセージの書き方はこちらです。
コミットメッセージを揃えるだけでチーム開発が楽になる話(Conventional Commits)
つまずきやすい点
ブランチを切り替えようとするとエラーになる
- 1
- 2
- 3
- 4
- 5
$ git switch feature/greeting
error: Your local changes to the following files would be overwritten by checkout:
app.py
Please commit your changes or stash them before you switch branches.
Aborting未コミットの変更が、切り替え先のブランチと衝突するときのエラーです。エラーが出るとドキっとしますが、メッセージをよく読めば、次にやることが書いてあることが多いです。コミットするか、stash(一時退避)します。
- 1
- 2
- 3
- 4
- 5
- 6
$ git stash push -m 作業中
Saved working directory and index state On main: 作業中
$ git switch feature/greeting
Switched to branch 'feature/greeting'
退避した変更は、元のブランチで git stash pop を実行すると戻ります。
「not fully merged」でブランチを削除できない
- 1
- 2
- 3
$ git branch -d feature/greeting
error: the branch 'feature/greeting' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D feature/greeting'mainに取り込んでいないコミットがあるという警告です。まず main に git merge で取り込めば、-d で消せます。取り込まずに消す覚悟があるときだけ、-D を使います。
コミットのIDを指定したら「a branch is expected」と出る
- 1
- 2
- 3
$ git switch efc78b9
fatal: a branch is expected, got commit 'efc78b9'
hint: If you want to detach HEAD at the commit, try again with the --detach option.switch はブランチ用です。過去のコミットを見るだけなら --detach を付けます。この状態(detached HEAD)のまま作業するなら、git switch -c 新しい名前 でブランチを作りましょう。
まとめ
- ブランチは、試す前に切る。
git switch -c 名前で作成と切り替えが同時にできる - 戻し方は3つの質問で選ぶ。コミット前は restore、push前は reset、push後は revert
-
reset --hardとrestoreは変更が消える。実行前にgit statusとgit diffを見る
まずは練習用リポジトリで、今日の流れを一度なぞってみてくださいね。手を動かしておくと、本番で慌てずに済みます。
この記事は、この1週間の連載の最終回です。最後まで読んでいただき、ありがとうございました。
関連する本・記事
本:『Go言語アンチパターン42問:悪い例→なぜ→直し方で、実務の落とし穴を見抜く』
Gitの操作に慣れてきたら、次は「書いたコードの質」を上げる段階です。この本は、悪い例・理由・直し方の3点セットで、実務で踏みやすい落とし穴を確認できる問題集です。Goを使う開発の方に向いています。
記事・本:
- メンバーがGoの書籍を書いたよ!『Go言語アンチパターン42問』:この本の紹介記事です
- 『思考を実装する技術:Obsidian × Cursorで、知の断片を価値に変える』:AIエージェントに編集を任せる前提で、メモと開発を結びつけたい方向けです
- biliotechまわりのKindle著書リスト:悩み別に探せる一覧です