Git入門:バージョン管理のきほん
公開済みの履歴を安全に戻す(revert)
この回でやること
git revert で、すでに共有したコミットを安全に打ち消す方法を学びます。reset との使い分けの基準と、コンフリクトが起きたときの進め方まで身につけましょう。
- 読む 約 8 分
push したあとに、その変更が原因だと分かる
昨日送った変更が原因で、本番の検索結果が壊れている。手元だけの履歴なら無かったことにできますが、すでに送ってしまったものを消すと、自分の履歴だけが短くなって相手と食い違います。
git revert は履歴を消しません。代わりに、そのコミットと逆の変更をする新しいコミットを積みます。
プレーンテキスト
reset A --- B --- C → A --- B
revert A --- B --- C → A --- B --- C --- C'C' は、C で足した行を消し、C で消した行を足し直すコミットです。ファイルの中身は B の時点と同じに戻りますが、履歴には C も C' も残ります。
残ることが利点です。履歴は増えるだけなので、すでに C を受け取っている人の手元と矛盾しません。「いつ入れて、いつ止めたのか」も記録に残るので、原因を調べて入れ直す作業がやりやすくなります。
消さずに、逆の変更を 1 つ積む
打ち消したいコミットの名前を調べて渡します。
ターミナル
$ git log --oneline
9f1c0a4 検索フォームの並び順を変更
3b7d21e トップページの見出しを修正
$ git revert 9f1c0a4エディタが開き、Revert "検索フォームの並び順を変更" という下書きが表示されます。なぜ戻すのかを 1 行足してから保存して閉じてください。あとから読む人には、そこがいちばんの情報になります。
ターミナル
$ git log --oneline
7a5e3d1 Revert "検索フォームの並び順を変更"
9f1c0a4 検索フォームの並び順を変更
$ git push9f1c0a4 は消えていません。その上に打ち消しが積まれただけです。履歴を書き換えていないので、push に細工は要りません。
reset と revert のどちらを選ぶかは、基準が 1 つだけです。そのコミットを共有したかどうかで、まだ送っていないものは一覧できます。
ターミナル
$ git log --oneline origin/main..HEAD
9f1c0a4 検索フォームの並び順を変更origin はリモートリポジトリに付く既定の名前です。ここに出るものは、まだ自分の手元にしかありません。入っていれば reset を使ってよく、入っていなければ revert を選びます。打つ前にこの 1 行を見るだけで、履歴を壊す事故はほぼ防げます。
戻せない行があったら、手で決める
打ち消したい行が、そのあとのコミットでさらに書き換えられていると、Git は自動で戻せません。
プレーンテキスト
CONFLICT (content): Merge conflict in src/search.js
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run "git revert --continue".慌てる必要はありません。ヒントに手順が書かれています。ファイルを開くと、現在の内容と戻したい内容が <<<<<<< と >>>>>>> で挟まれています。残すべき形に手で書き直し、その印の行を消し、git add してから git revert --continue を打ちます。
やめたくなったら git revert --abort で、始める前の状態に戻せます。この逃げ道があるので、revert は試してみて構いません。
打ち消すコミットを取り違えても慌てなくて大丈夫です。revert で積んだものも普通のコミットなので、それをさらに revert すれば元に戻ります。往復した記録が残りますが、それでいいのです。履歴が汚れるのを嫌って強制的に上書きするほうが、はるかに危険です。
作業中の変更を抱えたまま始めると、Git は手前で止まります。先にコミットするか
git stashで退避してから、もう一度打ってください。
git revertは履歴を消さず、逆の変更をする新しいコミットを積んで打ち消す- 選ぶ基準は共有済みかどうか。送る前なら
reset、送ったあとならrevert - ぶつかったら手で直して
git addし、--continue。やめるなら--abort