はじめに
マイクロサービス化が進むと、リポジトリが複数に分かれてしまい、「あの定義、どこに書いてあったっけ?」と探すのが大変になることがよくあります。
特に、main ブランチだけでなく、「開発中の develop ブランチ」や「特定の機能改修ブランチ(feature/xxx)」も含めて横断検索(grep)したい場合、いちいち全てのリポジトリでブランチを切り替えるのは手間です。
そこで、「指定したリポジトリの、指定したブランチだけをサクッと1つのフォルダに書き出すシェルスクリプト」を作成しました。
Macの標準Bash(古いバージョン)でも動作するように作成しています。
やりたいこと
- 複数のリポジトリ(7つ程度)がある。
- リポジトリごとに「集めたいブランチ」が異なる(あるものは
mainだけ、あるものはdevelopとfeature/Aなど)。 -
.gitディレクトリは不要(検索用なのでソースコードだけ欲しい)。 - 1つのフォルダ(
Collected_Source)に集約して、VS Codeなどで一発検索したい。
ソースコード
このスクリプトを、リポジトリが並んでいるディレクトリと同じ階層に置いて実行します。
#!/bin/bash
# ================= 設定エリア =================
# 1. 処理するリポジトリのディレクトリ名を配列で列挙
REPOS=(
"common-lib"
"auth-service"
"order-api"
"payment-service"
"frontend-web"
"batch-worker"
)
# 2. 出力先ディレクトリ
OUTPUT_BASE="./Selected_Source"
# ============================================
echo "=== Start collecting branches ==="
mkdir -p "$OUTPUT_BASE"
for repo in "${REPOS[@]}"; do
# リポジトリの存在確認
if [ ! -d "$repo" ]; then
echo "Warning: Directory '$repo' not found. Skipping."
continue
fi
echo "--------------------------------------------------"
echo "Processing Repository: $repo"
# ============================================
# 3. リポジトリごとの取得したいブランチをここで定義
# MacOSの古いBashでも動くよう case文 を使用
# ============================================
BRANCHES=""
case "$repo" in
"common-lib")
# 共通ライブラリは main と develop を確認したい
BRANCHES="main develop"
;;
"order-api")
# 開発中の大規模改修ブランチも含める
BRANCHES="main develop feature/big-refactor"
;;
"payment-service")
# リリース済みのみ
BRANCHES="prod"
;;
"frontend-web")
BRANCHES="main develop fix/login-bug"
;;
*)
# 上記以外はデフォルトで main のみにする
BRANCHES="main"
;;
esac
# ============================================
# 指定されたブランチをループ処理
for branch in $BRANCHES; do
echo " Target: $branch"
# ブランチ名の解決
target_ref="$branch"
# ローカルになければ origin/ をつけてリモートブランチを探す
if ! git -C "$repo" rev-parse --verify "$target_ref" >/dev/null 2>&1; then
if git -C "$repo" rev-parse --verify "origin/$target_ref" >/dev/null 2>&1; then
target_ref="origin/$target_ref"
echo " -> Found as remote branch: $target_ref"
else
echo " [Error] Branch '$branch' not found in $repo. Skipping."
continue
fi
fi
# 出力先ディレクトリ作成
# スラッシュを含むブランチ名(feature/xxx)も階層としてそのまま作成
dest_dir="$OUTPUT_BASE/$repo/$branch"
if [ -d "$dest_dir" ]; then
echo " [Skip] Destination already exists."
continue
fi
mkdir -p "$dest_dir"
# git archive で書き出し(ここがポイント)
# .git フォルダを含まず、高速にファイルのみを展開
git -C "$repo" archive "$target_ref" | tar -x -C "$dest_dir"
if [ $? -eq 0 ]; then
echo " [OK] Exported to $dest_dir"
else
echo " [Fail] Export failed."
fi
done
done
echo "=================================================="
echo "Done! Aggregated in: $OUTPUT_BASE"
ポイント
1. git archive を使う
git clone や cp ではなく、git archive を使用しています。
- 高速: 必要なファイルだけをストリームで取り出せます。
-
クリーン:
.gitフォルダが含まれないため容量が軽く、検索時のノイズになりません。 - 安全: 現在のワークツリー(作業中のファイル)を変更せずに済みます。
2. case 文による分岐
MacOSのデフォルトBash(バージョン3系)では、連想配列(declare -A)が使えません。
そのため、リポジトリ名に応じたブランチ指定には case 文を使用し、環境を選ばず動くようにしています。
3. リモートブランチの自動解決
ローカルにブランチがない場合(checkout していない場合)でも、自動的に origin/ を付与してリモートブランチを探しに行くロジックを入れています。これにより git fetch さえしてあれば、checkout不要で抽出できます。
使い方
-
上記スクリプトを
collect_branches.shとして保存。 -
REPOS配列とcase文の中身を自分のプロジェクトに合わせて書き換え。 -
実行権限を付与して実行。Bash
chmod +x collect_branches.sh ./collect_branches.sh -
生成された
Selected_Sourceディレクトリを VS Code で開き、全文検索(Ctrl+Shift+F)するだけ!
これで、「あのユースケース、どのブランチのどこで定義されてるんだっけ?」という調査が爆速になりました。