Bulk GitHub Repository Sync
ActionsTags
(2)🔄 Sync GitHub repositories from source to target organizations using mirror cloning. Creates target repositories if they don't exist, with support for visibility control, Actions disabling, and archiving.
- 🔄 Mirror cloning - Complete repository sync including all branches and tags
- 🏗️ Automatic repository creation - Creates target repos if they don't exist
- 👁️ Visibility control - Set repository visibility per repo (private/public/internal)
- 🚫 GitHub Actions management - Disable Actions on target repositories
- 📦 Repository archiving - Archive repositories after sync (with smart unarchive/re-archive)
- 🌐 Multi-server support - Sync between github.com and GitHub Enterprise Server
- 📊 Post-run analysis - Detailed sync summary with statistics
Tip
This example uses personal access tokens for simplicity. See the GitHub Apps section below for the recommended approach using GitHub Apps.
- uses: actions/checkout@v5
- name: Bulk GitHub Repository Sync
uses: joshjohanning/bulk-github-repo-sync-action@v1
with:
repo-list-file: repos.yml
source-github-token: ${{ secrets.SOURCE_GITHUB_TOKEN }}
target-github-token: ${{ secrets.TARGET_GITHUB_TOKEN }}
overwrite-repo-visibility: true # overwrite repo visibility with what is in yml file; defaults to false
force-push: false # force push to target repos (overwrites history); defaults to false
### these parameters are only needed if either your source or target is NOT github.com
# source-github-url: ${{ github.server_url }} # defaults to https://github.com
# source-github-api-url: ${{ github.api_url }} # defaults to https://api.github.com
# target-github-url: ${{ github.server_url }} # defaults to https://github.com
# target-github-api-url: ${{ github.api_url }} # defaults to https://api.github.com
The repository list uses YML format with per-repository configuration:
repos:
- source: source-org/source-repo-1
target: target-org/target-repo-1
visibility: private # Optional: private, public, or internal (defaults to private)
disable-github-actions: true # Optional: disable Actions on target repo (defaults to true)
archive-after-sync: false # Optional: archive repo after sync (defaults to false)
See sample file.
You can use a personal access token, but it is recommended to use GitHub Apps instead:
Note
Required GitHub App Permissions:
- Source App: Repository Read access to
contents
andmetadata
- Target App: Repository Read and Write access to
actions
,administration
,contents
, andmetadata
- uses: actions/checkout@v5
# source
- uses: actions/create-github-app-token@v2
id: source-app-token
with:
app-id: ${{ vars.SOURCE_APP_ID }}
private-key: ${{ secrets.SOURCE_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
# target
- uses: actions/create-github-app-token@v2
id: target-app-token
with:
app-id: ${{ vars.TARGET_APP_ID }}
private-key: ${{ secrets.TARGET_APP_PRIVATE_KEY }}
owner: joshjohanning-emu
- name: Bulk GitHub Repository Sync
uses: joshjohanning/bulk-github-repo-sync-action@v1
with:
repo-list-file: repos.yml
source-github-token: ${{ steps.source-app-token.outputs.token }}
target-github-token: ${{ steps.target-app-token.outputs.token }}
overwrite-repo-visibility: true # overwrite repo visibility with what is in yml file; defaults to false
# force push to target repos (overwrites history); defaults to false
Setting | Description | Default |
---|---|---|
source |
Source repository in owner/repo format |
- |
target |
Target repository in owner/repo format |
- |
visibility |
Repository visibility (private/public/internal) | private |
disable-github-actions |
Disable GitHub Actions on target repository | true |
archive-after-sync |
Archive repository after successful sync | false |
Input | Description | Required | Default |
---|---|---|---|
repo-list-file |
YML file with repository configurations | No | - |
source-github-token |
GitHub PAT for source repositories | Yes | - |
target-github-token |
GitHub PAT for target repositories | No | (uses source token if not specified) |
source-github-url |
Source GitHub server URL | No | ${{ github.server_url }} |
target-github-url |
Target GitHub server URL | No | ${{ github.server_url }} |
source-github-api-url |
Source GitHub API URL | No | ${{ github.api_url }} |
target-github-api-url |
Target GitHub API URL | No | ${{ github.api_url }} |
overwrite-repo-visibility |
Force update visibility of existing repos | No | false |
force-push |
Force push to target repositories (overwrites history) | No | false |
You can also run the script directly:
export SOURCE_GITHUB_TOKEN=ghp_abc
export TARGET_GITHUB_TOKEN=ghp_xyz
node src/index.js --file=repos.yml
=== SYNC SUMMARY ===
Total repositories: 5
✅ Successful: 5
❌ Failed: 0
🆕 Created: 2
🔄 Updated: 3
👁️ Visibility updated: 1
📦 Archived: 2
Bulk GitHub Repository Sync is not certified by GitHub. It is provided by a third-party and is governed by separate terms of service, privacy policy, and support documentation.