T-CREATOR

Git で特定のコミットを打ち消す!git revert の正しい使い方

Git で特定のコミットを打ち消す!git revert の正しい使い方

開発現場で「あっ、このコミット間違えた!」という経験はありませんか。バグを含むコードをマージしてしまったり、仕様変更で不要になった機能をコミットしてしまったりと、Git を使った開発では避けて通れない問題です。

そんな時に頼りになるのが git revert コマンドです。このコマンドを使えば、履歴を壊すことなく安全にコミットを取り消すことができます。特にチーム開発では、他の開発者に影響を与えずに問題のあるコミットを無効化できる、とても重要なコマンドなのです。

背景

Git における履歴管理の重要性

Git の最大の特徴は、プロジェクトの全ての変更履歴を詳細に記録し続けることです。この履歴管理により、いつ誰がどのような変更を行ったかを正確に追跡できます。

しかし、この履歴の扱い方を間違えると、チーム全体の開発に大きな混乱を招いてしまいます。特に共有リポジトリでは、履歴の一貫性を保つことが極めて重要になります。

以下の図は、Git の履歴管理の基本的な流れを示しています。

mermaidflowchart LR
    commit1[コミット A] --> commit2[コミット B]
    commit2 --> commit3[コミット C]
    commit3 --> commit4[コミット D]

    subgraph shared[共有リポジトリ]
        commit1
        commit2
        commit3
        commit4
    end

    shared --> dev1[開発者1のローカル]
    shared --> dev2[開発者2のローカル]
    shared --> dev3[開発者3のローカル]

コミット取り消しの様々な方法

Git でコミットを取り消す方法は複数存在します。主要な方法を整理すると以下のようになります。

方法履歴への影響使用場面安全性
git revert履歴を保持共有済みコミット
git reset履歴を改変ローカルのみ
git rebase履歴を書き換えローカルでの整理

この中で最も安全で推奨されるのが git revert です。なぜなら、既存の履歴を一切変更せず、新しいコミットとして取り消し操作を記録するからです。

git revert と git reset の違い

git revertgit reset の動作の違いを理解することは重要です。以下の図で、それぞれの動作を比較してみましょう。

mermaidflowchart TD
    subgraph original[元の状態]
        A1[コミット A] --> B1[コミット B]
        B1 --> C1[コミット C]
    end

    subgraph reset_result[git reset の結果]
        A2[コミット A] --> B2[コミット B]
        C2[コミット C<br/>削除される]:::deleted
    end

    subgraph revert_result[git revert の結果]
        A3[コミット A] --> B3[コミット B]
        B3 --> C3[コミット C]
        C3 --> R3[Revert C<br/>Cを打ち消すコミット]:::revert
    end

    classDef deleted fill:#ffcccc
    classDef revert fill:#ccffcc

git reset は履歴からコミットを削除してしまいますが、git revert は新しいコミットを作成して変更を打ち消します。この違いが、チーム開発での安全性に大きく影響するのです。

課題

誤ったコミットが本番環境に反映されてしまう問題

本番環境にデプロイされた後でバグが発見されることは、開発現場では日常茶飯事です。このような状況では、迅速かつ安全にコミットを取り消す必要があります。

特に以下のようなケースでは、緊急度が高くなります。

  • セキュリティホールを含むコードがデプロイされた
  • データベースに悪影響を与える処理が実行される
  • ユーザー体験を著しく損なう不具合が発生した

チーム開発での履歴改変によるコンフリクト

git resetgit rebase を使って履歴を改変すると、他の開発者のローカルリポジトリとの間で深刻なコンフリクトが発生します。

mermaidsequenceDiagram
    participant Dev1 as 開発者A
    participant Remote as リモートリポジトリ
    participant Dev2 as 開発者B

    Dev1->>Remote: git push (コミット C)
    Remote->>Dev2: git pull (コミット C を取得)

    Note over Dev1: git reset で<br/>コミット C を削除

    Dev1->>Remote: git push --force
    Note over Remote: 履歴が書き換わる

    Dev2->>Remote: git push
    Note over Dev2,Remote: コンフリクト発生!<br/>Dev2 にはまだコミット C が存在

このような問題を避けるためには、共有済みのコミットに対しては git revert を使うことが重要です。

安全なコミット取り消し方法の選択

開発者が直面する課題は、状況に応じて適切な取り消し方法を選択することです。判断を間違えると、以下のような問題が発生します。

  • チームメンバーの作業環境が壊れる
  • 重要なコミット履歴が失われる
  • マージコンフリクトが頻発する
  • デプロイプロセスが停止する

解決策

git revert コマンドの基本概念

git revert は、指定したコミットの変更内容と正反対の変更を新しいコミットとして作成します。これにより、元のコミットはそのまま履歴に残しながら、その変更を実質的に無効化できます。

基本的な動作原理を以下の図で説明します。

mermaidflowchart TD
    subgraph timeline[タイムライン]
        direction LR
        commitA[コミット A<br/>ファイル追加] --> commitB[コミット B<br/>バグ修正]
        commitB --> commitC[コミット C<br/>新機能追加]
        commitC --> revertC[Revert C<br/>新機能を削除]
    end

    subgraph changes[変更内容]
        original[+新機能のコード<br/>+テストファイル<br/>+ドキュメント]
        reverted[-新機能のコード<br/>-テストファイル<br/>-ドキュメント]

        original -.逆の変更.- reverted
    end

    commitC -.参照.- original
    revertC -.参照.- reverted

新しいコミットで変更を打ち消すメリット

git revert を使うことで得られるメリットは数多くあります。

履歴の透明性 全ての操作が履歴として記録されるため、後から「なぜこの変更が取り消されたのか」を追跡できます。

