Fragments of verbose memory

冗長な記憶の断片 - Web技術のメモをほぼ毎日更新

Dec 27, 2025 - 日記

エンジニアの年末大掃除 2025(前編):統計で振り返る1年とGitリポジトリの棚卸し

エンジニアの年末大掃除 2025(前編):統計で振り返る1年とGitリポジトリの棚卸し

年末年始、あなたのホームディレクトリは大丈夫ですか?未コミットのコード、マージ済みなのに残っている放置ブランチ、1年以上触っていないプロジェクト…。新年を迎える前に、開発環境をクリーンな状態にリセットしましょう。

前編では、1年間の開発活動を統計で振り返り、Gitリポジトリの大掃除を行います。新しいRust製OSSツールと実用的なスクリプトで、効率的に整理していきましょう。

なぜ年末に大掃除が必要なのか

エンジニアの開発環境は、日々の作業で確実に「散らかって」いきます:

  • 未コミットの変更: 「後でコミットしよう」と思ったまま放置
  • 未プッシュのコミット: ローカルに溜まったまま年を越すリスク
  • 放置ブランチ: マージ済み・削除済みなのにローカルに残存
  • 古いプロジェクト: 1年以上触っていないディレクトリが容量を圧迫

年末は、これらを一掃する絶好のタイミングです。

📊 1年間の振り返り統計

まずは、自分が今年どんなコードを書いてきたのか、統計で振り返ってみましょう。

onefetch: リポジトリの美しいサマリー表示

onefetch は、Rust製のコマンドラインツールで、Gitリポジトリの統計情報をneofetch 風に美しく表示します。言語分布、コミット数、作成日、LOC(コード行数)などが一目でわかります。

インストール

# macOS
brew install onefetch

# [Cargo](https://doc.rust-lang.org/cargo/)経由(Rust環境がある場合)
cargo install onefetch

基本的な使い方

# カレントディレクトリのリポジトリ情報を表示
cd ~/work/my-project
onefetch

# ASCII artなしでコンパクトに表示
onefetch --no-art

実践例:全リポジトリのサマリーを一括表示

# ホームディレクトリ配下の全Gitリポジトリを巡回
find ~/work -name ".git" -type d 2>/dev/null | while read gitdir; do
    repo=$(dirname "$gitdir")
    cd "$repo"
    echo ""
    echo "=== $(basename $(pwd)) ==="
    onefetch --no-art --no-color-palette
done

このスクリプトで、全プロジェクトの統計を一覧できます。「あ、このプロジェクト今年1回しかコミットしてない」といった気づきが得られるでしょう。

シェル履歴の分析:よく使うコマンドTOP20

普段どんなコマンドを使っているか、確認してみましょう。

# Bash/Zshの履歴からよく使うコマンドTOP20を抽出
history | awk '{print $2}' | sort | uniq -c | sort -rn | head -20

実行結果の例:

  1523 git
   842 cd
   654 ls
   421 docker
   298 vim
   ...

統計の読み方アドバイス

統計データは、ただ眺めるだけでは意味がありません。以下の観点で解釈してみましょう:

コミット数の多寡

  • コミット数が多い ≠ 生産性が高い
    • 細かいコミットを心がけている可能性
    • リファクタリング作業が多かった可能性
    • 逆に、コミット数が少なくても大きな機能を実装している場合もある

よく触るファイル

  • 最も編集したファイル → あなたの専門領域
  • 長期間触っていないファイル → アーカイブ候補、または技術的負債の可能性

よく使うコマンド

  • gitが圧倒的に多い → バージョン管理を重視している
  • dockerの頻度が高い → コンテナ環境での開発が中心
  • npm installpip installが多い → 依存関係の管理に時間を取られている可能性

Gitリポジトリの統計を確認する開発者

GitHub統計の振り返り

ローカルリポジトリだけでなく、GitHubでの活動も振り返りましょう。GitHub CLI を使えば、コマンドラインから簡単に統計を取得できます。

GitHub CLIのインストール

# macOS
brew install gh

# Ubuntu/Debian
sudo apt install gh

# 認証
gh auth login

年間コントリビューション数の確認

# 自分のプロフィールを表示
gh api users/$(gh api user -q .login) | jq '{
  public_repos: .public_repos,
  public_gists: .public_gists,
  followers: .followers,
  following: .following
}'

# 今年作成したリポジトリ一覧
gh repo list --limit 100 --json name,createdAt,pushedAt \
  | jq '[.[] | select(.createdAt | startswith("2025"))]'

よく触るリポジトリTOP10

# 自分がコミットしたリポジトリを最終更新日順に表示
gh repo list --limit 100 --json name,pushedAt,isPrivate \
  | jq -r '.[] | "\(.pushedAt)\t\(.name)\t(private: \(.isPrivate))"' \
  | sort -r | head -10

Issue/PRの対応状況

# 自分が作成したIssueの統計
gh issue list --author @me --state all --limit 1000 --json state \
  | jq '[group_by(.state)[] | {state: .[0].state, count: length}]'

