こんにちは、エンジニアの西山です。

またクリエイターズブログの記事を書かせていただきます。

基本のGitの操作 commit, pull, push 等に慣れ作業を進めている時
本番サイトに反映した修正内容を、すぐ取り消して欲しいという要望も時にはあると思います。

修正ファイルや箇所が多く、急いで直している最中に限って
以下の事がよく起こります。

  • Slackでダイレクトチャットが飛んでくる
  • 隣の席の上司に声をかけられる
  • 先輩が息抜きにちょっかい出しにやってくる
  • 内線で呼び出される
  • 作業依頼をしていた方から質問を受ける
  • 別案件の緊急対応依頼

エンジニアあるあるですね。
どこまで直していたかを確認する為、時間を使い焦っていく。

そんな時に救ってくれるのが git revert です。

revert は リバートと読みます。
修正した内容を打ち消すコミットを行い、修正前の状態に戻してくれます。

早速、例を元に使っていきましょう。

■1. マージしていないコミットを打ち消し

テキストファイルを作成し
下記の内容を記載しコミットします。

コミットメッセージ 「太郎の最初のメッセージ」

僕は太郎です。花子さんが好きです。

文を追記し、コミットします。

コミットメッセージ 「花子さんと付き合えた」

僕は太郎です。花子さんが好きです。
花子さんと付き合うことになりました。

2行で付き合えるなら誰も苦労しませんね。
revert します。

まずは コミットの履歴を見ます。

Fumi-Mac:love fumi$ git log --graph
* commit 7a17b856e2af85b3d4b057614fdab832833748f1 (HEAD -> master)
| Author: Fumitaka Nishiyama <xxxxx@gmail.com>
| Date:   Thu Jan 24 02:25:52 2019 +0900
|
|     花子さんと付き合えた
|
* commit 4723d015c345e0dd0016bd91df69aced7db0f6f9
| Author: Fumitaka Nishiyama <xxxxx@gmail.com>
| Date:   Thu Jan 24 02:24:26 2019 +0900
|
|     太郎の最初のメッセージ
| 

「花子さんと付き合えた」というコミットのハッシュ値は
「7a17b856e2af85b3d4b057614fdab832833748f1」です。
打ち消したい内容であるこのハッシュ値を指定し、下記のコマンドを叩きます。

git revert 7a17b856e2af85b3d4b057614fdab832833748f1

ファイルを確認してください。「花子さんと付き合うことになりました。」という文が消えて
下記の状態になりました。

僕は太郎です。花子さんが好きです。

太郎は再び1人になりました。

■2. マージしたコミットを打ち消し

より実践的な例を見てみましょう。

実際の作業では修正用のブランチを作成し、修正内容をコミットします。
そして、本番反映時にブランチ「master」にマージするのがよく行われる流れかと思います。

ブランチ「master」から、ブランチ「hanako」を作成し
ブランチ「master」と、ブランチ「hanako」にそれぞれコミットを追加します。
最後に、ブランチ「hanako」を、ブランチ「master」にマージしました。

めでたく結ばれました。

全体のログ

Fumi-Mac:love fumi$ git log --graph
*   commit 46303cedb6e5ab634ee1f6b7f0ae28863d84868a (HEAD -> master)
|\  Merge: 88b202c a12f7c9
| | Author: Fumitaka Nishiyama <xxxxx@gmail.com>
| | Date:   Thu Jan 24 02:52:10 2019 +0900
| |
| |     Merge branch 'hanako'
| |
| * commit a12f7c9de1f18ac891e88d65c82453ae5acaee92 (hanako)
| | Author: Fumitaka Nishiyama <xxxxx@gmail.com>
| | Date:   Thu Jan 24 02:50:32 2019 +0900
| |
| |     花子コミット2
| |
| * commit 6a9bbbdf79c7d914ef214e614ca448aecedb899a
| | Author: Fumitaka Nishiyama <xxxxx@gmail.com>
| | Date:   Thu Jan 24 02:50:17 2019 +0900
| |
| |     花子コミット1
| |
* | commit 88b202c57a61f877a54fef5aeb4d31b850c25ebb
|/  Author: Fumitaka Nishiyama <xxxxx@gmail.com>
|   Date:   Thu Jan 24 02:48:15 2019 +0900
|
|       太郎コミット1

マージの箇所

*   commit 46303cedb6e5ab634ee1f6b7f0ae28863d84868a (HEAD -> master)
|\  Merge: 88b202c a12f7c9
| | Author: Fumitaka Nishiyama <xxxxx@gmail.com>
| | Date:   Thu Jan 24 02:52:10 2019 +0900
| |
| |     Merge branch 'hanako'

「88b202c」「a12f7c9」という2つの数字が記載されています。
これは親番号のハッシュ値です。
2つのブランチからマージされるので、それぞれの最後のコミットのハッシュ値の一部が記載されています。

ブランチ「master」の箇所

