Skip to content

Simple utilities to transfer all forked repos from your account to another organization in order to declutter your profile

Notifications You must be signed in to change notification settings

hesreallyhim/transfer-github-forks

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Fork Transfer & Local Remote Fix Tools

This repository contains two Bash scripts (macOS-compatible) that help you migrate GitHub forks from your personal account into an organization, and then update your local Git remotes to point to the new org repositories.

Both scripts are safe by default (dry-run mode) and fully compatible with Bash 3.2 (the macOS default Bash).


🧩 Main Scripts Overview

Script Purpose
transfer-forks.sh Scans your personal forks, transfers eligible ones to an organization, and records a mapping file (~/.fork_transfer_map.tsv).
fix-local-remotes.sh Reads that mapping file and updates local clones’ origin URLs to point to the new organization repos.

⚙️ Usage Summary

Script Flag / Argument Description
transfer-forks.sh <your-username> Your GitHub username (owner of the forks).
<target-org> Target organization to transfer forks into.
--execute Actually perform transfers (otherwise dry-run).
--delete-inactive Delete inactive forks left in your account.
--inactive-days N Days since last push to consider a fork inactive (default: 120).
--limit N Process at most N eligible (post-skip) repos in this run.
--debug Enable detailed execution trace and logging to ~/transfer-forks-debug.log.
fix-local-remotes.sh <local-clone-root> Directory under which your local clones live.
--execute Apply remote changes (otherwise dry-run).
--debug Enable xtrace and logging to ~/fix-remotes-debug.log.

✅ Example Workflows

Dry-run transfer (simulate only)

./transfer-forks.sh myuser myorg --limit 10

Execute transfers

./transfer-forks.sh myuser myorg --execute

Delete inactive forks

./transfer-forks.sh myuser myorg --execute --delete-inactive --inactive-days 90

Fix local remotes (dry-run, then apply)

./fix-local-remotes.sh ~/projects/forks
./fix-local-remotes.sh ~/projects/forks --execute

🔐 Permissions, Tokens, and Scopes

To successfully perform transfers using the GitHub API:

  • You must have admin access to each repository being transferred.
  • You must have create repository permission in the target organization.
  • The organization must not already have:
    • A repository with the same name, or
    • Another fork in the same fork network.
  • Private forks cannot be transferred if their upstream repository is also private.

🔑 Token Requirements

When authenticating via the GitHub CLI (gh auth login), use one of the following:

Classic Personal Access Token (PAT)

Required scopes:

  • repo — Full control of private and public repos.
  • admin:org — To create repos and perform transfers into the target org.
  • If the org enforces SSO, the PAT must be SSO-authorized for that org.

Fine-Grained Personal Access Token

  • Required repository permissions:
  • Administration: Read & Write
  • Contents: Read & Write
  • Organization access must be explicitly granted to the target org.

Verification

You can verify your token’s scopes with:

gh auth status
gh auth token

If a transfer fails with 403 or 404, confirm that your token covers both repo administration and org creation rights.


🧠 Script Behavior and Safety

  • Dry-run by default – no irreversible changes unless --execute is given.
  • Mapping file: ~/.fork_transfer_map.tsv stores tab-separated lines old_full<TAB>new_full.
  • Deduplication: Runs automatically after each transfer batch.
  • Logging: Timestamps printed for every action.
  • Limit (--limit) applies to attempted transfers, not scanned forks.
  • Error handling: Failures are logged but don’t stop other repos.
  • PR protection: Forks with open PRs you authored in their upstream are skipped.

🐛 Debug Logging

Both scripts support a --debug flag.

When enabled:

  • Turns on Bash xtrace (set -x).
  • Captures stdout + stderr to:
    • ~/transfer-forks-debug.log
    • ~/fix-remotes-debug.log
  • Still echoes output to the console.
  • Useful for troubleshooting gh API failures, permission errors, or unexpected skips.
./transfer-forks.sh myuser myorg --execute --limit 5 --debug
./fix-local-remotes.sh ~/projects/forks --execute --debug

🧼 Clean Run / Resetting State

If you performed a partial transfer (e.g. --limit 10) and want to restart fresh:

  1. Delete transferred repos from your org (if you want to re-transfer them).
  2. Remove the mapping file:
rm -f ~/.fork_transfer_map.tsv
  1. Run transfer-forks.sh again for a clean run. To automate this, you can use clean-run.sh:
#!/usr/bin/env bash
# clean-run.sh – removes all transferred forks from the org and resets mapping.
MAPPING_FILE="${HOME}/.fork_transfer_map.tsv"
[ ! -f "$MAPPING_FILE" ] && echo "No mapping file found." && exit 0

read -p "Delete all mapped repos from org and reset mapping? (y/N) " resp
[[ "$resp" != [yY] ]] && echo "Aborted." && exit 0

while IFS=$'\t' read -r old new; do
  [ -z "$new" ] && continue
  echo "Deleting $new ..."
  gh repo delete "$new" --yes || echo "Warning: failed to delete $new"
done < "$MAPPING_FILE"

rm -f "$MAPPING_FILE"
echo "Mapping cleared. Ready for a clean run."

⚠️ Redirect Behavior & Caveats

When a repo is transferred, GitHub automatically redirects all git and HTTP operations from the old path to the new one.

However, updating remotes is still recommended because:

  1. Redirects introduce slight latency and confusion in git remote -v.
  2. Your local config continues to reference the outdated location.
  3. Redirects are removed if a new repo later occupies the old path.
  4. GitHub Pages (username.github.io/repo) do not redirect after transfer.

Reference: GitHub Docs — About repository transfers


⚠️ Limitations & Considerations

  • Private upstream forks generally cannot be transferred.
  • Transfers fail if name conflicts or existing forks exist in the target org.
  • Old repo URLs continue working via redirects, but updating is cleaner.
  • Scripts assume clone directory names match repo names exactly.
  • Only the origin remote is updated; custom remote names are ignored.

🧩 Script Summary

transfer-forks.sh → Moves forks from your personal account to an org, logs results to ~/.fork_transfer_map.sh.

fix-local-remotes.sh

  • Reads ~/.fork_transfer_map.tsv.
  • For each mapping:
  • Finds local directory named after the repo.
  • Checks .git presence.
  • Updates or adds origin URL, preserving SSH/HTTPS scheme.
  • Skips already-correct remotes.
  • Provides a concise per-repo log and a summary at the end.

📊 Final Output Example

[2025-10-14T00:30:02Z] TRANSFER user/foo → org/foo [dry-run=true]
[2025-10-14T00:30:02Z] OK transferred: user/foo → org/foo
[2025-10-14T00:30:02Z] Done. Transferred: 1, Deleted: 0, Attempted: 1, Scanned: 3 (execute=false, limit=1)
[2025-10-14T00:30:02Z] Mapping persisted at: /Users/you/.fork_transfer_map.tsv

✅ Final Summary

Script Function Key Options
transfer-forks.sh Transfers forks to an organization and records mappings. --execute, --limit, --debug
fix-local-remotes.sh Updates local clones’ origin URLs to match transferred repos. --execute, --debug
clean-run.sh Deletes mapped repos and clears state for a clean rerun. (no flags)

All scripts are safe, idempotent, and designed for incremental migration of large numbers of forks.

About

Simple utilities to transfer all forked repos from your account to another organization in order to declutter your profile

Topics

Resources

Stars

Watchers

Forks

Sponsor this project

 

Languages