
git reset と revert と restore の違い - コミットを安全に取り消す選び方
当サイトは Amazon.co.jp を宣伝しリンクすることで紹介料を得る手段を提供する、Amazonアソシエイト・プログラムの参加者です。価格・在庫はリンク先の最新情報をご確認ください。
「さっきのコミットを取り消したい」「このファイルだけ元に戻したい」と思ったとき、Gitにはgit reset、git revert、git restoreという名前の似たコマンドが並んでいて、どれを使えばよいのか迷います。選び方を間違えると、共有ブランチの履歴を壊したり、まだコミットしていない変更を失ったりします。この記事では、3つのコマンドがどの領域を動かすのかを対応表で整理し、push済みかどうかでの判断、場面別の早見表、間違えたときの復旧方法までを順に見ていきます。仕様の説明はGitの公式マニュアルを出典にし、出力例はgit version 2.52.0の一時リポジトリで実際に実行した結果です。
まず結論 - 3つのコマンドの役割
Gitの公式マニュアル(gitコマンド本体のページ)には、「Reset, restore and revert」という節があり、3つの違いが次のように説明されています。
| コマンド | 役割 | 履歴への影響 |
|---|---|---|
git revert | 指定したコミットの変更を打ち消す新しいコミットを作る | コミットが増える(過去は書き換えない) |
git restore | ワーキングツリーのファイルを、インデックスや別のコミットの内容に戻す。インデックスの復元もできる | ブランチは動かない |
git reset | ブランチの先端を動かして、コミットを足したり外したりする | 履歴が変わる |
判断の入口は次の3つの問いです。
- ファイルの中身だけを戻したいなら
git restore - まだ自分しか持っていないコミットを取り消すなら
git reset - すでに他の人と共有したコミットを取り消すなら
git revert
3つの領域と各コマンドが動かす場所
Gitで扱う状態は、次の3つの場所に分かれています。
ワーキングツリー インデックス HEAD とブランチ
(実際のファイル) (次のコミットの内容) (最新コミットへの参照)
app.txt ──git add──> app.txt ──git commit──> main -> a508fb0ブランチの実体は「特定のコミットを指す参照」で、コミットを取り消す操作の多くは、この参照をどこに向けるかの話です。参照やオブジェクトの仕組みはGitの内部構造(オブジェクトとpackfile)の解説で扱っています。
各コマンドが3つの領域のどこを変えるかをまとめると、次のようになります。
| コマンド | HEADとブランチ | インデックス | ワーキングツリー |
|---|---|---|---|
git reset --soft HEAD~1 | 動かす | 変えない | 変えない |
git reset --mixed HEAD~1(既定) | 動かす | 指定先に合わせる | 変えない |
git reset --hard HEAD~1 | 動かす | 指定先に合わせる | 指定先に合わせる(未コミットの変更は破棄) |
git reset --keep HEAD~1 | 動かす | 指定先に合わせる | HEADと指定先で違うファイルを更新。それらにローカルの変更があれば中止 |
git reset --merge HEAD~1 | 動かす | 指定先に合わせる | HEADと指定先で違うファイルを更新。addしていない変更は残す |
git reset -- app.txt | 動かさない | HEADの内容に戻す | 変えない |
git restore app.txt | 動かさない | 変えない | インデックスの内容に戻す |
git restore --staged app.txt | 動かさない | HEADの内容に戻す | 変えない |
git restore --staged --worktree app.txt | 動かさない | HEADの内容に戻す | HEADの内容に戻す |
git restore --source=HEAD~2 app.txt | 動かさない | 変えない | 指定コミットの内容に戻す |
git revert HEAD | 新しいコミットの分だけ進む | 更新する | 更新する |
git reset - ブランチの先端を動かす
ここからの出力は、次の3コミットを持つリポジトリで確認したものです。検証はgit version 2.52.0で行い、紙面の都合でhint:の行や一部の出力は省略しています。
$ git log --oneline
a508fb0 commit C
57d1928 commit B
30138d3 commit Agit resetにコミットを指定すると、現在のブランチの先端をそのコミットへ動かします。公式マニュアルによると、モードを省略した場合は--mixedとして動作し、操作の前にORIG_HEADへ元の先端が記録されます。違いは、インデックスとワーキングツリーをどこまで巻き戻すかです。
--soft: コミットだけ取り消す
ブランチだけを動かし、インデックスとワーキングツリーには触れません。コミットの内容はステージされた状態で残ります。
$ git reset --soft HEAD~1
$ git status --short
M app.txt
$ git log --oneline
57d1928 commit B
30138d3 commit Aそのままgit commitすれば作り直せるので、「直前の複数コミットを1つにまとめ直す」用途にも使えます。
$ git reset --soft HEAD~2
$ git status --short
M app.txt
$ git commit -q -m "squashed B and C"
$ git log --oneline
2b72cdf squashed B and C
30138d3 commit A--mixed: コミットとaddを取り消す(既定)
インデックスも指定先に合わせますが、ワーキングツリーは変更しません。変更内容は「addされていない変更」として手元に残ります。
$ git reset HEAD~1
Unstaged changes after reset:
M app.txt
$ git status --short
M app.txt--hard: 内容ごと捨てる
インデックスとワーキングツリーの両方を指定先に合わせます。
$ git reset --hard HEAD~1
HEAD is now at 57d1928 commit B
$ cat app.txt
A
BWARNING
--hardは、追跡しているファイルの未コミットの変更を破棄します。コミット済みの内容は後述のreflogで戻せますが、未コミットの変更はGitに記録が残らないため戻せません。実行前にgit statusで確認してください。
未追跡のファイルは、原則として--hardでは消えません。実際に試すとuntracked.txtは残りました。ただし公式マニュアルは「追跡ファイルの書き込みの邪魔になる未追跡のファイルやディレクトリは単に削除される」と明記しているので、絶対に残るわけではありません。
$ git status --short
M app.txt
?? untracked.txt
$ git reset --hard
HEAD is now at a508fb0 commit C
$ git status --short
?? untracked.txt未追跡のファイルを消したいときはgit cleanを使います。-nで対象を確認してから-fで実行すると安全です。
$ git clean -n
Would remove u.txt
$ git clean -f
Removing u.txt--keep: 手元の変更を守りながら戻す
--hardと同じようにコミットを取り消しますが、ローカルの変更がある場合の動きが違います。取り消す範囲に関係ないファイルの変更は残り、取り消す範囲で変わるファイルに変更があれば中止します。
# notes.txt を編集中に、notes.txt に関係ない「commit D」を取り消す
$ git status --short
M notes.txt
$ git reset --keep HEAD~1
$ git status --short
M notes.txt
$ cat notes.txt
keepme
localedit取り消す範囲にあるファイルを編集していた場合は、何も変更せずにエラーで止まります。
$ git status --short
M app.txt
$ git reset --keep HEAD~1
error: Entry 'app.txt' not uptodate. Cannot merge.
fatal: Could not reset index file to revision 'HEAD~1'.手元に作業中の変更があるときは、--hardよりも--keepのほうが事故を防げます。
--merge: 作業中の変更を残して衝突だけ片付ける
--mergeは、インデックスを指定先に合わせ、addしていない変更は残します。代表的な用途は、別のファイルを編集中にgit mergeがコンフリクトしたときの片付けです。
$ git merge --no-edit topic
Auto-merging app.txt
CONFLICT (content): Merge conflict in app.txt
Automatic merge failed; fix conflicts and then commit the result.
$ git status --short
UU app.txt
M notes.txt
$ git reset --merge
$ git status --short
M notes.txtマージの中止だけならgit merge --abortもあります。ただし公式マニュアルは、マージ開始時に未コミットの変更があった場合は元の状態を再現できないことがあるとして、マージ前にcommitかstashを済ませるよう勧めています。
パスを指定するreset
git resetにファイルのパスを渡すと、ブランチは動かず、インデックスの該当エントリだけが戻ります。公式マニュアルは、これをgit addの逆でありgit restore --stagedと等価だと説明しています。パス指定で--hardは使えません。
$ git reset app.txt
Unstaged changes after reset:
M app.txt
$ git reset --hard app.txt
fatal: Cannot do hard reset with paths.git revert - 打ち消すコミットを足す
git revertは、指定したコミットの変更を逆に適用する新しいコミットを作ります。過去のコミットは残るので、共有済みのブランチでも安全に使えます。公式マニュアルにあるとおり、実行時はワーキングツリーがクリーンである必要があります。
$ git revert --no-edit HEAD
[main 32aac5e] Revert "commit D"
Date: Mon Nov 9 10:00:00 2026 +0900
1 file changed, 1 deletion(-)
$ git log --oneline -3
32aac5e Revert "commit D"
f7c25bb commit D
a508fb0 commit C
$ git log -1 --format=%B
Revert "commit D"
This reverts commit f7c25bbb80404e645d0ac42e272ad8af82061325.ワーキングツリーに競合する変更があると、次のように拒否されます。
$ git revert --no-edit HEAD
error: Your local changes to the following files would be overwritten by merge:
app.txt
Please commit your changes or stash them before you merge.
Aborting
fatal: revert failed複数のコミットをrevertする
範囲を指定すると、新しいコミットから順に1つずつrevertコミットが作られます。HEAD~2..HEADはHEAD~2を含まない範囲である点に注意してください。
$ git revert --no-edit HEAD~2..HEAD
[main 32aac5e] Revert "commit D"
...
[main 71bee41] Revert "commit C"
...
$ git log --oneline -6
71bee41 Revert "commit C"
32aac5e Revert "commit D"
f7c25bb commit D
a508fb0 commit C
57d1928 commit B
30138d3 commit A1つのrevertコミットにまとめたいときは-n(--no-commit)を使います。変更はワーキングツリーとインデックスに入るだけなので、最後に自分でコミットします。
$ git revert -n HEAD~2..HEAD
$ git status --short
M app.txt
$ git commit -q -m "Revert commits C and D"
$ git log --oneline -3
e8fbd28 Revert commits C and D
f7c25bb commit D
a508fb0 commit Crevertでもコンフリクトは起こります。解決してgit addしたあとgit revert --continueで進めるか、git revert --skipでそのコミットを飛ばすか、git revert --abortで中止します。
$ git revert --no-edit HEAD~1
Auto-merging app.txt
CONFLICT (content): Merge conflict in app.txt
error: could not revert a508fb0... commit C
$ git revert --abortマージコミットをrevertする(-m)
マージコミットには親が2つあるため、どちらの親を基準に戻すのかを-mで指定します。指定しないとエラーになります。
$ git log --oneline --graph -5
* 1dd3f18 Merge branch 'feature'
|\
| * 4cbcb48 feature: add f1
* | 5414455 main: add m1
|/
* 22e1378 add base
* f7c25bb commit D
$ git log -1 --format='parents: %p'
parents: 5414455 4cbcb48
$ git revert --no-edit HEAD
error: commit 1dd3f1801891b7ed24a520d8b106079a1ed69a66 is a merge but no -m option was given.
fatal: revert failed親の番号は1から始まります。mainへマージしたコミットでmain側を残したいなら、1番目の親を指定します。
$ git revert --no-edit -m 1 HEAD
[main 9f7ca86] Revert "Merge branch 'feature'"
Date: Mon Nov 9 10:00:00 2026 +0900
1 file changed, 1 deletion(-)
delete mode 100644 feature.txtrevertしたマージを再度マージする時の落とし穴
マージのrevertでいちばん間違えやすいのがここです。revertで消えるのは変更の内容だけで、「featureをマージした」という履歴は残ります。公式マニュアルは、マージのrevertを「そのマージが持ち込んだツリーの変更を今後も望まないという宣言」だと説明し、以後のマージは、revertしたマージの祖先ではないコミットの変更しか持ち込まないと書いています。
実際にfeatureを再度マージしても、何も起きません。
$ git merge --no-edit feature
Already up to date.featureに修正コミットを足してからマージしても、持ち込まれるのは修正コミットの分だけで、元のfeature.txtは戻ってきません。
# feature に fix.txt を足すコミットを作ってから
$ git merge --no-edit feature
Merge made by the 'ort' strategy.
fix.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 fix.txt
$ ls
app.txt
base.txt
fix.txt
main.txtGit公式のhowto「revert a faulty merge」が示している対処は、ブランチをどう直したかで分かれます。
- 修正を上に積んだ場合: 先にrevertコミットをrevertし(revert of the revert)、そのあとでブランチをマージする
- コミットを作り直した場合(別のコミットとして再作成した場合): revertのrevertは不要で、そのままマージする
1つ目は、上の状態から元のrevert(9f7ca86)をrevertすると、消えていたファイルが戻ることで確認できます。
$ git revert --no-edit 9f7ca86
[main 269fbe0] Reapply "Merge branch 'feature'"
Date: Mon Nov 9 10:00:00 2026 +0900
1 file changed, 1 insertion(+)
create mode 100644 feature.txt
$ ls
app.txt
base.txt
feature.txt
fix.txt
main.txt順番としては、修正をマージする前にrevertのrevertを済ませるのがhowtoの手順です。その順番でもfeature.txtとfix.txtの両方が揃うことを確認しました。
git revert <revertコミット> # 消した変更を戻す
git merge feature # 修正分を取り込む2つ目は、コミットを作り直したfeature-v2をマージすると、そのまま内容が入りました。
$ git merge --no-edit feature
Already up to date.
$ git merge --no-ff --no-edit feature-v2
Merge made by the 'ort' strategy.
feature.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 feature.txtgit restore - ファイルの内容を戻す
git restoreは、ファイルの内容だけを扱い、ブランチを動かしません。公式マニュアルによると、復元元の既定は--stagedがあればHEAD、なければインデックスです。--sourceで別のコミットを指定でき、復元先は既定でワーキングツリーです。
git statusのヒントにも、restoreが案内として表示されています。
$ git status
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: app.txt
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: app.txt変更の破棄とaddの取り消し
# ワーキングツリーの変更を破棄する(add していない変更が失われる)
$ echo wip >> app.txt
$ git status --short
M app.txt
$ git restore app.txt
$ git status --short
# add を取り消す(ファイルの変更は残る)
$ git add app.txt
$ git status --short
M app.txt
$ git restore --staged app.txt
$ git status --short
M app.txt
# add した変更ごと破棄する
$ git restore --staged --worktree app.txt未追跡のファイルは復元の対象ではないのでエラーになります。一方、新しくaddしたファイルに--stagedを使うと、ファイルは残したまま未追跡に戻ります。
$ git restore u.txt
error: pathspec 'u.txt' did not match any file(s) known to git
$ git status --short
A n.txt
$ git restore --staged n.txt
$ git status --short
?? n.txt--sourceで過去のコミットから取り出す
特定のファイルだけを過去の状態にしたいときは--sourceを使います。--stagedを付けない場合は、ワーキングツリーだけが変わります。
$ git restore --source=HEAD~2 app.txt
$ git status --short
M app.txt
$ cat app.txt
Aインデックスにも反映したいときは、--staged --worktreeを両方付けます。
$ git restore --source=HEAD~1 --staged --worktree app.txt
$ git status --short
M app.txt注意: 追跡しているファイルが復元元のコミットに存在しない場合、そのファイルは復元元に合わせて削除されます。
git checkoutとの関係
git restoreはgit switchとともにGit 2.23で導入されました。リリースノートには、ブランチの切り替えとパスの取り出しという、git checkoutが1つで担っていた2つの役割を分けるためと書かれています。導入当初は実験的な扱いでしたが、Git 2.51で「no longer experimental」と宣言され、現行の公式マニュアルにも実験的という記載はありません。
git checkout -- app.txtで変更を破棄する書き方は今も動きます。Git 2.52のマニュアルで確認した限り、git checkoutに非推奨の記載はありません。
| やりたいこと | 従来の書き方 | 分割後の書き方 |
|---|---|---|
| ファイルの変更を破棄 | git checkout -- app.txt | git restore app.txt |
| 過去のコミットからファイルを取り出す | git checkout HEAD~2 -- app.txt | git restore --source=HEAD~2 --staged --worktree app.txt |
| ブランチを切り替える | git checkout feature | git switch feature |
なお、git checkout HEAD~2 -- app.txtのようにコミットを指定した形では、インデックスも更新されます。git restore --source=HEAD~2 app.txtだけではインデックスは更新されない点が異なります。
git switchなどの日常的なコマンドはよく使うGitコマンドとエイリアスにまとめています。
push済みかどうかで判断する
コミットを取り消す方法を選ぶ分かれ目は、そのコミットを他の人が持っている可能性があるかです。
| 状況 | 基本の選択 |
|---|---|
| まだpushしていない | git reset、git commit --amendで自由に直してよい |
| pushしたが自分だけが使うブランチ | git resetのあと--force-with-leaseでpushしてもよい |
| mainなどの共有ブランチ | git revertで打ち消しコミットを足す |
push済みのコミットをresetで消してからpushすると、fast-forwardできないので拒否されます。
$ git reset --hard HEAD~1
HEAD is now at 269fbe0 Reapply "Merge branch 'feature'"
$ git push origin main
To ../origin.git
! [rejected] main -> main (non-fast-forward)
error: failed to push some refs to '../origin.git'ここでgit pullすると、消したはずのコミットが戻ってきます。共有ブランチで履歴を書き換えると、他の人の手元との間で同じ問題が起きるので、共有ブランチではgit revertが基本です。rebaseの黄金律と同じ考え方で、詳しくはmergeとrebaseの使い分けでも解説しています。git commit --amendも新しいコミットを作り直す操作なので、push済みのコミットに対して使うと同じ扱いになります。
--force-with-leaseの位置づけ
どうしても履歴を書き換えてpushする場合は、--forceではなく--force-with-leaseを使います。公式マニュアルによると、リモートの参照がリモート追跡ブランチの値と一致するときだけ上書きを許可するオプションです。自分の知らないコミットが誰かに積まれていれば失敗します。
$ git push --force-with-lease origin main
To ../origin.git
+ 56b0d7a...269fbe0 main -> main (forced update)
# 他の人がリモートに push した後だと拒否される
$ git push --force-with-lease origin main
To ../origin.git
! [rejected] main -> main (stale info)
error: failed to push some refs to '../origin.git'ただし、これは「最後にfetchした時点から変わっていないこと」を確認しているだけです。git fetchを実行してしまうとリモート追跡ブランチが更新されるので、他の人のコミットを取り込んでいなくても、チェックは通ります。
$ git fetch -q origin
$ git push -n --force-with-lease origin main
To ../origin.git
+ b90a6c0...08b0ea2 main -> main (forced update)エディタなどがバックグラウンドでfetchする環境では、これが起こり得ます。--force-if-includesを併用すると、リモート追跡ブランチの先端を手元に取り込んだ形跡がreflogにない場合は拒否されます。
$ git push -n --force-with-lease --force-if-includes origin main
To ../origin.git
! [rejected] main -> main (remote ref updated since checkout)
error: failed to push some refs to '../origin.git'WARNING
--force-with-leaseは事故を減らすためのもので、共有ブランチの書き換えを正当化するものではありません。チームで保護ルールを設定している場合は、それに従ってください。
場面別の早見表
| やりたいこと | コマンド | 備考 |
|---|---|---|
| 直前のコミットメッセージを直す | git commit --amend -m "新しいメッセージ" | 未pushのときのみ |
| 直前のコミットにファイルを足す | git add forgot.txtのあとgit commit --amend --no-edit | 未pushのときのみ |
| addを取り消す | git restore --staged app.txt | ファイルの変更は残る |
| ファイルの変更を破棄する | git restore app.txt | 未addの変更は戻せない |
| addした変更ごと破棄する | git restore --staged --worktree app.txt | 復旧は難しい |
| ファイルを過去の状態に戻す | git restore --source=HEAD~2 app.txt | ワーキングツリーのみ変更 |
| 直前のコミットを取り消して内容をステージに残す | git reset --soft HEAD~1 | 未pushのときのみ |
| 直前のコミットを取り消して内容を未addで残す | git reset HEAD~1 | 未pushのときのみ |
| 直前のコミットを内容ごと捨てる | git reset --hard HEAD~1 | 実行前にgit statusを確認 |
| 複数のコミットを1つにまとめ直す | git reset --soft HEAD~2のあとgit commit | 未pushのときのみ |
| 間違えて今のブランチにコミットした | git branch topic/fixのあとgit reset --hard HEAD~1 | 先にブランチで内容を保存する |
| push済みのコミットを取り消す | git revert HEAD | 共有ブランチの基本 |
| push済みの複数コミットを取り消す | git revert HEAD~2..HEAD | -nで1コミットにできる |
| push済みのマージを取り消す | git revert -m 1 <merge> | 再マージ時の落とし穴に注意 |
| 未追跡のファイルを消す | git clean -nのあとgit clean -f | 消すと戻せない |
| 直前のresetを取り消す | git reset --hard ORIG_HEAD | 上書き前のみ。reflogのほうが確実 |
git restore .のようにディレクトリを指定すれば、配下の追跡ファイルをまとめて戻せます。未追跡のファイルはそのまま残ります。
間違えたときの復旧
reflogで戻る
git reflogは、ローカルリポジトリでブランチの先端やHEADが動いた履歴を記録しています。reset --hardで消えたように見えるコミットも、ここから戻せます。
$ git reset --hard HEAD~1
HEAD is now at 57d1928 commit B
$ git reflog -n 3
57d1928 HEAD@{0}: reset: moving to HEAD~1
a508fb0 HEAD@{1}: commit: commit C
57d1928 HEAD@{2}: commit: commit B
$ git reset --hard HEAD@{1}
HEAD is now at a508fb0 commit CHEAD@{1}はHEADの「1つ前の位置」を指します。reflogはローカルリポジトリごとの記録なので、自分の手元にしかなく、他の人の手元やリモートのreflogとは別物です。git commit --amendの前の状態も、reflogから戻せます。
$ git commit --amend -m "commit C (fixed message)"
$ git reflog -n 2
9e715fe HEAD@{0}: commit (amend): commit C (fixed message)
a508fb0 HEAD@{1}: reset: moving to HEADORIG_HEADで直前の操作を戻す
公式マニュアルによると、ORIG_HEADはgit am、git merge、git rebase、git resetといったHEADを大きく動かすコマンドが、実行前の位置を記録するための参照です。直前の操作を戻すだけならreflogを見なくても済みます。
$ git reset --hard HEAD~1
HEAD is now at 57d1928 commit B
$ git reset --hard ORIG_HEAD
HEAD is now at a508fb0 commit CORIG_HEADは次の操作で上書きされるので、複数の操作を挟んだ場合はgit reflogを使ってください。
reflogの保持期間
reflogのエントリには期限があります。git reflog expireの既定値は公式マニュアルで次のように定められています。
| 設定 | 既定値 | 対象 |
|---|---|---|
gc.reflogExpire | 90日 | reflogのエントリ全般 |
gc.reflogExpireUnreachable | 30日 | 現在のブランチの先端から到達できないエントリ(--amendやresetで外れたコミットなど) |
resetで消したコミットは到達できないほうに当たるので、目安は30日です。またgit gcは既定で2週間より古い到達不能オブジェクトをgit pruneの対象にします。reflogが残っている間はコミットが保護されるので、エントリが消えたあとのgcで削除されます。
復旧できないもの
| 失ったもの | 復旧の可否 |
|---|---|
| コミット済みの内容(reflogの期間内) | git reflogから戻せる |
| addしたが未コミットの内容 | ファイル名は失われるが、中身は救える場合がある(後述) |
| addしていないワーキングツリーの変更 | Gitからは戻せない |
git clean -fで消した未追跡ファイル | Gitからは戻せない |
| reflogの期限が切れてgcされたコミット | 戻せない |
一度でもaddした内容はオブジェクトとして保存されているので、git fsck --lost-foundで救えることがあります。ファイル名やディレクトリの情報は失われ、ハッシュ名のファイルとして残ります。
$ echo "staged only content" > lost.txt
$ git add lost.txt
$ git reset --hard
HEAD is now at a508fb0 commit C
$ git fsck --lost-found
dangling blob 594d2a13b62c67be0df3722830533d098a1b233a
$ cat .git/lost-found/other/594d2a13b62c67be0df3722830533d098a1b233a
staged only contentreset --hardの前に迷ったら、git stash push -uで未コミットの変更と未追跡のファイルを退避しておくと安全です。ただし、別のコミットの上に戻すときはコンフリクトすることがあります。実際にreset --hard HEAD~1のあとでgit stash popするとコンフリクトになりましたが、stashのエントリは残るので失われることはありませんでした。
まとめ
git revertは打ち消しのコミットを足す、git restoreはファイルの内容を戻す、git resetはブランチの先端を動かすresetの--softはコミットだけ、--mixedはaddまで、--hardはワーキングツリーまで巻き戻す。作業中の変更があるなら--keepが安全- マージのrevertは
-mで親を指定する。再度マージするときは、修正を積んだ場合に先にrevertのrevertが必要 git restoreはGit 2.23で導入され、Git 2.51で実験的な扱いが外れた。git checkoutも引き続き使える- 共有ブランチでは
git revertが基本。自分だけのブランチで書き換えるなら--force-with-leaseを使い、必要に応じて--force-if-includesも併用する - 誤操作の多くは
git reflogとORIG_HEADで戻せるが、addしていない変更やgit cleanで消した未追跡ファイルは戻せない
迷ったときは「ブランチを動かしたいのか、ファイルを戻したいのか」「そのコミットを他の人が持っているのか」の2点から考えると、選ぶコマンドが絞れます。
参考
- git-reset(Git公式マニュアル)
- git-revert(Git公式マニュアル)
- git-restore(Git公式マニュアル)
- git(Git公式マニュアル「Reset, restore and revert」)
- git-checkout(Git公式マニュアル)
- git-reflog(Git公式マニュアル)
- git-gc(Git公式マニュアル)
- git-push(Git公式マニュアル)
- git-clean(Git公式マニュアル)
- gitrevisions(Git公式マニュアル)
- Revert a faulty merge(Git公式howto)
- Git 2.23.0 リリースノート
- Git 2.51.0 リリースノート
- builtin: unmark git-switch and git-restore as experimental(gitのコミット)
- Declare both git-switch and git-restore experimental(gitのコミット)