安全性 既存のコミットを削除しないため、他の開発者の作業に影響を与えません。

可逆性 revert 操作自体も後から取り消すことができます(revert の revert)。

履歴を保持しながら安全に取り消す方法

git revert の実行プロセスは以下のようになります。

mermaidstateDiagram-v2
    [*] --> 対象コミット特定
    対象コミット特定 --> コマンド実行
    コマンド実行 --> 変更内容確認
    変更内容確認 --> コンフリクト発生?: コンフリクト?
    コンフリクト発生? --> 手動解決: Yes
    コンフリクト発生? --> コミット作成: No
    手動解決 --> コミット作成
    コミット作成 --> [*]

このプロセスにより、安全かつ確実にコミットを取り消すことができます。

具体例

単一コミットの revert

最も基本的な使い方は、特定の一つのコミットを取り消すことです。

まず、取り消したいコミットのハッシュを確認します。

bashgit log --oneline

出力例は以下のようになります。

abc1234 新機能: ユーザー登録機能を追加
def5678 修正: ログイン画面のバグを修正
ghi9012 追加: データベーススキーマを更新

特定のコミット(例:abc1234)を取り消すには、以下のコマンドを実行します。

bashgit revert abc1234

このコマンドを実行すると、エディタが開いてコミットメッセージの編集画面が表示されます。

bashRevert "新機能: ユーザー登録機能を追加"

This reverts commit abc1234567890abcdef1234567890abcdef123456.

# メッセージを編集してください
# 'git commit --amend' でコミットメッセージを変更できます

メッセージを確認して保存すると、revert コミットが作成されます。

複数コミットの一括 revert

複数のコミットを一度に取り消したい場合は、範囲を指定して revert できます。

以下は、直近の 3 つのコミットを取り消す例です。

bashgit revert HEAD~2..HEAD

または、特定の範囲を指定する場合:

bashgit revert abc1234..def5678

複数のコミットを revert する際の注意点を整理しましょう。

指定方法動作用途
HEAD~2..HEAD直近 3 つのコミット最新の変更群を取り消し
abc1234..def5678指定範囲のコミット特定期間の変更を取り消し
--no-commit オプション一括で処理手動でコミット調整

--no-commit オプションを使用すると、各 revert をまとめて一つのコミットにできます。

bashgit revert --no-commit abc1234..def5678
git commit -m "複数の機能を一括で取り消し"

マージコミットの revert

マージコミットを revert する場合は、どちらの親コミットに戻すかを指定する必要があります。

mermaidflowchart TD
    main1[main: コミット A] --> merge[マージコミット M]
    feature1[feature: コミット B] --> merge
    feature2[feature: コミット C] --> merge
    merge --> main2[main: コミット D]

    subgraph parents[親コミット]
        parent1[親1: main ブランチ<br/>コミット A]
        parent2[親2: feature ブランチ<br/>コミット C]
    end

マージコミットの revert では、-m オプションで親を指定します。

bash# メインブランチ側に戻す場合(通常はこちら)
git revert -m 1 <マージコミットのハッシュ>

# フィーチャーブランチ側に戻す場合
git revert -m 2 <マージコミットのハッシュ>

どちらの親を選ぶかは、以下の基準で判断できます。

親 1(-m 1)を選ぶ場合:

  • フィーチャーブランチの変更をすべて取り消したい
  • メインブランチの状態に戻したい

親 2(-m 2)を選ぶ場合:

  • メインブランチの変更を取り消したい
  • フィーチャーブランチの状態に戻したい

revert の revert(取り消しの取り消し)

revert 操作を取り消して、元の変更を再び有効にすることも可能です。

bash# 最初に何かをrevert
git revert abc1234

# revert操作を取り消す(元の変更を復活させる)
git revert HEAD

このプロセスを図で表すと以下のようになります。

mermaidflowchart LR
    original[元のコミット<br/>機能A追加] --> revert1[Revert<br/>機能Aを削除]
    revert1 --> revert2[Revert Revert<br/>機能Aを再追加]

    subgraph state[コードの状態]
        state1[機能A有効] --> state2[機能A無効]
        state2 --> state3[機能A有効]
    end

    original -.対応.- state1
    revert1 -.対応.- state2
    revert2 -.対応.- state3

この機能は、一時的に機能を無効化して、後で再び有効にしたい場合に便利です。

まとめ

git revert の適切な使い分け

git revert を効果的に使うためには、以下の状況判断が重要です。

git revert を使うべき場面:

  • 共有リポジトリにプッシュ済みのコミット
  • 本番環境にデプロイ済みの変更
  • チームメンバーが既に pull している変更
  • 履歴を保持したい重要な変更

他の方法を検討すべき場面:

  • ローカルでのみ作業している変更
  • まだプッシュしていない間違い
  • 作業ブランチでの試行錯誤

正しい選択により、チーム全体の開発効率を大幅に向上させることができます。

チーム開発での注意点

チーム開発で git revert を使用する際は、以下の点に注意しましょう。

コミュニケーション revert 操作を行う前に、チームメンバーに影響を報告することが大切です。

コミットメッセージ なぜ revert を行うのか、明確な理由をコミットメッセージに記載しましょう。

bashgit revert abc1234 -m "セキュリティ脆弱性修正のため緊急revert"

テスト実行 revert 後は必ずテストを実行して、システムが正常に動作することを確認してください。

デプロイ計画 本番環境での revert は、デプロイ計画と合わせて慎重に実行しましょう。

git revert は Git における最も安全で信頼性の高いコミット取り消し方法です。履歴を保持しながら変更を無効化できるため、チーム開発では欠かせないコマンドといえるでしょう。適切に活用することで、安心して開発を進めることができます。

関連リンク