RevertとBlameを使いこなして安全性の高い開発を推進しよう
前回の記事ではProtected Branchesの機能を使ってシンプルなGitHub Flowに権限管理の味付けをする方法を学びました。
今回はPull Request単位でのRevertやビジュアルなBlame機能について学びましょう。
GitHub Flowに従ってmasterにマージする前のコードレビューやCIを必須にした運用をしていたとしても、誤ったコミットをマージしてしまい、システムテスト時または本番環境にて問題になることは、珍しい話ではありません。
そんな時に行いたいのがコミットのRevert(巻き戻し)ですが、Pull Requestをベースとした開発を行っていると、このような時にも恩恵をこうむることができます。
Revertとは
Revertとはコミットの巻き戻しのことです。たとえば次のようなコードをコミットしたとします。print
の出力文字を変更しています。
- print("Hello world!")
+ print("こんにちはこんにちは")
このコードに問題があり、もとに戻したい時に行うのがRevertです。たとえば次のようなコミットを作り、元のコミットを打ち消すようなことをします。
- print("こんにちはこんにちは")
+ print("Hello world!")
この作業を補助する機能はGitだけでなく多くのバージョン管理システムに備わっていて、大抵の場合この機能の名前をRevertとしていることが多いです。Gitもその例に漏れません。例えば次のようなコマンドを実行することで、巻き戻しのコミットを作ることができます。これがRevertです。
$ git revert <コミットsha>
巻き戻したいコミットが1つの場合は特に難しいことはありませんが、もし複数のコミットに渡って巻き戻しをしたい場合にはどうなるでしょうか。
従来の場合
たとえば次のように、プロダクトの挙動を変更するコミットと、それに付随してテストコードの挙動を変えるコミットがあったとします。この例ではurl.js
というファイルにてデフォルトの都市名を変更していて、それに付随してテストコードであるurl_spec.js
を変更しています。
この要件をRevertしたい場合には、この2つのコミットを間違いなく巻き戻してやる必要があります。でないと、思わぬデグレードが発生する可能性が出てきます。
1人で開発している分にはこの巻き戻しも簡単です。この関連する2つのコミットを突き止めるのも容易ですし、間に無関係な変更が入っているということもありえません。
ところがソフトウェア開発は1人で行うものではありませんから、現実には、この2つのコミットの間に他人のコミットが入っていることがありえます。たとえば次のようなイメージです。
このようなケースの場合、ある特定の要件に係るコミットだけを正しく巻き戻そうとすると、コミット履歴を1つ1つ目で確認して、どのコミットを巻き戻すべきかを精査する必要が出てきます。ここで判断を誤ると、戻さなくても良いコミットまで戻してしまい、デグレードが起きる羽目になります。かと言って過去のある時点のコミットまですべて巻き戻してしまうと、必要のないコミットまですべて巻き戻ってしまいます。
Pull Requestを使っていると
Pull Requestベースで開発を行っていると、このようなケースに柔軟かつ迅速に対応できるようになります。
Pull Requestをマージすると、次のようにマージした履歴がPull Requestに表示されます。
この履歴の右端にRevertというボタンが有るのが分かるでしょうか。拡大すると次のようになります。
このボタンを押すと、Pull Request単位でRevertをすることができます。これはどういうことでしょうか。
先ほどの例でお見せしたように、ある要件に係るコミットをもれなく間違いなく巻き戻すためには、従来であれば目で確認する他ありませんでした。
Pull Requestを使って開発をしていると、この苦労をしなくて済むようになります。なぜならば、Pull Request自体にコミットが紐付けられているからです。
ですので、要件ごとにPull Requestを適切に利用して開発をしていれば、その巻き戻しはただRevertボタンを押すだけで良くなるのです。試しに押してみましょう。
すると、次のように新たに別のPull Requestが作られます。
このPull Request配下に作成されたコミットを見てみましょう。
先ほどのプロダクトコードとテストコードがともに巻き戻るようにコミットが作られているのがわかると思います。このように、Pull Requestベースで開発していると、その単位で巻き戻すのもこんなに簡単になります。
さらに、RevertコミットもPull Requestとして作られるので、この巻き戻しが本当に正しいかどうか、コードレビューとCIを実施できるというのも見逃せないメリットです。
Pull RequestをベースとしたGitHub Flowで開発していると、このように付随的なメリットもあることがお分かりいただけたかと思います。
特定のコード行の変更について調べる
Pull Requestを使っているとRevertも容易にできることがわかりました。
ソフトウェア開発をしていると、次のようなケースに出くわすことも多いかと思います。 たとえば、 − 障害が発生してしまい、原因追求をしないといけない − 調査の結果、特定のコードが原因であることがわかったが、なぜそのコードが作成されたかを知りたい
このようなケースに適合するのがBlameという機能です。
Blameとは
Blame自体はGitそのものに備わっているコマンドであり、特定のコード行についていつ誰が変更を入れたのか確認できるものです。リファレンスは英語になりますがこちらになります。
Blame(非難する、〜のせいにする)という言葉の本来の意味に近く、特定の変更が誰の責任に帰するものなのかを突き止める目的のコマンドです。
GitHub上で見るBlame
BlameはGitのコマンドですので、本来コマンドラインで使うものですが、GitHubはBlame用にUIを用意し、誰でも簡単にBlameの機能が使えるようにしています。
Atomプロジェクトを例にとってどんなUIなのか、何ができるのか見てみましょう。ここではcontext-menu-manager.coffee
というファイルを見てみます。
上記画面の右肩に"Blame"というボタンが見えます。このボタンを押すと、ビジュアルに確認することが可能です。押してみましょう。すると次のような画面になります。
このように、コード行毎にいつ誰が変更したのか、コミットメッセージと該当するSHAへのリンク付きで表示されます。Blameはさらにここから、特定のSHAに飛び、さらにそのSHAが生まれた原因まで遡ることも可能にします。
ここでは例として、6行目の{remote} = require 'electron'
を見てみましょう。コミットメッセージの"Use the new style of `remote`"というところがリンクになっていますのでクリックします。すると次のように、該当コミットの変更内容を確認できます。
複数ある変更のうち、真ん中あたりに該当のcontext-menu-manager.coffee
の変更が次のように見つかると思います。この変更をみると、当時どのような変更が追加されたのかが分かります。
さらに、このコミットにはPull Requestへのリンクも貼られています。先ほどのコミットメッセージの下部、ブランチ名の右に括弧つきでリンクがあります。
このリンクから、次のPull Requestまでたどり着くことができ、この変更が行われた当時の議論状況、テスト結果、デプロイ結果等々、あらゆる付帯情報を確認できます。このようにPull Requestベースで開発することのメリットは、Blameによってコードから原因追求をする際にも有効なのです。
このPull Requestを順に見ていくと、次のコミットログに突き当たります。このコミットこそが先ほどの変更を起こしたものになります。
SHAの左にある緑のチェックマークをクリックすると、当時のこのコミットに対するテスト結果を確認することもできます。次のようになります。
また、このPull Requestが最終的に誰によっていつマージされたのか、そしてマージされたときの最終的なテスト結果はどうだったのか、も次のように確認できます。
このような情報がBlameを使うことでコード行から遡って追求できます。Blameの威力がよく分かるかと思います。また同時にPull Requestをベースに開発や議論、CIを行っているとどれほど恩恵を得られるか、についてもよくわかっていただけたかと思います。
さらに、このPull Requestに対してRevertをすることで、このコード行にまつわる変更すべてを安全に巻き戻すことすら可能です(AtomのこのPull Requestに関しては皆さんには書き込み権限がないため、Revertボタンは見えていません)。
最近追加された機能
2017年1月、Blameにはさらに新しい機能が追加されました。これはその変更が加わるまえのリビジョンのファイルに遡ることができる機能です。
UI上は次のボタンを押すことで利用できます。
この機能を使うことで、特定ファイルの特定行の変更を過去に遡っていって原因追求することが可能になります。この機能は2017年2月現在GitHub.comのみで利用可能で、GitHub Enterpriseにおいてはv2.10以降(現在はv2.8)に利用可能になる予定です。
まとめ
Pull RequestをベースとしたGitHub Flowで開発をすることで、Revertも簡単にできること、またBlameを使って特定のコード行からPull Requestにさかのぼって原因追求することが可能なこと、などを見てきました。
GitHubの持つ強力な機能がよくご理解いただけたかと思います。ぜひ日々の開発にGitHub Flowを取り入れて、さらなる開発効率化、品質向上を目指しましょう!
さて次回はマージのオプションについてお話しします。
GitHubでは最近、従来のMerge Commitを介したマージ(--no-ff
マージ)に加えて、Squash mergeとRebase mergeをオプションとして加えました。
それぞれのマージオプション毎の違い、ユースケースなどを紹介します。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- これだけは押さえておきたいGitHub Flowの基礎
- Protected Branches機能で柔軟なワークフローを構築する
- DevOpsにおける開発者の振る舞いを理解しよう
- GitLabを用いた継続的インテグレーション
- SODA Data Vision 2023より、Gitの使い勝手をデータレイクに応用したlakeFSを紹介
- 複数人で1つのUnityプロジェクトを管理するには
- GitHubとGitのおさらい
- DevOpsのアプリ開発にも欠かせない「Git」を活用したソースコードのバージョン管理
- 「開発者ファースト」で組織の変革を支援するGitHub (前編)
- Akka Streamsで実装するリアクティブストリーム(その2)