0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

複数の Git リポジトリの状態を一括確認する Bash スクリプト

0
Last updated at Posted at 2026-05-17

複数のリポジトリを並行して開発していると、1日の開始・終了時に「リモートと同期しているか」「ローカルに変更はないか」と確認して回るのも少し面倒だと思います。

なので、複数の Git リポジトリの状態を一括確認する Bash スクリプトを書きました。

実行すると下図のように「リモートと同期しているか」「ローカルに変更はないか」を一括で確認できます。

image.png

スクリプト

スクリプトは以下です。Git ホストは問いません (github.com でなくても OK です)。

以下の変数を設定ください。

  • repos — ここにローカルリポジトリ一覧を記入ください。
  • ssh_key — リポジトリに SSH 接続する場合はその秘密鍵のパスに変更してください。開始時に リポジトリに SSH 接続しますか? (y/n): と訊かれるので y と入力した後 ssh-agent に秘密鍵のパスフレーズをキャッシュさせてください。
    • 親プロセスでキャッシュ済の場合は訊かれません (自動で利用します)。
    • もし HTTPS 接続 git ls-remote https://git_host/xxx/yyy.git でリモートのコミットハッシュが取れるなら秘密鍵をキャッシュしなくても構いません (origin が SSH URL であっても、HTTPS URL に変換して接続します)。
    • 秘密鍵がキャッシュ済かつ origin が SSH URL ならまず SSH 接続を試み、その後 HTTPS 接続を試みます。

以下の制限があります。

  • ローカルが main ブランチでない場合はリモート最新コミットと比較しません。
  • SSH 接続するリポジトリは秘密鍵が全て共通の想定です (ホスト混在未対応)。
  • リポジトリの origin が SSH URL だが秘密鍵をキャッシュせず HTTPS 接続を試みる場合は、SSH リポジトリの SSH URL が git@git_host:xxx/yyy.git で、HTTPS URL が https://git_host/xxx/yyy.git である想定で URL を変換します。
check.sh
#!/usr/bin/env bash
ssh_key="${HOME}/.ssh/id_ed25519"  # 秘密鍵 (リポジトリに SSH 接続するなら必須)

check_key_cached() {
  # キャッシュ済み鍵一覧に ssh_key の fingerprint が含まれるか確認します
  local fp="$(ssh-keygen -lf "$ssh_key" | awk '{print $2}')"
  ssh-add -l 2>/dev/null | grep -q "$fp"
}

check_latest() {
  # ローカル最新コミットとリモート最新コミットが同一か確認します
  local branch="$(git branch --show-current)"
  if [ "$branch" != "main" ]; then
    echo -e "\033[93mローカルが main ブランチではない\033[0m"
    return 1
  fi
  local local_hash="$(git rev-parse HEAD)"
  local url="$(git remote get-url origin)"
  local remote_hash=''
  if [[ "$url" == git@*:* ]] && check_key_cached; then
    # (1) origin が SSH URL かつ鍵がキャッシュ済みなら SSH 接続します
    echo "リモートに SSH 接続します"
    remote_hash="$(git ls-remote origin 'refs/heads/main' 2>/dev/null | awk '{print $1}')"
  fi
  if [[ -z "$remote_hash" ]]; then
    # (2) SSH 接続しない場合、または SSH 接続に失敗した場合は HTTPS 接続します
    echo "リモートに HTTPS 接続します"
    https_url="$(echo "$url" | sed -E 's#^git@([^:]+):#https://\1/#')"
    remote_hash="$(git ls-remote "$https_url" 'refs/heads/main' | awk '{print $1}')"
  fi
  if [[ -z "$remote_hash" ]]; then
    echo -e "\033[93mリモートリポジトリへの接続に失敗\033[0m"
    return 1
  fi
  echo "local : $local_hash"
  echo "remote: $remote_hash"
  if [ "$local_hash" = "$remote_hash" ]; then
    echo -e "\033[92mローカル最新コミットとリモート最新コミットが同一です\033[0m"
  else
    git merge-base --is-ancestor "$remote_hash" "$local_hash" >/dev/null 2>&1
    if [ $? -eq 0 ]; then
      echo -e "\033[91mローカル最新コミットが未プッシュです\033[0m"
    else
      echo -e "\033[91mリモート最新コミットが未マージです\033[0m"
    fi
  fi
}

check_status() {
  # ローカルに変更があるか確認します
  local flag=0
  local status="$(git status --porcelain)"
  local msg0="\033[92mローカルに変更はありません\033[0m"
  local msg1="\033[91mステージ済の変更があります\033[0m"
  local msg2="\033[91m未ステージの変更があります\033[0m"
  local msg3="\033[93m未追跡のファイルがあります\033[0m"
  echo "$status" | grep -q '^[MADRC]' && { echo -e "$msg1"; flag=1; }
  echo "$status" | grep -q '^.[MD]' && { echo -e "$msg2"; flag=1; }
  echo "$status" | grep -q '^??' && { echo -e "$msg3"; flag=1; }
  [ $flag -eq 0 ] && echo -e "$msg0"
}

# ========== MAIN ==========
# 秘密鍵が未キャッシュならキャッシュします
# 全リポジトリに HTTPS 接続できる (git ls-remote https://git_host/xxx/yyy.git が通る)
# 場合は秘密鍵のキャッシュは必須ではありません
# Ex. GitHub パブリックリポジトリは HTTPS 接続できます
# Ex. GitHub プライベートリポジトリでも PAT 認証などがあれば HTTPS 接続できます
if check_key_cached; then
  echo "${ssh_key} はキャッシュ済です"
else
  read -p "リポジトリに SSH 接続しますか? (y/n): " ans
  if [ "$ans" = 'y' ]; then
    ssh-add "$ssh_key" || {
      eval "$(ssh-agent -s)"
      ssh-add "$ssh_key"
    }
  fi
fi
# 各リポジトリの状態を一括確認します
repos=(
  # 以下にローカルリポジトリ一覧を記入 (HOME からの相対パスで)
  ".local/share/chezmoi"
  "workspace/nazuna"
  "workspace/cookipedia"
)
for repo in "${repos[@]}"; do
  echo -e "\033[96m===== $repo =====\033[0m"
  repo_dir="${HOME}/${repo}"
  [ -d "$repo_dir" ] || { echo -e "\033[93mディレクトリがない\033[0m"; continue; }
  (
    cd "$repo_dir"
    check_latest
    check_status
  )
done

おまけ: (chezmoi 利用者向け) chezmoi リポジトリについてはローカルとソースの差異まで確認する場合

chezmoi を利用している場合、これについては「ソースディレクトリがリモートリポジトリと同期しているか」だけでは不十分で、「ローカルがソースディレクトリと同期しているか」まで確認しておきたくなると思います。

その場合、スクリプトに以下の関数を追記してください。

check_chezmoi() {
  # chezmoi についてはローカルとソースの差異も確認します
  if [ -z "$(chezmoi diff)" ]; then
    echo -e "\033[92mローカルはソースと同一です\033[0m"
  else
    echo -e "\033[91mローカルとソースに差異があります\033[0m"
  fi
}

そして、サブシェル内に以下を追記してください。

  (
    cd "$repo_dir"
    check_latest
    check_status
    [ "$repo" = ".local/share/chezmoi" ] && check_chezmoi  # これを追記
  )

ローカルとソースディレクトリに差分がないと以下のようになります。
image.png
ローカルとソースディレクトリに差分があると以下のようになります。
image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?