自分がこの会社で今までにgit commitした行数を数える方法

この記事は「ウィルゲート Advent Calendar 2024」の 17 日目の記事です! adventar.org

こんにちは!!ウィルゲートプロダクト事業部 開発グループのことみん(@kotomin_m)です!!

このブログでは、複数リポジトリで特定の誰かがコミットしたコード行数を数える方法を簡単に紹介していきます!

端折っている部分も少々ありますが、コピペで実行できるシェルも載せているので、1年のふりかえりにぜひお試しください!

やり方の説明

今回は以下の5ステップで、GitHubのorganizationsにある全てのリポジトリでコミットしたコード行数を数えるようにしました!

  1. GitHubに登録しているリポジトリ一覧をAPIで取得
  2. 取得したリポジトリ一覧を整形
  3. 全リポジトリをgit clone
  4. git log でコミットログを集計してCSV出力
  5. CSVファイルをGoogle スプレッドシートで集計

今回はパワーで集計したのでちょっと無理矢理感もありますね。たぶん、もっとスマートな方法もあると思います。

コミットした期間で絞り込んだり、特定のリポジトリだけを集計するなどアレンジは可能なので、自分の用途に合わせてお使いください!

ステップ1:GitHubに登録しているリポジトリ一覧をAPIで取得

GitHubのAPIを使って全てのリポジトリ情報を取得します。 organizationsに含まれるリポジトリ数が多く、手動でgit cloneするリポジトリを指定するのは大変だったのでAPIで取得しました。

GitHub Personal Access Token を取得し、以下のシェルを実行します。

1_fetch_org_repos.sh

#!/bin/bash -eu

# 必要な変数を設定
# あなたの GitHub Personal Access Token
TOKEN="トークンを入力"
# 対象のorganizations名
ORG_NAME="organizations-name"
# 出力ファイル名
OUTPUT_FILE="1_repos.json"

# GitHub API を使ってリポジトリ一覧を取得
curl -H "Authorization: token $TOKEN" \
     "https://api.github.com/orgs/$ORG_NAME/repos?per_page=100" > "$OUTPUT_FILE"

echo "リポジトリ一覧を $OUTPUT_FILE に保存しました。"

1_repos.jsonファイルにリポジトリ情報が出力されます。

[
  {
    "id": 123456789,
    "node_id": "ABCDEFGH",
    "name": "repository-name",
    "full_name": "organizations-name/repository-name",
    (省略)
  },
]

ステップ2:取得したリポジトリ一覧を整形

ステップ1で取得したリポジトリ情報から、full_nameのみを取得してテキストファイルに書き出します。

2_get_repos_full_name.sh

#!/bin/bash -eu

# 必要な変数を設定
# 1で取得したJSONファイル名
INPUT_FILE="1_repos.json"
# リポジトリ名を保存するファイル名
OUTPUT_FILE="2_repos_full_name.txt"  

# JSONファイルからリポジトリ名を抽出して保存
jq -r '.[].full_name' "$INPUT_FILE" > "$OUTPUT_FILE"

echo "リポジトリ一覧を $OUTPUT_FILE に保存しました。"

2_repos_full_name.txtに全てのリポジトリ名が出力されます。

organizations-name/repository-name
organizations-name/repository-name-2
organizations-name/repository-name-3

ステップ3:全リポジトリをgit clone

ステップ2で取得したテキストファイルを使って、全てのリポジトリをgit cloneします。ファイルを編集することで、集計対象のリポジトリをフィルターすることも出来ます。

今回は特定のリポジトリに絞ってデバッグしながら実行したかったのでステップ2,3が存在していますが、一度テキストファイルに書き出す作業をしなくてもgit clone出来そうですね。

3_clone_repos.sh

#!/bin/bash -eu

# 必要な変数を設定
# 2で取得したリポジトリ一覧ファイル名
REPOS_LIST="2_repos_full_name.txt"
# クローン先ディレクトリ
CLONE_DIR="repos"

# リポジトリ一覧ファイルの確認
if [[ ! -f "$REPOS_LIST" ]]; then
  echo "リポジトリ一覧ファイルが見つかりません: $REPOS_LIST"
  exit 1
fi

# クローン先ディレクトリの作成
mkdir -p "$CLONE_DIR"

