バージョン管理システムの目的はコードへの変更内容を記録することです。これにより、プロジェクト履歴に戻って誰が何を行ったかを確認したり、バグが生じた場所を見つけたり、問題のある変更を元に戻したりすることができます。しかし、履歴をナビゲートする方法を知らなければ、この履歴のすべてを利用できるようにしても役に立ちません。そこで、git log コマンドの出番です。

みなさんはコミットを表示するための基本的な git log コマンドを既に知っています。しかし、多くの様々なパラメーターを git log に渡すことでこの出力を変更することが可能です。

git log の高度な機能は次の2つのカテゴリに分類できます。各コミットの表示方法の形式設定と、出力に含めるコミットのフィルタリングです。これら2つのスキルを組み合わせると、プロジェクトに戻り、必要となる可能性のある情報を検索できます。

ログ出力のフォーマット

First, this article will take a look at the many ways in which git log’s output can be formatted. Most of these come in the form of flags that let you request more or less information from git log.

既定の git log 形式にしない場合は、git config のエイリアス機能を使用して、以下で説明している表示形式設定オプションのショートカットを作成できます。エイリアスの設定方法については、「git config コマンド」を参照してください。

Oneline

--oneline フラグは、各コミットを単一行に凝縮します。既定では、コミット ID とコミットメッセージの最初の行のみを表示します。一般的な git log --oneline 出力は次のように表示されます。

0e25143 Merge branch 'feature'
ad8621a Fix a bug in the feature
16b36c6 Add a new feature
23ad9ad Add the initial code base

これは、プロジェクトのハイレベルの概要を取得するには非常に便利です。

Decorate

各コミットが関連付けられているブランチまたはタグがわかると何倍も便利です。--decorate フラグを使用すると git log で各コミットをポイントする参照 (ブランチやタグなど) がすべて表示されます。

This can be combined with other configuration options. For example, running git log --oneline --decorate will format the commit history like so:

0e25143 (HEAD, master) Merge branch 'feature'
ad8621a (feature) Fix a bug in the feature
16b36c6 Add a new feature
23ad9ad (tag: v0.9) Add the initial code base

これにより先頭のコミットもチェックアウトされ (HEAD によって示されています)、これが master ブランチの先端でもあることがわかります。2 番目のコミットにはそれをポイントしている feature, と呼ばれる別のブランチがあり、最後に 4 番目のコミットが v0.9 とタグ付けされています。

Branches, tags, HEAD, and the commit history are almost all of the information contained in your Git repository, so this gives you a more complete view of the logical structure of your repository.

Diff

git log コマンドには各コミットの diff を表示するための多くのオプションがあります。最もよく使用されるオプションのうちの2つは、--stat-p です。

--stat オプションは、各コミットによって変更された各ファイルの挿入および削除の数を表示します (行の修正は、1 insertion (挿入) および 1 deletion (削除) のように表現されます)。これは各コミットによって生じた変更の簡単な概要が必要な場合に便利です。たとえば、次のコミットは hello.py ファイルに 67 行追加し、38 行削除しました。

commit f2a238924e89ca1d4947662928218a06d39068c3
Author: John <john@example.com>
Date: Fri Jun 25 17:30:28 2014 -0500
Add a new feature
hello.py| 105 ++++++++++++++++++++++++-----------------
1 file changed, 67 insertion(+), 38 deletions(-)

The amount of + and - signs next to the file name show the relative number of changes to each file altered by the commit. This gives you an idea of where the changes for each commit can be found.

各コミットによって生じた実際の変更を見る必要がある場合、-p オプションを git log に渡します。これにより、そのコミットを表す全パッチが出力されます。

commit 16b36c697eb2d24302f89aa22d9170dfe609855b
Author: Mary <mary@example.com>
Date: Fri Jun 25 17:31:57 2014 -0500
Fix a bug in the feature
diff --git a/hello.pyb/hello.py
index 18ca709..c673b40 100644
--- a/hello.py
+++ b/hello.py
@@ -13,14 +13,14 @@ B
-print("Hello, World!")
+print("Hello, Git!")

多くの変更を含むコミットの場合、結果の出力は非常に長く、扱いにくくなりがちです。だいたいにおいて、完全なパッチを表示している場合、特定の変更を検索しています。このため、pickaxe オプションを使用する必要があります。

Shortlog

