Git --distributed-even-if-your-workflow-isnt
Chapters ▾

2.3 Git の基本 - コミット履歴の閲覧

コミット履歴の閲覧

何度かコミットを繰り返すと、あるいはコミット履歴つきの既存のリポジトリをクローンすると、過去に何が起こったのかを振り返りたくなることでしょう。そのために使用するもっとも基本的かつパワフルな道具が git log コマンドです。

ここからの例では、simplegit という非常にシンプルなプロジェクトを使用します。これは、私が説明用によく用いているプロジェクトで、次のようにして取得できます。

git clone git://github.com/schacon/simplegit-progit.git

このプロジェクトで git log を実行すると、このような結果が得られます。

$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test code

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 10:31:28 2008 -0700

    first commit

デフォルトで引数を何も指定しなければ、git log はそのリポジトリでのコミットを新しい順に表示します。つまり、直近のコミットが最初に登場するということです。ごらんのとおり、このコマンドは各コミットについて SHA-1 チェックサム・作者の名前とメールアドレス・コミット日時・コミットメッセージを一覧表示します。

git log コマンドには数多くのバラエティに富んだオプションがあり、あなたが本当に見たいものを表示させることができます。ここでは、よく用いられるオプションのいくつかをご覧に入れましょう。

もっとも便利なオプションのひとつが -p で、これは各コミットの diff を表示します。また -2 は、直近の 2 エントリだけを出力します。

$ git log -p -2
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

diff --git a/Rakefile b/Rakefile
index a874b73..8f94139 100644
--- a/Rakefile
+++ b/Rakefile
@@ -5,5 +5,5 @@ require 'rake/gempackagetask'
 spec = Gem::Specification.new do |s|
     s.name      =   "simplegit"
-    s.version   =   "0.1.0"
+    s.version   =   "0.1.1"
     s.author    =   "Scott Chacon"
     s.email     =   "schacon@gee-mail.com

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test code

diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index a0a60ae..47c6340 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -18,8 +18,3 @@ class SimpleGit
     end

 end
-
-if $0 == __FILE__
-  git = SimpleGit.new
-  puts git.show
-end
\ No newline at end of file

このオプションは、先ほどと同じ情報を表示するとともに、各エントリの直後にその diff を表示します。これはコードレビューのときに非常に便利です。また、他のメンバーが一連のコミットで何を行ったのかをざっと眺めるのにも便利でしょう。

コードレビューの際、行単位ではなく単語単位でレビューするほうが容易な場合もあるでしょう。git log -p コマンドのオプション --word-diff を使えば、通常の行単位diffではなく、単語単位のdiffを表示させることができます。単語単位のdiffはソースコードのレビューに用いても役に立ちませんが、書籍や論文など、長文テキストファイルのレビューを行う際は便利です。こんな風に使用します。

$ git log -U1 --word-diff
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

diff --git a/Rakefile b/Rakefile
index a874b73..8f94139 100644
--- a/Rakefile
+++ b/Rakefile
@@ -7,3 +7,3 @@ spec = Gem::Specification.new do |s|
    s.name      =   "simplegit"
    s.version   =   [-"0.1.0"-]{+"0.1.1"+}
    s.author    =   "Scott Chacon"

ご覧のとおり、通常のdiffにある「追加行や削除行の表示」はありません。その代わりに、変更点はインラインで表示されることになります。追加された単語は {+ +} で、削除された単語は [- -] で囲まれます。また、着目すべき点が行ではなく単語なので、diffの出力を通常の「変更行前後3行ずつ」から「変更行前後1行ずつ」に減らしたほうがよいかもしれません。上記の例で使用した -U1 オプションを使えば行数を減らせます。

また、git log では「まとめ」系のオプションを使うこともできます。たとえば、各コミットに関するちょっとした統計情報を見たい場合は --stat オプションを使用します。

$ git log --stat
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

 Rakefile |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test code

 lib/simplegit.rb |    5 -----
 1 file changed, 5 deletions(-)

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 10:31:28 2008 -0700

    first commit

 README           |    6 ++++++
 Rakefile         |   23 +++++++++++++++++++++++
 lib/simplegit.rb |   25 +++++++++++++++++++++++++
 3 files changed, 54 insertions(+)

ごらんの通り --stat オプションは、各コミットエントリに続けて変更されたファイルの一覧と変更されたファイルの数、追加・削除された行数が表示されます。また、それらの情報のまとめを最後に出力します。もうひとつの便利なオプションが --pretty です。これは、ログをデフォルトの書式以外で出力します。あらかじめ用意されているいくつかのオプションを指定することができます。oneline オプションは、各コミットを一行で出力します。これは、大量のコミットを見る場合に便利です。さらに shortfull そして fuller といったオプションもあり、これは標準とほぼ同じ書式だけれども情報量がそれぞれ少なめあるいは多めになります。

$ git log --pretty=oneline
ca82a6dff817ec66f44342007202690a93763949 changed the version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test code
a11bef06a3f659402fe7563abf99ad00de2209e6 first commit