# 自分が作成したPRの統計
gh pr list --author @me --state all --limit 1000 --json state \
  | jq '[group_by(.state)[] | {state: .[0].state, count: length}]'

# 未対応のIssue/PRを確認
echo "=== Open Issues ==="
gh issue list --author @me --state open

echo "=== Open PRs ==="
gh pr list --author @me --state open

Star/Forkが多いリポジトリ

# 自分のリポジトリをStar数順に表示
gh repo list --limit 100 --json name,stargazerCount,forkCount \
  | jq -r 'sort_by(.stargazerCount) | reverse | .[] 
    | "\(.stargazerCount) ⭐ \(.forkCount) 🍴 \(.name)"' \
  | head -10

読み方のポイント:

  • 最終更新が3ヶ月以上前のリポジトリ → アーカイブまたは削除を検討
  • Starが0のリポジトリ → プライベートに変更、または整理対象
  • 未対応のIssue/PR → 年末に一気に対応またはクローズ

GitHub統計とアクティビティの確認

GitHub Actionsの棚卸し

GitHub Actionsのワークフローも、定期的に見直しが必要です。使われていないワークフローや失敗し続けているジョブを整理しましょう。

全リポジトリのワークフロー実行状況を確認

#!/bin/bash
# check-github-actions.sh
# 目的: 全リポジトリのGitHub Actions実行状況を確認

echo "🔍 GitHub Actions の実行状況をチェック中..."
echo ""

gh repo list --limit 100 --json name | jq -r '.[].name' | while read repo; do
    echo "=== $repo ==="
    
    # 最近のワークフロー実行を取得
    gh run list --repo $(gh api user -q .login)/$repo --limit 10 --json status,conclusion,name,createdAt 2>/dev/null | \
    jq -r '.[] | "\(.createdAt) | \(.name) | \(.status) | \(.conclusion // "running")"' 2>/dev/null
    
    echo ""
done

失敗し続けているワークフローの発見

# 特定リポジトリの失敗したワークフローを確認
gh run list --repo owner/repo --status failure --limit 20

# 失敗したワークフローの詳細を確認
gh run view <RUN_ID> --log-failed

