Moving a repository from BitBucket to GitHub is usually not a hard challenge. I will give you a step by step instruction to achieve your goal. With this instruction, you can also move in vice versa or to the repository of your choice. But you have to change the repository host and your user to your needs.
The first step is to create a new repository in Github. This is quite easy to do over the UI. The next step is to clone the old repository with the –bare option. This option is used to make a copy of the remote repository. This means that a repository will be set up with the history of the project that can be pushed and pulled from but cannot be edited directly. By convention, the directory name ends with a .git suffix. Here is an example of the command with ssh:
git clone --bare git@bitbucket.org:JohnDoe/repo.git
Now you should see a repo.git
directory. Go into the repo.git
directory and push the repository into the new repository. We will use the --mirror
option to push all refs to the new repository.
cd repo.git
git push --mirror git@github.com:JohnDoe/repo.git
Now, you can delete the local repository.
cd ..
rm -rf repo.git
Quite easy, isn’t it? You can see all your branches, commits and tags are moved and you can go on with your work.
The pitfall for big repositories
Unfortunately, I could not move all repositories so easy. I had some cases were I ran into the following error:
remote: fatal: pack exceeds maximum allowed size
error: remote unpack failed: index-pack abnormal exit
error: failed to push some refs to 'git@github.com:JohnDoe/repo'
I took a look into the objects/pack
folder and found only two files, but one of them was over 4.6 GB big:
-r--r--r-- 1 john john 11M Feb 10 14:25 pack-<foo>.idx
-r--r--r-- 1 john john 4.6G Feb 10 14:25 pack-<bar>.pack
The question is how to solve this issue? Because the history of your branch is too big you need to divide your pushes to the repository in smaller chunks. You can do this in different ways:
git push <remotename> <commit SHA>:<branch> # for a commit
git push <remotename> refs/tags/<tagname>:refs/tags/<tagname> # for a tag
Unfortunately, the repository has over 100 tags and even more commits. I didn’t want to do it manually. Luckily, I found a Stackoverflow thread which helped me to automate the process. Git provides a command to iterate over all refs. You can build a script that pushes them one by one until are all done. The script looks like the following:
git for-each-ref --format="%(refname)" --sort='authordate' refs/heads refs/tags | \
while read ref;
do git push <remotename> $ref:$ref
done
I hope my article helps you to solve a similar issue and build up your professional skills. If you already run into the same problem let a comment and describe how do you solve the issue and if you like the article let a comment, too 🙂