もっとも興味深いオプションは format で、これは独自のログ出力フォーマットを指定することができます。これは、出力結果を機械にパースさせる際に非常に便利です。自分でフォーマットを指定しておけば、将来 Git をアップデートしても結果が変わらないようにできるからです。

$ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 11 months ago : changed the version number
085bb3b - Scott Chacon, 11 months ago : removed unnecessary test code
a11bef0 - Scott Chacon, 11 months ago : first commit

表 2-1 は、format で使用できる便利なオプションをまとめたものです。

オプション 出力される内容
%H コミットのハッシュ
%h コミットのハッシュ (短縮版)
%T ツリーのハッシュ
%t ツリーのハッシュ (短縮版)
%P 親のハッシュ
%p 親のハッシュ (短縮版)
%an Author の名前
%ae Author のメールアドレス
%ad Author の日付 (--date= オプションに従った形式)
%ar Author の相対日付
%cn Committer の名前
%ce Committer のメールアドレス
%cd Committer の日付
%cr Committer の相対日付
%s 件名

authorcommitter は何が違うのか気になる方もいるでしょう。author とはその作業をもともと行った人、committer とはその作業を適用した人のことを指します。あなたがとあるプロジェクトにパッチを送り、コアメンバーのだれかがそのパッチを適用したとしましょう。この場合、両方がクレジットされます (あなたが author、コアメンバーが committer です)。この区別については 第 5 章 でもう少し詳しく説明します。

oneline オプションおよび format オプションは、log のもうひとつのオプションである --graph と組み合わせるとさらに便利です。このオプションは、ちょっといい感じのアスキーグラフでブランチやマージの歴史を表示します。Grit プロジェクトのリポジトリならこのようになります。

$ git log --pretty=format:"%h %s" --graph
* 2d3acf9 ignore errors from SIGCHLD on trap
*  5e3ee11 Merge branch 'master' of git://github.com/dustin/grit
|\
| * 420eac9 Added a method for getting the current branch.
* | 30e367c timeout code and tests
* | 5a09431 add timeout protection to grit
* | e1193f8 support for heads with slashes in them
|/
* d6016bc require time for xmlschema
*  11d191e Merge branch 'defunkt' into local

これらは git log の出力フォーマット指定のほんの一部でしかありません。まだまだオプションはあります。表 2-2 に、今まで取り上げたオプションとそれ以外によく使われるオプション、そしてそれぞれがlogの出力をどのように変えるのかをまとめました。

オプション 説明
-p 各コミットのパッチを表示する
--word-diff 変更点を単語単位で表示する
--stat 各コミットで変更されたファイルの統計情報を表示する
--shortstat --stat コマンドのうち、変更/追加/削除 の行だけを表示する
--name-only コミット情報の後に変更されたファイルの一覧を表示する
--name-status 変更されたファイルと 追加/修正/削除 情報を表示する
--abbrev-commit SHA-1 チェックサムの全体 (40文字) ではなく最初の数文字のみを表示する
--relative-date 完全な日付フォーマットではなく、相対フォーマット (“2 weeks ago” など) で日付を表示する
--graph ブランチやマージの歴史を、ログ出力とともにアスキーグラフで表示する
--pretty コミットを別のフォーマットで表示する。オプションとして oneline, short, full, fuller そして format (独自フォーマットを設定する) を指定可能
--oneline --pretty=oneline --abbrev-commitと同じ意味の便利なオプション

ログ出力の制限

出力のフォーマット用オプションだけでなく、 git log にはログの制限用の便利なオプションもあります。コミットの一部だけを表示するようなオプションのことです。既にひとつだけ紹介していますね。-2 オプション、これは直近のふたつのコミットだけを表示するものです。実は -<n>n には任意の整数値を指定することができ、直近の n 件のコミットだけを表示させることができます。ただ、実際のところはこれを使うことはあまりないでしょう。というのも、Git はデフォルトですべての出力をページャにパイプするので、ログを一度に 1 ページだけ見ることになるからです。

しかし --since--until のような時間制限のオプションは非常に便利です。たとえばこのコマンドは、過去二週間のコミットの一覧を取得します。

$ git log --since=2.weeks

このコマンドはさまざまな書式で動作します。特定の日を指定する (“2008-01-15”) こともできますし、相対日付を“2 years 1 day 3 minutes ago”のように指定することも可能です。

コミット一覧から検索条件にマッチするものだけを取り出すこともできます。--author オプションは特定の author のみを抜き出し、--grep オプションはコミットメッセージの中のキーワードを検索します (author と grep を両方指定すると、両方にマッチするものだけが対象になります)。

grep を複数指定したい場合は、--all-match を追加しないといけません。そうしないと、どちらか一方にだけマッチするものも対象になってしまいます。

最後に紹介する git log のフィルタリング用オプションは、パスです。ディレクトリ名あるいはファイル名を指定すると、それを変更したコミットのみが対象となります。このオプションは常に最後に指定し、一般にダブルダッシュ (--) の後に記述します。このダブルダッシュが他のオプションとパスの区切りとなります。

