【Git】特定のコミットまで戻す方法を初心者向けに丁寧に解説
はじめに
git を使って開発を進めていると、過去に行った作業をやり直したい場面が出てくるかもしれませんね。
たとえば「バグを修正したつもりが、かえって新しい不具合を増やしてしまった」というケースがあるでしょう。
こういった場合に便利なのが、特定のコミットまで戻すという操作です。
ただ、git にはさまざまなコマンドがあり、どれを使うのがベストなのか迷う方も多いのではないでしょうか。
初心者の方が戸惑わないように、まずは git のコミット履歴の考え方を整理し、次にどのコマンドを使ってどう戻すのかをステップを踏んで解説します。
この記事を読むとわかること
- 特定のコミットまで戻す目的とシーンが理解できる
git reset
とgit revert
の違いを把握できる- 巻き戻し作業における具体的なコード例と手順がわかる
- 実務で気をつけたい注意点を学べる
特定のコミットまで戻すとはどういうことか
コード管理ツールとして有名な git は、コミット単位で変更履歴を蓄積していきます。
そのため、どの時点でどのファイルがどのように変わったかをたどれるのが大きな特徴です。
いざミスが発覚したときに「2つ前のコミットで動いていた状態に戻したい」という需要は多くのプロジェクトで起こります。
特定のコミットまで戻すとは、文字通り git の履歴を遡り、問題が起きる前の状態を再現する行為を指します。
コミット履歴管理の概要
git のコミット履歴は、時系列でどんどん積み重なっていきます。
下記のように、最新のコミットが上に来る形で履歴を確認できます。
# 履歴を確認するには git log を利用 git log --oneline
--oneline
はコミットごとに短い要約表示をしてくれるオプションです。
実務では、履歴を確認しながら「どこに戻すのか」を決める流れが一般的ですね。
特定のコミットに戻すシーン
- バグの発生: あるコミットから新しい不具合が混入したため、そこ以前の状態にコードを戻したい
- 試験的な実装: 試験的なコードを入れたものの、思ったように進まず撤回したい
- リリース時の巻き戻し: リリース後に重大な不具合が見つかったので、安定していたコミットに戻す
これらはいずれも、過去の特定のポイントに戻す場面としてはよくあるケースです。
ただし、本当に過去に戻すのか、それともミス部分だけを取り消すのか、目的によって使うコマンドが異なる点がポイントです。
git で特定のコミットに戻す方法
一口に「戻す」と言っても、よく使われるコマンドには主に git reset
と git revert
の 2つがあります。
それぞれの使い方や実務での意図が少し違うので、用途に合わせて正しい方法を選ぶと良いでしょう。
git reset で履歴を巻き戻す
git reset
は、ブランチの先頭位置を指定したコミットに切り替えてしまうコマンドです。
たとえば以下のような履歴があったとき、C1 -> C2 -> C3 -> C4 (HEAD)
という 4つのコミットがあるとします。
# 現在の履歴(一番上が最新) C4 (HEAD) C3 C2 C1
ここで C2
のコミットに戻したい場合は、以下のようにします。
git reset --hard <C2 のコミットハッシュ>
実行後は、最新のコミットが C2
に変わります。
つまり C3
や C4
が無かったことになるイメージです。
注意点
git reset --hard
はローカルの作業ディレクトリを強制的に変更するため、未保存の変更が消える可能性がある- すでにリモートリポジトリにプッシュ済みのコミットを reset すると、共同作業のメンバーが混乱する場合がある
このため、共同開発の場面では git reset --hard
をむやみに使わないようにしましょう。
個人作業で「やり直し」が必要なときには便利ですが、実務ではメンバーと相談して進めるのが安全です。
git revert で特定コミットを打ち消す
一方で、git revert
は指定したコミットでの変更内容を逆向きの変更として再度コミットするコマンドです。
実行すると、新たなコミットが追加されて「変更内容を取り消す」という形になります。
例として、履歴上の C3
の変更を取り消すには次のようにします。
git revert <C3 のコミットハッシュ>
これにより、C3
の差分を無効化するコミットが新しく作られます。
git revert
の特徴は、履歴を残したまま不要な変更だけを反映除外できる点です。
注意点
git revert
は過去のコミット全体を取り消すので、1つのコミットの中に複数の変更が含まれていると一括で戻る- もし連続した複数のコミットを取り消したい場合は、複数回
git revert
を実行するか、revert
をまとめて適用するオプションを使う
実務ではすでに多くの人が使っているブランチに不具合が混入した場合、git revert
の方が安全に履歴を保てます。
逆に、まだ誰もプッシュ済みのコミットを見ていない場面などでは git reset --hard
を使ってスッキリさせる方法も検討されます。
コミットをやり直すときのポイント
特定のコミットまで戻す方法は分かりましたが、実際にやり直すときはどんな部分に気を配れば良いのでしょうか。
ここでは初心者の方が躓きやすいポイントをいくつか挙げます。
巻き戻し後の再コミット
git reset --hard
で戻したあと、そのまま新しいコミットを作成すると、元々の C3
や C4
の変更は消え去ったままになります。
一方、git revert
で取り消した場合は履歴に「打ち消しコミット」が追加されるため、後から差分を確認しやすいです。
他の開発者がリモートリポジトリで最新のコミットをすでに取得していると、reset による巻き戻しは衝突の原因になります。 共同開発では revert の方が安全な選択肢になることが多いです。
コミットメッセージの書き方
git revert
を使うと、自動的にメッセージ入力用の画面が起動します。
このとき、元のコミットメッセージが引用される形になるので、何を取り消したのかが分かるように丁寧にメッセージをまとめておくと便利です。
実務では「うまく動かないので revert しました」のような曖昧な内容ではなく、具体的に「不具合 #123 対応分を取り消した」など、プロジェクトの管理内容がわかるように記述すると良いでしょう。
リモートリポジトリの操作
もしローカルだけで完結するのであればあまり問題はありませんが、リモートリポジトリと同期する場面では要注意です。
git reset --hard
で履歴を変更した場合、git push --force
などを使って無理やりリモートに反映しないと整合性が取れません。
これは他のメンバーが作業中の場合に大きなトラブルを招きかねないため、組織で使う際には慎重な判断が必要です。
実務でよくあるケースと手順
ここでは、初心者の方が特に遭遇しやすい具体的なシナリオを例に見てみましょう。
バグ修正が失敗してしまったケース
bugfix
というブランチを作り、不具合修正のコミットをいくつか積み重ねた。- ところが、その修正が原因で別のバグが発生。
- まだこの
bugfix
は誰にもプルリクエストを送っていない状態。
このようなとき、まだ共有されていない作業であれば、git reset --hard <安定していたコミット>
を使ってブランチの先頭を戻してしまうのが手早いでしょう。
消えてしまったコードに後から一部だけ戻したい場合は、別のブランチを切って差分を手動で取り込むなど工夫することもあります。
リリース後に重大な問題が発覚
- すでにリモートリポジトリの
main
にコミットが取り込まれ、他メンバーも最新版を取得している。 - 大量のユーザーに配布済みで、すぐに不具合を止めたい。
こういう場合は、git revert <対象コミット>
で該当コミットの差分を打ち消すのが無難です。
reset では履歴が変わり、他メンバーの作業に影響するため大混乱につながる可能性があります。
revert なら履歴はそのまま残るので、「いつ」「誰が」「何を打ち消したのか」も明確です。
トラブルシューティング
巻き戻し作業に慣れていないと、いざ実行したあとに「思った状態に戻らない」「変更多すぎて把握できない」といった問題に直面しがちです。
ここでは、よくあるトラブルと対処法を挙げます。
コミットハッシュを間違えた
git log --oneline
や git log --graph
などのコマンドで、正しいコミットハッシュを再度よく確認しましょう。
1文字でも間違えると別のコミットに戻ってしまうことがあるので、コピー&ペーストを活用するのがおすすめです。
変更が完全に消えてしまった
git reset --hard
を使ってしまい、戻す前の変更が丸ごとなくなるケースがあります。
ローカルブランチであれば「何もプッシュしていない状態の変更は救えない」場合がほとんどなので注意が必要です。
万一に備えて、事前に別ブランチを作成しておく、stash
を使うなどして消失を防ぐ工夫をすると良いでしょう。
revert したが衝突が起こる
複数のコミットで同じファイルを編集していた場合、git revert
の適用時にコンフリクトが発生することがあります。
その際は通常のマージコンフリクトと同様、手動でファイルの内容を整合させてからコミットすれば解決です。
コンフリクトを避けるためにも、一度に大きすぎる変更を行うのではなく、小まめにコミットを分割しておくと後々の管理が容易になります。
まとめ
特定のコミットまで戻す方法は、git reset
と git revert
という 2 つの代表的なコマンドに分けられます。
- 個人のブランチで誰にも影響がない場面や、やり直しがはっきりしている場合は
git reset --hard
が簡単 - 不具合がみんなの作業にすでに統合されている場面や、履歴の保全が重要な場面では
git revert
が安全
いずれの方法も使い所を誤ると、取り返しのつかない混乱が生じる恐れがあります。
そのため、巻き戻しの操作を行う前には必ずコミット履歴を確認し、本当に戻したいコミットを見極めることが大切です。
使い方を理解しておくと、万が一のトラブルにすぐ対処できるため、チーム開発や個人プロジェクトでも大きな安心材料になるでしょう。
皆さんの開発現場でも、git の強力な履歴操作をうまく使って効率的に作業を進めてみてください。