* | commit 88b202c57a61f877a54fef5aeb4d31b850c25ebb
|/  Author: Fumitaka Nishiyama <xxxxx@gmail.com>
|   Date:   Thu Jan 24 02:48:15 2019 +0900
|
|       太郎コミット1

ブランチ「hanako」の箇所

| * commit a12f7c9de1f18ac891e88d65c82453ae5acaee92 (hanako)
| | Author: Fumitaka Nishiyama <xxxxx@gmail.com>
| | Date:   Thu Jan 24 02:50:32 2019 +0900
| |
| |     花子コミット2

今回はブランチ「hanako」のマージを打ち消し
ブランチ「master」で「太郎コミット1」が反映されている状態にします。

現在のファイル内容

花子コミット1の内容です
花子コミット2の内容です
太郎です。
太郎コミット1の内容です

エラーになるリバート方法

git revert <マージコミット>

Fumi-Mac:love fumi$ git revert 46303cedb6e5ab634ee1f6b7f0ae28863d84868a
error: commit 46303cedb6e5ab634ee1f6b7f0ae28863d84868a is a merge but no -m option was given.
fatal: revert failed

ただマージコミットのハッシュ値を指定するだけでは
-m のオプションがないとエラーになります。

-m オプションが必要な理由

まず、「太朗コミット1」から「マージコミット」になった時に、どのような差がでているか確認します。

git diff <太郎コミット1> <マージコミット>

git diff 88b202c57a61f877a54fef5aeb4d31b850c25ebb 46303cedb6e5ab634ee1f6b7f0ae28863d84868a 

下記のように表示され、マージによりブランチ「hanako」の「花子コミット1」と「花子コミット2」により
文が2つ追加されているのが分かります。

+花子コミット1の内容です
+花子コミット2の内容です
太郎です。
太郎コミット1の内容です

実際にリバートをして説明いたします。
マージの箇所を確認します。

*   commit 46303cedb6e5ab634ee1f6b7f0ae28863d84868a (HEAD -> master)
|\  Merge: 88b202c a12f7c9
「補足」
88b202c の時は 1  ※ブランチ「master」のハッシュ値の一部 「太朗コミット1」
a12f7c9 の時は 2  ※ブランチ「hanako」のハッシュ値の一部 「花子コミット2」

git revert にオプション「-m」をつけ、ブランチ「master」の「太朗コミット1」の方を選ぶよう「1」を設定します。 マージコミットのハッシュ値「46303cedb6e5ab634ee1f6b7f0ae28863d84868a」を設定します。

リバートするコマンド

git revert -m 1 46303cedb6e5ab634ee1f6b7f0ae28863d84868a

実際にリバートした後のログを確認すると下記のようになります。

commit 9d9d9ece3d237065b87c81b963057a0ec069eb8d (HEAD -> master)
Author: Fumitaka Nishiyama <xxxxx@gmail.com>
Date:   Wed Feb 13 23:53:27 2019 +0900
Revert "Merge branch 'hanako'"
This reverts commit 46303cedb6e5ab634ee1f6b7f0ae28863d84868a, reversing
changes made to 88b202c57a61f877a54fef5aeb4d31b850c25ebb.

マージコミットとリバートコミットの差分を確認し
リバートでどのように変更されたか確認してみましょう。

git diff <マージコミット> <リバートコミット>

git diff 46303cedb6e5ab634ee1f6b7f0ae28863d84868a 9d9d9ece3d237065b87c81b963057a0ec069eb8d

リバートコミットにより、文が削除されているのが分かります。
マージにより追加された文が削除されています。

-花子コミット1の内容です
-花子コミット2の内容です
太郎です。
太郎コミット1の内容です

これにより、リバートとは
「マージコミット」と「戻すべきコミット」の差分を取得して、それとは逆のコミットを行うことが分かります。

その為、
「マージコミット」と「戻すべきコミット」との差分を取得するために
-m のオプションで、どのコミットが「戻すべきコミット」かを指定する必要があるのですね。

【マージをリバートするコマンド】

git revert -m <1や2等、戻すべきコミットを指定する数値> <マージコミット>

「参考」

例)git revert -m 1 46303cedb6e5ab634ee1f6b7f0ae28863d84868a
「マージの箇所」
*   commit 46303cedb6e5ab634ee1f6b7f0ae28863d84868a (HEAD -> master)
|\  Merge: 88b202c a12f7c9

これにより、ブランチ「hanako」のコミットが反映されていない状態になりました。
実際の業務で、ブランチ「master」にマージした修正ブランチの内容を打ち消した事と同様です。

あとがき

これで、基本のrevertの使い方を説明することができました。

git revert する時は緊急な時が多いので
コマンド1つで打ち消すことができて、感動しました!

私もこの記事を書くことによって、麻雀で負けた分を打ち消すことができました。
半荘が1回とは限らないのです。

以上、西山でした。