表 2-3 に、これらのオプションとその他の一般的なオプションをまとめました。

オプション 説明
-(n) 直近の n 件のコミットのみを表示する
--since, --after 指定した日付/時刻以降のCommitDateのコミットのみに制限する
--until, --before 指定した日付/時刻以前のCommitDateのコミットのみに制限する
--author エントリが指定した文字列にマッチするコミットのみを表示する
--committer エントリが指定した文字列にマッチするコミットのみを表示する

日時にもとづくログ出力の制限

Git のリポジトリ(git://git.kernel.org/pub/scm/git/git.git)からCommitDateを使ってコミットを検索してみましょう。パソコンに設定されたタイムゾーンにおける2014/04/29のコミットを検索するには、以下のコマンドを実行します。

$ git log --after="2014-04-29 00:00:00" --before="2014-04-29 23:59:59" \
  --pretty=fuller

この場合、コマンドの結果はパソコンのタイムゾーン設定ごとに異なってしまいます。それを避けるには、タイムゾーンを含むISO 8601フォーマットのような日時を --after--before の引数に指定するといいでしょう。そうすれば、上述のケースのようにコマンド実行結果が異なる可能性がなくなります。

特定日時(例として、中央ヨーロッパ時間で2013/04/29 17:07:22)を指定してコミットを検索するには、以下のコマンドを使います。

$ git log  --after="2013-04-29T17:07:22+0200"      \
          --before="2013-04-29T17:07:22+0200" --pretty=fuller

commit de7c201a10857e5d424dbd8db880a6f24ba250f9
Author:     Ramkumar Ramachandra <artagnon@gmail.com>
AuthorDate: Mon Apr 29 18:19:37 2013 +0530
Commit:     Junio C Hamano <gitster@pobox.com>
CommitDate: Mon Apr 29 08:07:22 2013 -0700

    git-completion.bash: lexical sorting for diff.statGraphWidth

    df44483a (diff --stat: add config option to limit graph width,
    2012-03-01) added the option diff.startGraphWidth to the list of
    configuration variables in git-completion.bash, but failed to notice
    that the list is sorted alphabetically.  Move it to its rightful place
    in the list.

    Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
    Signed-off-by: Junio C Hamano <gitster@pobox.com>

これらの日時(AuthorDateCommitDate)はGitのデフォルトフォーマット(--date=default オプション相当)です。作者とコミッター、それぞれのタイムゾーン情報を表示します。

日時フォーマットの指定は他にも --date=iso (ISO 8601)、--date=rfc (RFC 2822)、--date=raw (Unix時間)、--date=local (端末のタイムゾーン)、--date=relative("2 hours ago"のように相対的な指定)などがあります。

また、 git log 実行時に日時指定を省略すると、パソコンの時計をもとにコマンド実行日時を指定日時として使用します(協定標準時からの時差も同一になります)。

具体的には、仮にパソコンの時計が09:00を指していて、かつタイムゾーン設定が協定標準時プラス3時間の場合、以下の git log コマンドの日時指定は同一として扱われます。

$ git log --after=2008-06-01 --before=2008-07-01
$ git log --after="2008-06-01T09:00:00+0300" \
    --before="2008-07-01T09:00:00+0300"

もう一つ例を挙げておきましょう。Git ソースツリーのテストファイルに対する変更があったコミットのうち、Junio Hamano がコミットしたもの (マージは除く) で 2008 年 10 月(ニューヨークのタイムゾーン)に行われたものを知りたければ次のように指定します。

$ git log --pretty="%h - %s" --author=gitster \
   --after="2008-10-01T00:00:00-0400"         \
  --before="2008-10-31T23:59:59-0400" --no-merges -- t/
5610e3b - Fix testcase failure when extended attribute
acd3b9e - Enhance hold_lock_file_for_{update,append}()
f563754 - demonstrate breakage of detached checkout wi
d1a43f2 - reset --hard/read-tree --reset -u: remove un
51a94af - Fix "checkout --track -b newbranch" on detac
b0ad11e - pull: allow "git pull origin $something:$cur

約 36,000 件におよぶ Git ソースコードのコミットの歴史の中で、このコマンドの条件にマッチするのは 6 件となります。

GUI による歴史の可視化

もう少しグラフィカルなツールでコミットの歴史を見たい場合は、Tcl/Tk のプログラムである gitk を見てみましょう。これは Git に同梱されています。gitk は、簡単に言うとビジュアルな git log ツールです。git log で使えるフィルタリングオプションにはほぼすべて対応しています。プロジェクトのコマンドラインで gitk と打ち込むと、図 2-2 のような画面があらわれるでしょう。


図 2-2. gitk history visualizer

ウィンドウの上半分に、コミットの歴史がきれいな家系図とともに表示されます。ウィンドウの下半分には diff ビューアがあり、任意のコミットをクリックしてその変更内容を確認することができます。