git log 応用:著者・時間・ファイルでコミットを絞り込み、–graph –pretty でブランチを可視化する

Git tutorial - IT technology blog
Git tutorial - IT technology blog

3,000以上のコミットを複数人で積み上げてきたコードベースを6ヶ月扱ってわかったのは、デフォルトのgit logがほぼ使い物にならないということだ。先週の同僚のコミットを探すために数百行スクロールするなんて、誰にもそんな時間はない。この記事では、ドキュメントの網羅的なリストではなく、本番環境で毎日使っているオプションを紹介する。

git log のデフォルトの問題点

引数なしでgit logを実行すると、コミットが新しい順にずらっと並ぶ。デフォルトのフォーマットはコミット1件あたり5〜6行を占め、情報が凝縮されておらず、どのブランチがどこにマージされているかもわからない。

コミット履歴を活用したいときの主なアプローチは3つある:

  • GUI ツール(GitKraken、Sourcetree など)— 視覚的にわかりやすいが、ターミナルでは使えず、スクリプトにも組み込めない
  • GitHub/GitLab の UI — 便利だがインターネット依存で、まだプッシュしていないローカルブランチは確認できない
  • git log とオプション — どこでも動き、スクリプト化でき、速い

3つすべて試したが、ターミナルに戻った理由は明確だ:チームの進捗報告のために、週次でコミットを分析するスクリプトを書く必要があった。git logだけが、何もインストールせずにそれを実現できる。

著者でコミットを絞り込む

最もよく使うオプションだ。特定のメンバーの作業を確認するスプリントレビューで特に重宝する:

# 名前またはメールアドレスで絞り込む
git log --author="Nguyen Van A"
git log --author="[email protected]"

# 正規表現も使える — Nguyen という名前の全員を検索
git log --author="Nguyen"

# 組み合わせ:直近2週間の自分のコミット
git log --author="$(git config user.name)" --since="2 weeks ago"

--authorは完全一致ではなく正規表現でマッチする。チームに「An」と「Anh」という名前の人がいれば、--author="An"は両方にヒットする。より正確にするには、メールアドレスを使うか^An$のようにアンカーを付ける。

時間で絞り込む

Git はさまざまなフォーマットを解釈できる — ISO 日付から自然な英語表現まで、どちらでも動く:

# 相対時間
git log --since="3 days ago"
git log --after="1 week ago"
git log --until="yesterday"
git log --before="2024-01-01"

# 特定の期間
git log --since="2024-06-01" --until="2024-06-30"

# 今週のチーム全体のコミットを確認
git log --since="monday" --format="%h %an %s"

--since--afterは同じ意味のエイリアスだ。--until--beforeも同様。1つのコマンドで組み合わせるとき、--since/--untilのペアの方が読みやすいので、こちらをよく使う。

コミット内容とファイルで絞り込む

探す対象によって、2つの方法がある。

コミットメッセージで検索

# --grep: コミットメッセージを検索
git log --grep="fix" --grep="bug"        # OR(デフォルト)
git log --grep="fix" --grep="auth" --all-match  # AND

# 大文字小文字を区別しない
git log --grep="hotfix" -i

# login 機能に関連するコミットを検索
git log --grep="login\|auth\|authentication" -i --format="%h %s"

コード内の変更内容で検索

# -S: この文字列を追加または削除したコミットを検索(pickaxe)
git log -S "password_hash"
git log -S "def calculate_tax"

# -G: diff 内の正規表現で検索
git log -G "api_key.*=.*['\"]" --all

# この関数を誰が削除したか調べる
git log -S "def send_notification" --patch

-Sは文字列の出現回数が変化したコミット(追加または削除)を探す。-Gは diff にその正規表現を含むコミットを探す。関数を削除した経緯を追跡したいなら、-Sの方が正確だ — 出現回数が実際に変わったコミットのみを報告し、その行が diff に含まれる全コミットを返すわけではない。

ファイルまたはディレクトリで絞り込む

# 特定のファイルに触れたコミット
git log -- src/auth.py
git log -- "*.sql"   # ワイルドカードはクォートが必要

# あるディレクトリ内のコミット
git log -- src/api/

# 他のフィルターと組み合わせる
git log --since="1 month ago" --author="Anh" -- migrations/

# コミットごとにそのファイルの実際の変更を確認
git log -p -- config/settings.py

パスの前の--は、それがファイル/フォルダであってブランチ名ではないと git に伝えるためのものだ。省略しても通常は動くが、ファイル名とブランチ名が一致するとき、予告なくエラーになる。