対処方法:

  • 使っていないワークフロー.github/workflows/ から削除
  • 失敗し続けているジョブ → 原因を修正するか、無効化する
  • 古いActionバージョン → 最新版にアップデート(例:actions/checkout@v2@v4

不要なワークフローの削除

# .github/workflows/ 内のファイル一覧
find .github/workflows/ -name "*.yml" -o -name "*.yaml"

# 最終更新日を確認
ls -la .github/workflows/

# 不要なワークフローを削除
git rm .github/workflows/old-workflow.yml
git commit -m "chore: remove unused GitHub Actions workflow"

GitHub Issueの大掃除

長期間放置されたIssueは、プロジェクトの見通しを悪くします。年末に一気に整理しましょう。

古いIssueの一覧表示

# 1年以上更新されていないIssueを表示
gh issue list --repo owner/repo --state open --limit 100 --json number,title,updatedAt \
  | jq '.[] | select(.updatedAt < "2024-01-01") | {number, title, updatedAt}'

# 特定のラベルがついたIssueを表示
gh issue list --label "bug" --state open

古いIssueを一括クローズ

#!/bin/bash
# close-stale-issues.sh
# 目的: 1年以上更新されていないIssueを一括クローズ

REPO="owner/repo"
CUTOFF_DATE="2024-01-01"

gh issue list --repo $REPO --state open --limit 100 --json number,updatedAt \
  | jq -r ".[] | select(.updatedAt < \"$CUTOFF_DATE\") | .number" \
  | while read issue_num; do
    echo "Closing issue #$issue_num..."
    gh issue close $issue_num --repo $REPO --comment "このIssueは1年以上更新されていないため、年末の大掃除でクローズします。必要であれば再オープンしてください。"
done

ラベルの整理

# ラベル一覧を表示
gh label list --repo owner/repo

# 使われていないラベルを確認
gh label list --repo owner/repo --json name | jq -r '.[].name' | while read label; do
    count=$(gh issue list --repo owner/repo --label "$label" --state all --limit 1000 --json number | jq 'length')
    if [ "$count" -eq 0 ]; then
        echo "未使用: $label"
    fi
done

# 不要なラベルを削除
gh label delete "old-label" --repo owner/repo --yes

チェックポイント:

  • 1年以上更新されていないIssueをクローズまたはコメント
  • 重複ラベルを統合(例:bugBug
  • 使われていないラベルを削除
  • テンプレートの見直し(.github/ISSUE_TEMPLATE/

🗂️ Gitリポジトリの棚卸し

統計で振り返ったら、次は実際にリポジトリをクリーンアップしていきましょう。

未コミット・未プッシュの発見スクリプト

年末年始で作業が中断されると、未コミットのコードや未プッシュのコミットを忘れてしまうリスクがあります。以下のスクリプトで一括チェックしましょう。

#!/bin/bash
# ~/bin/git-status-all.sh
# 目的: ホームディレクトリ配下の全Gitリポジトリで未コミット・未プッシュを検出
# 使い方: ./git-status-all.sh

echo "🔍 未コミット・未プッシュのチェックを開始..."
echo ""

find ~ -name ".git" -type d 2>/dev/null | while read gitdir; do
    repo=$(dirname "$gitdir")
    cd "$repo"
    
    # 未コミットの変更があるか
    if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then
        echo "📝 未コミット: $repo"
        git status --short
        echo ""
    fi
    
    # 未プッシュのコミットがあるか
    if [ -n "$(git log @{u}.. 2>/dev/null)" ]; then
        unpushed_count=$(git log @{u}.. --oneline 2>/dev/null | wc -l | tr -d ' ')
        echo "⬆️  未プッシュ ($unpushed_count commits): $repo"
        git log @{u}.. --oneline
        echo ""
    fi
done

echo "✅ チェック完了"

保存したら実行権限を付与:

chmod +x ~/bin/git-status-all.sh
~/bin/git-status-all.sh

放置ブランチの一括削除

マージ済みのブランチや、リモートで削除されたブランチがローカルに残っていると、git branchの出力が煩雑になります。

手動で削除する場合

# リモートで削除されたブランチの参照を削除
git fetch --prune

# マージ済みのローカルブランチを一覧表示
git branch --merged main

# マージ済みブランチを一括削除(main/master/developを除く)
git branch --merged main | grep -v "main\|master\|develop" | xargs git branch -d

Rust製ツールを使う場合

放置ブランチの削除を自動化するRust製ツールがいくつかあります:

1. git-clean-gone

# インストール(Cargo経由)
cargo install git-clean-gone

# [gone]状態のブランチを削除
git clean-gone

2. git-clean (mcasper/git-clean)

# インストール
cargo install git-clean

# インタラクティブに削除するブランチを選択
git-clean

これらのツールは、git branch -vv[gone]と表示されるブランチ(リモートで削除済み)を自動検出して削除してくれます。

以前紹介したgit-absorb も便利ですが、ブランチ整理には今回紹介したツールが専門的です。

放置リポジトリの発見

1年以上更新のないリポジトリは、アーカイブ候補かもしれません。以下のスクリプトで古いリポジトリを検出しましょう。

#!/bin/bash
# 1年以上更新のないGitリポジトリを検出
# 使い方: ./find-stale-repos.sh

echo "🕰️  1年以上更新のないリポジトリを検索中..."
echo ""

find ~/work -name ".git" -type d 2>/dev/null | while read gitdir; do
    repo=$(dirname "$gitdir")
    cd "$repo"
    
    # 最新コミットの日付を取得
    last_commit=$(git log -1 --format=%ci 2>/dev/null | cut -d" " -f1)
    
    if [ -n "$last_commit" ]; then
        # 日付の差分を計算(macOS/Linuxで動作)
        if command -v date >/dev/null 2>&1; then
            # macOSの場合
            if date -j -f "%Y-%m-%d" "$last_commit" >/dev/null 2>&1; then
                last_epoch=$(date -j -f "%Y-%m-%d" "$last_commit" +%s 2>/dev/null)
            else
                # Linuxの場合
                last_epoch=$(date -d "$last_commit" +%s 2>/dev/null)
            fi
            
            current_epoch=$(date +%s)
            days_ago=$(( (current_epoch - last_epoch) / 86400 ))
            
            # 365日以上前の場合のみ表示
            if [ "$days_ago" -gt 365 ]; then
                size=$(du -sh "$repo" 2>/dev/null | cut -f1)
                echo "📦 $days_ago 日前: $repo ($size)"
            fi
        fi
    fi
done | sort -rn

echo ""
echo "✅ 検索完了"

検出されたリポジトリは、以下の選択肢を検討しましょう:

  1. アーカイブ: tar czf archive.tar.gz old-project/ で圧縮
  2. 削除: 不要なら削除(GitHub などにバックアップがあれば安心)
  3. 再開: 実は必要なプロジェクトだった場合は継続

Gitの履歴書き換えツールも活用

リポジトリの大掃除をより高度に行いたい場合は、Gitの黒歴史を隠蔽する:履歴書き換えツールまとめ で紹介したツールも活用できます。

まとめ:前編のチェックリスト

以下の項目を実施して、Gitリポジトリをクリーンな状態にしましょう:

  • onefetchで全リポジトリの統計を確認
  • シェル履歴でよく使うコマンドを分析
  • 未コミット・未プッシュのチェックスクリプトを実行
  • 放置ブランチを一括削除
  • 1年以上触っていないリポジトリをアーカイブ or 削除

次回の後編では、ディスク容量の奪還(node_modules、Docker images)とバックアップ体制の見直しを行います。お楽しみに!

参考リンク