前回(Day 44)は、提出前のコミット履歴をピカピカに整頓する
git rebase -i と autosquash による自動合体術を学びました。そして本日の【Day 45】から、いよいよ「第9部:トラブルシューティング&完全復旧術」が開幕します!
その第1弾として、Gitの持つ最も強力で、かつ最も誤解されやすいコマンド【究極の巻き戻しツール(git reset 3兄弟:soft, mixed, hard)】を徹底解説します!
30年選手のベテランエンジニアから、開発現場の切実な悩みが届いています:
「コミットした後に『あ、まだ単体テスト通ってないのにコミットしちゃった』とか『appsettings.Development.json に接続文字列のパスワードを書いたままコミットしてしまった』という事故がよくある。
SVNのRevertは単に作業中の未コミット変更を破棄するだけだったが、Gitの reset はコミット自体を取り消せると聞いた。
でも --soft, --mixed, --hard の3つがあって、どれを使うとせっかく書いたC#コードが消えてしまうのか、どれなら安全なのかが怖くて手が出せない!
それぞれの違いと、現場で安全に使うための判断基準を教えてほしい!」
その恐怖心、非常によく分かります!「reset」という単語の響きが「全消去」を連想させるため、多くのエンジニアが構えてしまいます。
しかし、Gitの「3つの領域(作業ツリー・ステージ・リポジトリ)」の仕組みさえ知ってしまえば、resetは決して恐ろしい破壊コマンドではありません。
むしろ、「間違えてコミットしたコードを1行も消さずに、安全にコミットだけを解体できる」という、SVN時代には夢にも思えなかった最強のセーフティネットなのです!
本日は、reset 3兄弟の違いを図解でスッキリ整理し、C#開発現場での実践シーン、そしてTortoiseGitでの安全な操作法まで完全伝授します!
① なぜresetが怖いのか?Gitの「3つの領域」とresetの本質
SVNユーザーがGitの reset で最も混乱する原因は、「SVNのRevert」と「GitのReset」の意味が全く異なる点にあります。
SVNの svn revert は「コミット前の未コミット作業コピーの変更を破棄する」コマンドでした。
一方、Gitの git reset は「過去に確定したコミット履歴を巻き戻す」コマンドです!
Gitには、Day 05 で学んだ以下の「3つの領域」が存在します:
- ① 作業ツリー(Working Tree): エディタやVisual Studioで実際にC#コードを編集しているファイル実体。
- ② ステージング領域(Staging / Index):
git addで登録した、「次のコミットに含める準備棚」。 - ③ リポジトリ(Git Directory / HEAD):
git commitで確定保存された、スナップショット履歴の保管庫。
💡 git reset の本質とは?
git reset の本質は、「HEAD(現在見ている最新コミットを指すポインタ)を、指定した過去のコミットへ移動させること」です。
そして、ポインタを過去へ移動させたとき、「取り残されたステージング領域と作業ツリーのファイルをどう扱うか?」によって、3兄弟(--soft, --mixed, --hard)の動作が分かれます!
② `git reset` 3兄弟の徹底比較!どこまで巻き戻すか?
reset には主に3つのオプションがあります。それぞれの違いと影響範囲を図解で比較してみましょう。
⚠️ 【最重要警告】--hard を使うときの絶対の注意点
--soft と --mixed は、作業ツリーのファイル(あなたが書いたC#コード)には一切手を触れません。そのため、コードが消える心配はゼロです。
しかし、--hard だけは作業ツリーの変更を過去のコミット状態に強制上書きします!
未コミットの変更があった場合、それはGitの履歴にも残っていないため、二度と復元できなくなります。
「作業中のコードを完全に捨て去りたい」という明確な意図がある場合を除き、普段のコミット取り消しでは --soft または --mixed を使うのが鉄則です!
③ C#開発現場での実践シーン:誤コミットからの安全な救出
開発現場で最もよくある「やらかし事故」と、git reset によるスマートな解決手順を見てみましょう。
シナリオ:appsettings.Development.json に平文パスワードを書いたまま誤コミット!
C#(ASP.NET Core)でローカル開発中、データベース接続文字列を appsettings.Development.json に書き込み、うっかり新機能コードと一緒にコミットしてしまったとします:
$ git commit -m "ユーザー登録ロジックの実装"
まだリモート(GitHub)に git push していない状態なら、慌てる必要はありません!
git reset --soft HEAD~1 を実行します:
$ git reset --soft HEAD~1
コマンドを実行すると、直前のコミットが解体され、変更されたファイル群はすべて「ステージング済み(Staged)」の状態で無傷で手元に残ります!
ここから、機密情報が含まれる設定ファイルだけステージから解除し、安全にコミットし直します:
$ git restore --staged appsettings.Development.json
# 機密ファイルを除いたクリーンな状態で再コミット!
$ git commit -m "ユーザー登録ロジックの実装(機密情報除外)"
このように、--soft を使えば、何百行と書いたC#のビジネスロジックは1ミリも消えず、コミットという「包装紙」だけを安全に開けて中身を詰め直すことができます!
④ TortoiseGit / GUI での直感的リセット操作
コマンドラインが苦手なWindows開発者や、視覚的に過去のコミットを確認しながら巻き戻したい場合は、TortoiseGit を使うと極めて直感的に操作できます。
🖱️ TortoiseGit でのリセット手順
- エクスプローラーでプロジェクトフォルダを右クリックし、[TortoiseGit] → [ログを表示] を開きます。
- 巻き戻したいコミット(HEADを移動させたい過去のコミット)を右クリックします。
- メニューから [このバージョンにリセット(Reset to this commit)...] を選択します。
- ダイアログが表示されるので、リセットの種類を選択します:
- Soft: 変更をインデックスに残す(コミットだけやり直し)
- Mixed: 変更を作業ツリーに残す(addからやり直し)
- Hard: すべて破棄(※変更が完全に消えるので注意)
- [OK] をクリックすれば、一瞬でHEADが指定位置へ巻き戻ります!
⑤ 現場の絶対鉄則:push済みコミットへのreset禁止とrevertとの使い分け
最後に、開発現場でチーム全員の平和を守るための「絶対の鉄則」を確認しましょう。
🌟 「reset」と「revert」のゴールデンルール
- まだプッシュしていない(ローカルの)コミット: 自由自在に
git resetで巻き戻してOK! - すでにプッシュした(GitHub / チーム共有の)コミット:
git resetは絶対禁止!Day 43で学んだgit revertを使う!
GitHubにプッシュ済みのコミットに対して git reset を行い、git push --force で歴史を強制上書きしてしまうと、そのブランチから派生して作業していた他のチームメンバーの環境で深刻なコンフリクトが発生します。
「自分の手元にあるうちは reset で完璧に磨き上げ、一度世に出した歴史は revert で紳士的に打ち消す」。
このルールさえ守っていれば、Gitで歴史事故を起こすことは絶対にありません!
📌 本日のまとめ(Day 45 理解のチェックポイント)
- resetの本質: HEADポインタを過去のコミットに巻き戻す操作である。
--soft: HEADだけ戻る。ステージも作業ツリーも無傷で残る(コミットやり直しの最強味方)。--mixed: HEADとステージが戻る。作業ツリーのコードは無傷(既定動作、addからやり直したい時)。--hard⚠️: HEAD・ステージ・作業ツリーすべて巻き戻す。未コミットの変更は二度と戻らないので厳重注意!- C#実践: 誤って機密ファイルを含めても、
--softで解体すればコードを失わずに再コミット可能。 - チーム鉄則: ローカルの試行錯誤は reset、プッシュ済みの歴史は revert で打ち消す!
次回【Day 46】予告:間違えて削除したコミットや hard reset から奇跡の生還?!
Git最後の命綱「コミット消失からの完全生還(git reflog)」をお届けします。お楽しみに!
コメント
コメントを投稿