動画で読む
まず結論 — 復旧手順は「個人の記憶」ではなく「運用の一部」に置く
運用者としての結論を先に置きます。Git の操作ミスは「気をつける」では減りません。だから Issue 駆動でワークフローの動線を固定し、その横に「やらかしたときの戻し方」を Runbook(手順書)として並べておくのが一番安い。事故が起きてから手順を思い出すのではなく、事故る前から手順が決まっている状態にする、という順序の話です。
この線引きをきれいに書いてくれているのが、Zenn の penne_inc によるIssue 駆動 Git ワークフローとトラブルシューティングの記録です。標準フローを 5 ステップに固定したうえで、誤 commit / 誤 push / 誤 merge の 6 ケースそれぞれに復旧コマンドを対応させています。読みどころは個々のコマンドそのものより、事故を例外イベントではなく運用の想定内に入れている、その姿勢のほうです。
Issue 駆動ワークフローの 5 ステップ — main を汚さない動線を先に作る
まず動線を固定します。やることを Issue に落とし、ブランチを切り、コミットし、PR を出してマージする。この 5 ステップを毎回同じ順序で踏むだけで、main に直接コミットする事故の大半は構造的に起きなくなります。
penne_inc の記事はこの流れを次のコマンドで示しています。
git switch main && git pull --ff-only # 1. main を最新に
git switch -c feature/123-top-hero # 2. Issue 番号付きブランチを切る
git add -p # 3. 差分を見てからコミット
gh pr create --base main --fill # 4. push + PR 作成
gh pr merge --squash --delete-branch # 5. レビュー後にマージ
ブランチ名に Issue 番号を埋める(feature/123-...)のが地味に効きます。何のための変更か分からないブランチが 5 本溜まって、金曜の夜に「これは何だっけ」と git log を遡る。あの時間が消えます。私は要件を先に言葉にする派で、要件定義を「思想」と「仕様」に分けるに書いたとおり、何を作るかを Issue で固めてから手を動かすほうが手戻りが減ります。ブランチはその Issue の物理的な作業場所にすぎません。
「しまった」の 6 ケースと復旧コマンド — 焦ってからでは思い出せない
肝心の復旧です。先に分岐だけ言うと、push 前なら reset、push 後なら revert、消してしまったコミットは reflog か GitHub のログから SHA を拾って cherry-pick、と入口で分けると迷いません。記事の 6 ケースを運用 Runbook の形に並べ替えると、こうなります。
| やらかし | 状況 | 戻し方 |
|---|---|---|
| 関係ない変更を混ぜた | コミット前 | git stash push で退避し、後で stash pop |
| 違うブランチで作業した | コミット前 | git switch -c feature/x で変更ごと移動 |
| main にコミットした | push 前 | git reset --hard origin/main |
| main に push した | push 後 | git revert HEAD で打ち消しコミット |
| force push で他人の変更を消した | push 後 | GitHub Activity から SHA を見て cherry-pick |
| コミットメッセージを間違えた | push 前 | git commit --amend |
ここで一番大事なのは、push 前と push 後で道具が変わるという 1 点です。push 前はローカルだけの世界なので reset --hard で履歴ごと巻き戻してよい。push 後は他人(や別マシンの自分)が見た後かもしれないので、履歴を書き換えず revert で「打ち消した」という事実を 1 コミット足す。この境界を体に入れておくと、git push --force を反射的に打って事故る確率がぐっと下がります。
念のため自分の失敗も書いておきます。以前、reset --hard で戻したつもりが、別ターミナルでまだ走っていた処理の生成物まで巻き込んで消したことがありました。原因は私が「ローカルだから安全」と過信していたことです。reflog で直前の HEAD を拾って事なきを得ましたが、git reflog が「消えたコミットを当面のあいだ覚えている安全網」だと腹落ちしたのは、このときでした。
なぜ Runbook 化するのか — 焦っているときに人間は考えられない
理由を一言でいうと、事故った瞬間の人間は判断力が落ちていて、その場で正しいコマンドを組み立てられないからです。だから「考える」を事前に済ませ、当日は「引く」だけにする。これは Git に限らず運用全般の鉄則です。
私はブログの自動投稿パイプラインを回していますが、そこで先に作ったのも凝った自動化ではなく「失敗したとき何を見るか」のチェックリストでした。自動化の対象は勘ではなく測定で決めるに書いたとおり、何が起きるかを先に数えて手順に落としておくと、本番で詰まったときの復旧が速い。タスクの終わらせ方も同じで、タスクの完了は「状態を確定させる」ことで書いた「完了 = 状態が確定している」感覚は、Git でいえば「main が常に直近の正しい状態である」を守ることに当たります。復旧手順は、その状態を守るための保険です。
予防が一番安い — branch protection と pre-push hook
とはいえ最良の復旧は「事故らないこと」です。GitHub のブランチ保護(Require pull request before merging / Require linear history)を main に掛け、ローカルには pre-push hook で main への直 push を止める番犬を置く。この 2 枚があれば、上の 6 ケースのうち main 系の事故はそもそも発火しません。
# .git/hooks/pre-push(抜粋)main への直接 push を止める
while read local_ref local_sha remote_ref remote_sha; do
if [ "$remote_ref" = "refs/heads/main" ]; then
echo "main への直接 push は禁止です。PR を使ってください。"
exit 1
fi
done
ただし hook はあくまでローカルの番犬で、--no-verify で外せますし、clone し直した別マシンには付いてきません。だから本丸は GitHub 側のブランチ保護で、hook は「うっかりを手元で 1 回止める」補助、と役割を分けて考えるのが現実的です。どこまで仕組みで縛り、どこから人の注意に任せるかは、始める前に「やめ方」を決めるで書いた撤退基準の話と地続きで、全部を仕組みで縛ろうとすると今度は運用そのものが重くなります。
私ならどう運用に落とすか — 個人開発でも「想定内」にする
最後に方針を一つ。個人開発だからこそ、レビュアーも相方もいない分、事故の想定と復旧手順を自分の外(リポジトリや README)に置いておく価値が高いです。頭の中のローカル変数に持っていると、半年後の自分は確実に忘れています。
具体的には、リポジトリの CONTRIBUTING.md か README の末尾に、上の 6 ケース表をそのまま貼っておくだけでいい。凝ったツールは要りません。Issue で作業を定義し、ブランチで隔離し、PR でマージし、しくじったら表を見て引く。この一連を「自分一人のための運用ルール」として明文化しておくと、git push --force を打つ指が一瞬止まります。その一瞬が、金曜の夜に半泣きで reflog を漁る未来を防いでくれます。
よくある質問
- push する前のミスと push した後のミスで、戻し方はどう変わりますか?
- push 前はローカルだけの世界なので `git reset --hard` で履歴ごと巻き戻せます。push 後は他人や別マシンの自分が見た後かもしれないため、履歴を書き換えず `git revert` で打ち消しコミットを 1 つ足すのが安全です。この境界が復旧の入口になります。
- うっかり消してしまったコミットは取り戻せますか?
- 多くの場合は取り戻せます。ローカルなら `git reflog` で直前の HEAD の SHA を拾って `cherry-pick` や `reset` で復元できます。force push で消えたものは GitHub の Activity ログから SHA を確認して cherry-pick します。
- main への直接 push を仕組みで防ぐにはどうすればよいですか?
- GitHub 側のブランチ保護(Require pull request before merging / Require linear history)を main に掛けるのが本丸です。加えてローカルに pre-push hook を置くと手元で 1 回止められますが、hook は --no-verify で外せるため補助と位置づけます。
- 個人開発でも復旧手順を明文化する意味はありますか?
- あります。レビュアーがいない分、事故の想定と戻し方を自分の外(README や CONTRIBUTING.md)に置く価値が高いです。頭の中だけに持っていると半年後の自分が忘れるため、6 ケース表を貼っておくだけでも復旧が速くなります。