Skip to main content

Git Repository Migration Guide

When to Use​

When you want to migrate an entire repository from one hosting platform to another while preserving branches, tags, and other refs, a mirror migration is usually the safest approach.

Common scenarios include:

  • Migrating from Gitee to GitHub
  • Migrating from a personal repository to an organization repository
  • Preserving full history and tags, not just the default branch

Check Current State First​

  • The target repository should ideally be a newly created empty repository to avoid --mirror overwriting existing refs.
  • Confirm you have read/write access to both the source and target repositories.
  • If the repository uses Git LFS, large file objects need additional migration -- a simple git push --mirror won't handle them.

Full Migration of All Branches and Tags​

git clone --mirror git@gitee.com:username/repo-name.git repo-name.git
cd repo-name.git
git remote set-url origin git@github.com:username/repo-name.git
git push --mirror

This set of commands migrates all refs, not just the current branch.

Common Scenarios​

Basic Checks After Migration​

git remote -v
git for-each-ref --format='%(refname:short)' refs/heads refs/tags
git ls-remote --heads --tags origin

Just Want to Point the Working Copy to a New Remote​

If you're not doing a "full repository mirror migration" but just want to switch an existing working directory to a new remote:

git remote set-url origin https://github.com/username/repo-name.git
git remote -v

Repository Uses Git LFS​

git push --mirror only syncs Git refs -- it won't automatically upload LFS large file objects. In this case, run the following in a regular working copy:

git clone git@gitee.com:username/repo-name.git repo-name
cd repo-name
git lfs fetch --all
git remote add github git@github.com:username/repo-name.git
git lfs push --all github

If you haven't configured Git LFS yet, see Cloning Large Files with Git LFS.

Optional Advanced Operation: Rewrite Commit Email Addresses​

If your goal is to have old commits attributed to a new email in GitHub Contributions, use git filter-repo -- don't treat git filter-branch as the default choice.

Operate in a temporary mirror copy:

git filter-repo --commit-callback '
if commit.author_email == b"old-email@example.com":
commit.author_name = b"Your Name"
commit.author_email = b"github-email@example.com"
if commit.committer_email == b"old-email@example.com":
commit.committer_name = b"Your Name"
commit.committer_email = b"github-email@example.com"
'
git push --force --mirror

This rewrites history and is only appropriate when you fully understand the consequences and have coordinated with collaborators.

Risks and Boundaries​

  • git push --mirror makes the target refs identical to the local mirror -- it will also delete refs that exist on the target but not locally.
  • If the target repository already has a README, initial commit, or default tags, the mirror push may overwrite them.
  • History-rewriting operations change commit hashes; if anyone has already developed based on the old history, you must coordinate in advance.
  • git filter-branch still works, but it's now considered a legacy tool and is not recommended as the default approach.