# リポジトリ一覧を1行ずつ処理
while read -r REPO_FULL_NAME; do
  # 空行をスキップ
  if [[ -z "$REPO_FULL_NAME" ]]; then
    continue
  fi

  # ローカルのディレクトリ名
  REPO_DIR="$CLONE_DIR/$(basename "$REPO_FULL_NAME")"

  # ディレクトリが存在する場合はスキップ
  if [[ -d "$REPO_DIR" ]]; then
    echo "$REPO_FULL_NAME は既に存在します。"
    continue
  fi

  # リポジトリをクローン
  git clone "git@github.com:$REPO_FULL_NAME.git" "$REPO_DIR"

done < "$REPOS_LIST"

echo "すべてのリポジトリをクローンしました。"

repos/ディレクトリ配下に、全てのリポジトリがクローンされます。

ステップ4:git log でコミットログを集計してCSV出力

git cloneしたリポジトリに対して、git logawkコマンドでコミット行数を集計し、CSVファイルを出力します。

ここで集計期間も指定するので、過去1年分だけ集計するなどカスタマイズすることも出来ます。

4_git_log_commit_count.sh

#!/bin/bash -eu

# 必要な変数を設定
# コミットログを取得したい人のメールアドレス
EMAIL="email@example.com"
# クローン先ディレクトリ
CLONE_DIR="repos"
# 実行結果を保存するファイル名
RESULT_FILE="$EMAIL.csv"
# コミットログの取得期間
SINCE_DATE="2010-01-01"
UNTIL_DATE="2024-12-31"

# 初期化:結果ファイルを空にする
> "$RESULT_FILE"

# クローン先ディレクトリを確認
if [[ ! -d "$CLONE_DIR" ]]; then
  echo "ディレクトリが見つかりません: $CLONE_DIR"
  exit 1
fi

# 各リポジトリを処理
for REPO_PATH in "$CLONE_DIR"/*; do
  if [[ ! -d "$REPO_PATH/.git" ]]; then
    echo "$REPO_PATH はリポジトリディレクトリではありません。"
    continue
  fi

  REPO_NAME=$(basename "$REPO_PATH")

  # リポジトリのディレクトリに移動
  cd "$REPO_PATH" || continue

  # git log コマンドでコミットログを取得し、awk で集計
  LOG_SUMMARY=$(git log --numstat --pretty="%H" --author="$EMAIL" --since="$SINCE_DATE" --until="$UNTIL_DATE" --no-merges | awk 'NF==3 {plus+=$1; minus+=$2} END {printf("%d, %d, %d\n", plus+minus, plus, minus)}')

  # ログのサマリーを表示
  echo "$REPO_NAME, $LOG_SUMMARY"

  # 元のディレクトリに戻る
  cd - > /dev/null || exit

  # 結果をファイルに追記
  echo "$EMAIL, $REPO_NAME, $LOG_SUMMARY" >> $RESULT_FILE

done

echo "結果を $RESULT_FILE に保存しました。"

email@example.com.csvに、リポジトリごとの変更行数が保存されます。

メールアドレス, リポジトリ名, 変更総数, 追加行数, 削除行数
email@example.com, repository-name, 1000, 500, 500
email@example.com, repository-name-2, 2000, 1000, 1000
email@example.com, repository-name-3, 3000, 2000, 1000

ステップ5:CSVファイルをGoogle スプレッドシートで集計

email@example.com.csvをGoogle スプレッドシートで開いて手動で集計します。

こういうときにスプシは便利ですね〜。変更行数が多いリポジトリ順とかも簡単に見れますね。

おわりに

変更行数を出すと「自分ってこんなにコード書いたんだな〜😆」ってなれますね!

他にも、「あの先輩どんだけコード書いてきたんだろう?対決だ!」なんてことも出来ます!💪(そして、「マジか〜全然勝てねえじゃん😇」なんてこともあります。)

使い方は無限大、ぜひやってみてください!!

「ウィルゲート Advent Calendar 2024(https://adventar.org/calendars/10272)」、翌日は中尾さんによる「 【フロントエンド改修事例】既存プロダクトのReactにCompound Components Petternを導入しました【コンポーネント設計】 」です。乞うご期待!