git shortlog コマンドは git log の特別なバージョンで、リリースのお知らせを作成することを目的としています。作成者別に各コミットを分類し、各コミットメッセージの最初の行を表示します。これは、誰がどんな作業をしているかについて確認する簡単な方法です。

たとえば、2 人の開発者がプロジェクトに 5 コミット発行した場合、git shortlog 出力は次のように表示されます。

Mary (2):
 Fix a bug in the feature
 Fix a serious security hole in our framework

John (3):
 Add the initial code base
 Add a new feature
 Merge branch 'feature'

By default, git shortlog sorts the output by author name, but you can also pass the -n option to sort by the number of commits per author.

Graph

The --graph option draws an ASCII graph representing the branch structure of the commit history. This is commonly used in conjunction with the --oneline and --decorate commands to make it easier to see which commit belongs to which branch:

git log --graph --oneline --decorate

ブランチが2つだけの単純なリポジトリの場合、これは次のようになります。

* 0e25143 (HEAD, master) Merge branch 'feature'
|\
| * 16b36c6 Fix a bug in the new feature
| * 23ad9ad Start a new feature
* | ad8621a Fix a critical security issue
|/
* 400e4b7 Fix typos in the documentation
* 160e224 Add the initial code base

アスタリスクはコミットが存在したブランチを示すため、上記のグラフから、23ad9ad および 16b36c6 コミットは、トピックブランチにあり、残りのコミットは master ブランチにあることがわかります。

単純なリポジトリの場合、これは役立つオプションですが、多くのブランチがあるプロジェクトでは、より完全な構造を視覚化できる gitkSourceTree のようなツールを使用するほうが便利でしょう。

カスタム形式設定

For all of your other git log formatting needs, you can use the --pretty=format:"<string>" option. This lets you display each commit however you want using printf-style placeholders.

たとえば、次のコマンドで %cn%h および %cd 文字はそれぞれ、コミッター名、短縮されたコミットハッシュ、およびコミッター日付に置き換えられます。

git log --pretty=format:"%cn committed %h on %cd"

これにより、各コミットについて、次の形式で返されます。

John committed 400e4b7 on Fri Jun 24 12:30:04 2014 -0500
John committed 89ab2cf on Thu Jun 23 17:09:42 2014 -0500
Mary committed 180e223 on Wed Jun 22 17:21:19 2014 -0500
John committed f12ca28 on Wed Jun 22 13:50:31 2014 -0500

The complete list of placeholders can be found in the Pretty Formats section of the git log manual page.

関心のある情報のみを表示することに加えて、--pretty=format:"<string>" オプションは git log 出力を別のコマンドにパイピングしようとする場合に特に役立ちます。

コミット履歴にフィルターをかける

Formatting how each commit gets displayed is only half the battle of learning git log. The other half is understanding how to navigate the commit history. The rest of this article introduces some of the advanced ways to pick out specific commits in your project history using git log. All of these can be combined with any of the formatting options discussed above.

量によるフィルタリング

git log の最も基本的なフィルタリングオプションは、表示されるコミット数を限定することです。最近のいくつかのコミットにのみ関心がある場合、フィルタリングすることでページャーにすべてのコミットを表示する手間が省けます。

git log の出力は -<n> オプションを指定することで制限できます。たとえば、次のコマンドは3つの最新のコミットのみを表示します。

git log -3

日付によるフィルタリング

特定の期間のコミットを探す場合は、--after または --before フラグを使用して日付によってコミットをフィルタリングします。これらは両方ともパラメーターとして多様な日付形式を受け入れます。たとえば、次のコマンドは、2014 年 7 月 1 日以降に作成されたコミットのみを表示します。

git log --after="2014-7-1"

"1 week ago" (1 週間前) および "yesterday" (昨日) のような相対参照で渡すこともできます。

get log --after="yesterday"

2つの日付の間で作成されたコミットを検索するには、--before--after の両方の日付を指定できます。たとえば、2014 年 7 月 1 日と 2014 年 7 月 4 日の間に追加されたすべてのコミットを表示するには、次のようにします。

git log --after="2014-7-1" --before="2014-7-4"

--since および --until フラグはそれぞれ、--after および --before と同義です。

作成者によるフィルタリング

特定のユーザーが作成したコミットのみを検索する場合は、 --author フラグを使用します。これは正規表現を受け入れ、そのパターンに一致する作成者のすべてのコミットを返します。検索する相手が正確にわかっている場合は、正規表現の代わりに従来のプレーンテキストを使用できます。

git log --author="John"

これは John という名前を含むコミットの作成者をすべて表示します。作成者名は完全一致である必要はありません。単に、指定された語句を含んでいる 必要があるだけです。

You can also use regular expressions to create more complex searches. For example, the following command searches for commits by either Mary or John.

git log --author="John\|Mary"

作成者のメールも作成者の名前に付随するため、このオプションを使用してメールで検索することも可能です。

ワークフローでコミッターと作成者を分離している場合、--committer フラグが同じように動作します。

メッセージによるフィルタリング

コミットをコミットメッセージによりフィルタリングするには、--grep フラグを使用します。これは、上記で説明した --author フラグと同様に動作しますが、作成者ではなく、コミットメッセージに一致するものを照合します。

たとえば、チームが関連する課題番号を各コミットメッセージに取り込む場合、次のようにすると、その課題に関係するすべてのコミットを取得できます。

git log --grep="JRA-224:"

You can also pass in the -i parameter to git log to make it ignore case differences while pattern matching.

ファイルによるフィルタリング

特定のファイルに生じた変更のみを知りたい場合もよくあります。ファイルに関連する履歴を表示するために必要なことは、ファイルパスを渡すだけです。たとえば、次のコマンドは、foo.py または bar.py ファイルのいずれかに影響を与えたすべてのコミットを返します。

git log -- foo.py bar.py

-- パラメーターは、後続の引数がブランチ名ではなく、ファイルパスであることを git log に伝えるために使用されます。ブランチと混同される可能性がまったくない場合は、-- を省略できます。

コンテンツによるフィルタリング

ソースコードの特定の行を追加または削除するコミットを検索することも可能です。これは pickaxe と呼ばれ、形式は -S"<string>" です。たとえば、文字列 Hello, World! がプロジェクト内のいずれかのファイルにいつ追加されたのか知りたい場合、次のコマンドを使用します。

git log -S"Hello, World!"

文字列ではなく、正規表現を使用して検索したい場合は、 -G"<regex>" フラグを代わりに使用できます。

これは非常に強力なデバッグツールで、特定のコード行に影響を与えるすべてのコミットの場所を見つけることができます。コード行が別のファイルにコピーまたは移動された場合でも、その場所を示すことが可能です。

範囲によるフィルタリング

コミットの範囲を git log に渡すと、その範囲に含まれるコミットのみを表示できます。この範囲は、次の形式で指定されます。ここで、<since> および <until> はコミット参照です。

git log <since>..<until>

このコマンドは、パラメーターとしてブランチ参照を使用する場合に特に役立ちます。2つのブランチ間の相違を示す単純な方法です。次のコマンドを考えます。

git log master..feature

master..feature 範囲には、feature ブランチにはあり、master ブランチにはないコミットがすべて含まれています。つまり、これは featuremaster からフォークした後、作業が進行したことを示します。これは次のように可視化できます。

範囲を使用して履歴でフォークを検出

Note that if you switch the order of the range (feature..master), you will get all of the commits in master, but not in feature. If git log outputs commits for both versions, this tells you that your history has diverged.

マージコミットのフィルタリング

既定では、git log の出力にはマージコミットが含まれます。しかし、チームに「常にマージ」ポリシーがあると (つまり、トピックブランチを上流ブランチにリベースするのではなく、上流の変更をトピックブランチにマージする)、多くの無関係なマージコミットがプロジェクト履歴に残ることになります。

git log がこれらのマージコミットを表示しないようにするには、--no-merges フラグを渡します。

git log --no-merges

反対に、マージコミットにのみ関心がある場合、--merges フラグを使用します。

git log --merges

これにより、2つ以上の親を持つすべてのコミットが返されます。

Summary

これで皆さんは git log の高度なパラメーターを快適に使いこなして出力形式の設定や表示したいコミットの選択を行えるようになりました。したがって、プロジェクト履歴から必要なものを正確に取り出すことができます。

これらの新しいスキルは Git ツールキットの重要な部分ですが、git log は多くの場合、他の Git コマンドと共に使用されることを覚えておいてください。探しているコミットが見つかったら、コミット履歴を操作するためにそれを git checkoutgit revert、または他のツールに渡すのが一般的です。それでは、今後も Git の高度な機能について学習を欠かさないようにしましょう。