–graph と –pretty でブランチを可視化する

これが最もよく遭遇する問題を解決するパートだ:git logの出力を見ても、どのブランチがどこにマージされているかわからない問題。

–graph の基本

# シンプルなグラフ
git log --graph --oneline --decorate

# すべてのブランチを表示
git log --graph --oneline --decorate --all

出力はこのようになる:

* a3f2c1d (HEAD -> main) fix: auth token expiry
*   b1e9f8a Merge pull request #42 from feature/login
|\  
| * c7d4e23 feat: implement JWT refresh
| * 9a1b5f0 feat: login endpoint
|/  
* 4f8c2d1 refactor: extract user service

–pretty でカスタムフォーマット

デフォルトのフォーマットは長すぎる。これが毎日使っているものだ:

# 色付きのコンパクトなフォーマット
git log --graph --pretty=format:"%C(yellow)%h%Creset %C(cyan)%an%Creset %C(green)(%ar)%Creset %s" --all

# レポート用のより詳細なフォーマット
git log --pretty=format:"%H|%an|%ae|%ad|%s" --date=short

--pretty=format:でよく使うプレースホルダー:

  • %h — 短いハッシュ、%H — フルハッシュ
  • %an — 著者名、%ae — 著者メールアドレス
  • %ar — 相対日時(”3 days ago” 形式)、%ad — 絶対日時
  • %s — コミットメッセージのタイトル
  • %C(color) — 色を設定、%Creset — 色をリセット

毎回入力しなくていいようにエイリアスを設定する

この3つはずっと~/.gitconfigに入れている:

# ~/.gitconfig に追加
git config --global alias.lg "log --graph --pretty=format:'%C(yellow)%h%Creset -%C(auto)%d%Creset %s %C(green)(%ar) %C(cyan)<%an>%Creset' --all"
git config --global alias.ll "log --oneline --decorate --all --graph"
git config --global alias.lw "log --pretty=format:'%C(yellow)%h%Creset %s %C(green)(%ar)%Creset' --date=relative"

# あとはこれだけでいい
git lg
git ll

実際のプロジェクト進捗を分析する

うちのチームは8人だ。毎週金曜日に、このスクリプトが自動で実行されてスプリントレポートをまとめる:

#!/bin/bash
# weekly-report.sh

echo "=== Sprint Report: $(date +'%Y-%m-%d') ==="
echo ""
echo "--- Commit count by author ---"
git log --since="1 week ago" --format="%an" | sort | uniq -c | sort -rn

echo ""
echo "--- Files changed most ---"
git log --since="1 week ago" --name-only --format="" | sort | uniq -c | sort -rn | head -10

echo ""
echo "--- Commit timeline ---"
git log --since="1 week ago" --format="%ad %an: %s" --date=format:"%a %H:%M" --reverse

「Files changed most」のセクションは思っていた以上に役立つ。最も変更が多いファイルは、たいてい何か問題を抱えているか、二人が並行して作業しているのにお互い気づいていないところだ。このレポートができてから、チームのマージコンフリクトが目に見えて減った:新しいタスクを始める前に、お互いがどこを触っているか確認するようになったからだ。

フィルターの組み合わせ:実践例

# 6月の自分のコミットのうち、Python ファイルのみ、データベース関連のものを検索
git log \
  --author="$(git config user.name)" \
  --since="2024-06-01" --until="2024-06-30" \
  --grep="db\|database\|migration" -i \
  -- "*.py" \
  --oneline

# デバッグ:過去3ヶ月で特定の関数に加えられた全変更を確認
git log -G "def process_payment" --since="3 months ago" --patch -- payments/

# 監査:PR を経ずに直接 main にコミットした人を調べる
git log main --no-merges --since="1 month ago" --format="%h %an %s"

どのような場面で何を使うか

理論ではなく、実際の経験からまとめると:

  • 素早くデバッグしたいときgit log --oneline --graph --all — 2秒でブランチツリー全体を把握できる
  • 誰がどのファイルを変更したか調べるときgit log --author --since -- path/to/file
  • バグを追跡するときgit log -S "suspicious_function" --patch — コードが変更された正確な箇所を確認できる
  • スプリントレポートを作成するときgit log --format --sincesort | uniq -cにパイプする
  • マージ前に PR をレビューするときgit log main..feature-branch --oneline

GUI ツールも、初心者への説明や行単位の差分を視覚的に確認したいときには有用だ。ただ、人・時間・ファイル・内容で — すべてを同時に — 絞り込みたいなら、ターミナルの方が速く、クリック操作も不要だ。

Share: