公開 GitHub リポジトリを長期保存したいなら、自分のアカウント配下に専用の Private ミラーを作る方法があります。

ここでいう「ミラー」は通常の git clone ではありません。git clone --mirror と git push --mirror を使い、Git refs をできるだけそのまま別リポジトリへ同期します。

これはソースコードレベルのバックアップとして便利ですが、GitHub プロジェクト全体の完全バックアップではありません。Issues、Pull Requests、Release 添付、Repository Settings、Secrets などの GitHub プラットフォーム側データは別です。Git LFS を使っている場合は LFS オブジェクトも追加で同期する必要があります。

注意: git push --mirror は「追加」ではなく「同期」です。対象リポジトリにだけ存在する refs を削除したり、同名 refs を強制更新したりできます。バックアップ専用の空 Private リポジトリを使うのが安全です。

どんな用途に向いているか

この方法は次のようなケースに向いています。

  • 依存している OSS の完全な Git 履歴を手元に残したい
  • 上流が削除、改名、非公開化されてもコードを保持したい
  • 上流の branch / tag を定期同期したい
  • Fork として開発参加するのではなく、復旧用コピーを持ちたい

コードを変更して上流へ PR を送りたいなら Fork の方が自然です。単に読むだけなら通常の clone で十分です。

mirror で保存されるもの / されないもの

git clone --mirror は bare mirror repository を作成し、遠隔 refs を追跡する設定も含めます。

主に保存できるのは次です。

  • Git commit 履歴
  • branch refs
  • tag refs
  • その他の遠隔 Git refs
  • Git object

一方、次は自動では入りません。

  • Issues
  • Pull Requests
  • Discussions
  • Release 添付
  • Actions Secrets / Variables
  • Webhook
  • Collaborators / 権限
  • Branch protection / Rulesets
  • Repository visibility

Git LFS の大きなファイルも、Git 側には pointer が保存されるため実体を別途転送します。

事前準備

ローカルには次を用意します。

  • Git
  • GitHub CLI (gh)
  • 必要なら Git LFS

GitHub CLI のログイン状態を確認します。

gh auth status
gh auth setup-git

未ログインなら、

gh auth login

を使います。

PAT、パスワード、Cookie、秘密鍵をリポジトリ URL やスクリプトへ直接書かない方が安全です。GitHub CLI の credential 設定か SSH を使います。

初回の Private ミラー作成

例えば次の公開リポジトリを保存するとします。

https://github.com/OWNER/REPOSITORY

専用ディレクトリで次のように実行できます。

set -euo pipefail

UPSTREAM_URL="https://github.com/OWNER/REPOSITORY.git"
REPO_NAME="REPOSITORY"
ACCOUNT="$(gh api user --jq .login)"
BACKUP_REPO="$ACCOUNT/$REPO_NAME"
BACKUP_URL="https://github.com/$BACKUP_REPO.git"
MIRROR_DIR="$REPO_NAME.git"

if gh repo view "$BACKUP_REPO" >/dev/null 2>&1; then
  echo "Target repository already exists: $BACKUP_REPO"
  exit 1
fi

if [ -e "$MIRROR_DIR" ]; then
  echo "Local path already exists: $MIRROR_DIR"
  exit 1
fi

gh repo create "$BACKUP_REPO" --private

git clone --mirror "$UPSTREAM_URL" "$MIRROR_DIR"

git -C "$MIRROR_DIR" remote add backup "$BACKUP_URL"

git -C "$MIRROR_DIR" push --mirror backup

ここでは二つの停止条件を重要視しています。

  1. 同名の対象リポジトリがすでにあれば停止する
  2. ローカル mirror ディレクトリがすでにあれば停止する

どちらも「とりあえず上書き」はしません。

なお、Private / Public は GitHub リポジトリ側の設定です。git push 自体が visibility を変更するわけではありません。

なぜ普通の clone + push ではないのか

通常の clone は日常開発向けで、作業ツリーと現在の branch を中心に扱います。

ミラーの目的は、上流の Git refs をできるだけそのまま別の Git リポジトリへ保存することです。

git clone --mirror "$UPSTREAM_URL" "$MIRROR_DIR"

で作るディレクトリは bare repository で、普通の作業ツリーはありません。バックアップ専用タスクなら、その方が構造が明確です。

2 回目以降の増分同期

初回ミラー後は毎回 clone し直す必要はありません。

git -C REPOSITORY.git fetch --prune origin
git -C REPOSITORY.git push --mirror backup

ここで、

  • origin は公開上流
  • backup は自分の Private ミラー

です。

fetch --prune origin で上流の最新 refs を取得し、上流から消えた refs も整理します。その状態を push --mirror backup で対象へ反映します。

ミラー置き場を固定しているなら絶対パスでも構いません。

git -C "$HOME/git-mirrors/REPOSITORY.git" fetch --prune origin
git -C "$HOME/git-mirrors/REPOSITORY.git" push --mirror backup

Git LFS は別に同期する

上流が Git LFS を使っているなら、refs の同期だけでは足りません。

まず確認します。

git lfs version

その後、mirror 内で LFS オブジェクトを取得し、backup 側へ送ります。

git -C REPOSITORY.git lfs fetch --all origin
git -C REPOSITORY.git lfs push --all backup

更新時は例えば次の順番です。

git -C REPOSITORY.git fetch --prune origin
git -C REPOSITORY.git lfs fetch --all origin
git -C REPOSITORY.git lfs push --all backup
git -C REPOSITORY.git push --mirror backup

--all は大規模リポジトリでは時間がかかり、GitHub LFS のストレージ / 転送量も消費する点に注意します。

本当に同期できたか確認する

まず対象が Private であることを確認します。

ACCOUNT="$(gh api user --jq .login)"

gh repo view "$ACCOUNT/REPOSITORY"   --json nameWithOwner,visibility,defaultBranchRef

次に上流と backup の refs / object ID を比較します。

UPSTREAM_URL="https://github.com/OWNER/REPOSITORY.git"
ACCOUNT="$(gh api user --jq .login)"
BACKUP_URL="https://github.com/$ACCOUNT/REPOSITORY.git"

git ls-remote --refs "$UPSTREAM_URL"   | awk '{print $1, $2}'   | sort > /tmp/upstream-refs.txt

git ls-remote --refs "$BACKUP_URL"   | awk '{print $1, $2}'   | sort > /tmp/backup-refs.txt

diff -u /tmp/upstream-refs.txt /tmp/backup-refs.txt

diff に出力がなく終了コードが 0 なら、現在列挙される refs と object ID は一致しています。

LFS がある場合は、Private 側から実際に clone / checkout して、大きなファイルをダウンロードできることまで確認した方が安心です。

push —mirror で最も危険な点

覚えておくべきことは一つです。

Mirror は「追加バックアップ」ではなく「状態を一致させる操作」です。

対象にしかない refs は削除される可能性があります。同名 ref が別 object を指していれば強制更新される可能性もあります。

そのため私は次を固定ルールにしています。

  • 一つの上流につき一つの専用 Private mirror
  • mirror 側で独自 branch を開発しない
  • 普通の共同開発リポジトリとして使わない
  • 初回 push 前に対象が空であることを確認する
  • 自動化する前に一度手動で通す

自動化するなら安全条件を増やす

複数の公開リポジトリを長期保存するなら、cron や CI にできます。

git -C "$MIRROR_DIR" fetch --prune origin

if git -C "$MIRROR_DIR" lfs env >/dev/null 2>&1; then
  git -C "$MIRROR_DIR" lfs fetch --all origin
  git -C "$MIRROR_DIR" lfs push --all backup
fi

git -C "$MIRROR_DIR" push --mirror backup

ただし無人実行では、少なくとも次を固定するべきです。

  • 許可する上流 URL
  • push 先の backup repository
  • 対象が想定外なら即終了

push --mirror では、スクリプトを短くすることより、誤ったリポジトリへ push しないことの方が重要です。

CLI Agent に依頼する場合の境界

AI エージェントに作業させるなら、「バックアップして」だけでは足りません。

例えば次のように停止条件まで書きます。

指定した公開 GitHub リポジトリを、現在ログインしている GitHub アカウント配下の同名 Private リポジトリへ完全ミラーしてください。

要件:
1. git、gh、gh auth status を先に確認する。
2. 公開 URL からリポジトリ名を取得する。
3. 同名の対象リポジトリが存在する場合は停止し、上書きしない。
4. ローカル mirror ディレクトリが存在し、用途が不明なら停止して削除しない。
5. 空の Private リポジトリを作る。Fork は作らない。
6. git clone --mirror を使う。
7. backup remote を追加し、git push --mirror backup を実行する。
8. Git LFS を使う場合は LFS object も同期する。
9. visibility=PRIVATE を確認し、両側の git ls-remote --refs を比較する。
10. 次回更新用の fetch --prune + push --mirror コマンドを提示する。

安全条件:
- Token、パスワード、Cookie、秘密鍵を表示・要求しない。
- 公開元リポジトリを変更しない。
- 既存リポジトリや不明なローカルディレクトリを削除しない。
- 対象リポジトリに既存内容がある場合は停止する。
- 関係ない本番デプロイを実行しない。

エージェントに重要なのは、作業内容だけでなく「どの状態なら止まるか」を伝えることです。

この方法の境界

これは Git repository mirror backup であり、GitHub 全体の disaster recovery ではありません。

完全な GitHub プロジェクト保全が必要なら、さらに次を考える必要があります。

  • Issues / Pull Requests
  • Releases / 添付
  • Wiki
  • Actions 設定と variables
  • Repository permissions / rules
  • Packages / Container images
  • Discussions

ただ、目的が「公開リポジトリが将来消えても、ソース履歴、branch、tag を自分で保持したい」なら、clone --mirror + push --mirror はシンプルで検証しやすい方法です。

公式資料