🚀 Executive Summary
TL;DR: This guide addresses the problem of managing development across both Bitbucket and GitHub by providing a streamlined, two-command process to migrate repositories. It details how to perfectly transfer all Git history, branches, and tags from Bitbucket to an empty GitHub repository, unifying development workflows.
🎯 Key Takeaways
- Use `git clone –bare` to create a full mirror of the Bitbucket repository, capturing all commits, branches, and tags without a working directory.
- Employ `git push –mirror` to push the entire mirrored history, including all references, to the new GitHub repository.
- Always create a completely empty GitHub repository as the target to avoid ‘unrelated histories’ errors during the push.
- A GitHub Personal Access Token (PAT) with `repo` scope is required for authentication when pushing to GitHub.
- Configuring SSH URLs for both cloning and pushing can streamline the process by eliminating repeated credential entry.
Migrate Bitbucket Repositories to GitHub (Including Branches/Tags)
Hey there, Darian Vance here. Let’s get straight to it. For a long time at TechResolve, we had a split-brain problem: legacy projects on Bitbucket, new stuff on GitHub. Juggling two platforms for pull requests, CI/CD pipelines, and security scanning was a massive time sink. Consolidating everything into GitHub streamlined our entire workflow, and frankly, made my life easier. This isn’t just about moving files; it’s about unifying your development ecosystem. If you’re looking to do the same, this is the exact, no-frills process I use to migrate a repository perfectly, history and all, in under five minutes.
Prerequisites
Before we start, make sure you have the following ready. A little prep saves a lot of troubleshooting.
- Git CLI: You’ll need Git installed on your local machine.
- Bitbucket Repository URL: The HTTPS or SSH clone URL for the repository you want to migrate.
- An Empty GitHub Repository: Go to GitHub and create a new, completely empty repository. Do not initialize it with a README, license, or .gitignore file.
- GitHub Personal Access Token (PAT): You’ll need a PAT with `repo` scope to authenticate the push to your new GitHub repository. Treat this like a password.
The Step-by-Step Migration Guide
This process is all about creating a perfect, mirrored copy of the Git data itself, not just the files in the main branch. We’ll do this by performing a “bare” clone.
Step 1: Create a Full Mirror of the Bitbucket Repository
First, open your terminal. We’re not going to do a standard `git clone`. Instead, we’ll use the `–bare` flag. This downloads the entire Git object database—all the commits, branches, and tags—without creating a working directory with the actual files. It’s like copying the brain of the repository.
Navigate to a folder where you want to temporarily store the repository data and run this command:
git clone --bare https://bitbucket.org/your-workspace/your-repo.git
This will create a new directory named `your-repo.git`. All of our next steps will happen inside that directory.
Pro Tip: Using a bare clone is non-negotiable for a true migration. A regular clone only checks out the default branch and its history, leaving all your other feature branches and tags behind. The `–bare` flag ensures you get everything.
Step 2: Push the Mirrored Repository to GitHub
Now, navigate into the directory you just created. I’ll skip the standard `cd` command, as you know how to navigate your own terminal. Once you are inside the `your-repo.git` directory, we’re going to push this entire mirrored history to its new home on GitHub.
We’ll use the `–mirror` flag for the push. This ensures that every single reference (branches, tags, etc.) from your local bare repository is pushed to the new remote.
git push --mirror https://github.com/your-username/your-new-repo.git
When prompted, use your GitHub username and your Personal Access Token (PAT) as the password.
Once that command finishes, you’re done. Refresh your GitHub repository page. You should see all your files, your full commit history, and if you check the branches/tags dropdown, every single one will be there.
Pro Tip: In my production setups, I always use SSH URLs instead of HTTPS for both cloning and pushing. It saves me from having to enter credentials every time. If your SSH keys are configured correctly in both Bitbucket and GitHub, the process is even smoother.
Step 3: Clean Up
Since we created a temporary local copy, you can now safely delete the `your-repo.git` folder from your machine. The source of truth is now on GitHub.
Common Pitfalls (Where I’ve Messed Up Before)
- Pushing to a Non-Empty Repo: I can’t stress this enough. If you initialize your new GitHub repo with a README, it creates an initial commit. Trying to push your mirrored history on top of that will lead to errors about unrelated histories. Always start with a completely blank slate on the GitHub side.
- Incorrect PAT Permissions: If your push fails with an authentication error, the first thing to check is your GitHub PAT. Ensure it has the full `repo` scope enabled. A token without the right permissions won’t be able to write to the repository.
- Forgetting `–mirror` on the Push: A regular `git push` will only send up your default branch. The `–mirror` flag is what tells Git to push all refs (branches and tags). Forgetting it means you’ll only get a fraction of your repository’s history.
Conclusion
And that’s the whole playbook. Two commands are all it takes to perform a clean, complete migration from Bitbucket to GitHub. By using the `bare` clone and `mirror` push, you guarantee that not a single commit, branch, or tag is left behind. In our team at TechResolve, standardizing these small, repeatable processes is what allows us to move quickly and avoid costly mistakes. Hopefully, this one saves you some time and a few headaches.
🤖 Frequently Asked Questions
âť“ What is the essential command-line process to migrate a Bitbucket repository to GitHub, ensuring all history, branches, and tags are preserved?
First, create a bare clone of the Bitbucket repository using `git clone –bare
âť“ How does this direct Git CLI migration method compare to other repository migration tools or services?
This direct Git CLI method offers precise control and guarantees a perfect, mirrored copy of all Git data using standard commands. While other tools might provide more automation or UI, this approach is highly reliable for ensuring full history preservation and avoiding partial migrations, making it ideal for critical transfers.
âť“ What is a common implementation pitfall during this migration process and how can it be avoided?
A common pitfall is pushing to a GitHub repository that was initialized with a README, license, or .gitignore, which creates an initial commit and leads to ‘unrelated histories’ errors. This can be avoided by always creating a completely blank, empty GitHub repository as the target for the migration.
Leave a Reply