Have you ever wondered what is the reason people run self-hosted solutions, even though they copy or imitate services or tools thay are battle hardened, proven to work well and mostly free?

There is something really powerful behind such endeavour. It always takes some time to set up. It does not have that much users to created interactions. It may even cost you money to run. Sometimes after you think that "I have finally made it" you discover that there are unresolved issues that might really cross your path.

When you finally make it run, another question arises: what do you put inside?

Moving out!

In this article I will explain a simple process about how to migrate existing BitBucket repositories to the gitea server.

Before we begin, make sure that you set up gitea in the right way, otherwise it wil get in your way and slow you down.

The functionality I am reffereing to the "Push to create repository". This feature is also present in GitLab, and if I am not mistaken, it landed it there first and I find is super usfeul, especially for migrating. You just add origin to the local repo and push it. No more need for page loading, signing in or clicking!

Also note that I could not find this feature in BitBucket, so the reverse process will not probably not work the seme way, and I am not sure about GitHub either.

The way to enable it in gitea is to walk straight into your app.ini and edit everything furiously. I am just kidding. Just add or edit the [repository] section. The config variables that you need are either ENABLE_PUSH_CREATE_USER and / or ENABLE_PUSH_CREATE_ORG, depending on your use case. Set it to true.

This feature is documented, so you can read more about at the gitea config cheat scheet.

The getting part

Now when the needed settings are in place, the next step is to clone the repository from the BitBucket. This is the easy part, you think. We can use gitea's migration functionality. Well, in time of writing, the stable version of gitea is 1.11.6, which has a note in the migration interface stating:

Mirroring LFS objects is not supported - use git lfs fetch --all and git lfs push --all instead.

There is also no change of this in sight. Even though the release candidate for 1.12 does include enhancement related to migrations, it is a logging enabled by #11647. So we have to do it the hard way, let's start by cloing:

git clone git@bitbucket.org:alexilaiho/guitar-repository.git

Step back for a moment. Alexi would not be happy to find out that his guitar strings are actually a submodule and he has his guitar, but without them. Let's fix it:

git clone --recurse-submodules git@bitbucket.org:alexilaiho/guitar-repository.git

This is the one I have taken from the oh-my-zsh git plugin, but I believe this is quite well known. Look for gcl alias.

If Alexi's guitar somehow had a development branch, he would have missed it as well. The solution I have found is to subsequently run the pull command with --all argument:

git pull --all --tags

We expected Alexi would also responsibly tag his guitar releases, so he would like to have all relevant information pulled in as well, thus the --tags argument.

But again, the neck of his guitar is quite a large part and could even be distributed in a binary format, for instance as a picture in a relly huge resolution. As a professional, he would obviously want his guitar be crisp and sharp in every aspect possible. If he had multiple versions of this guitar neck blob in the repository, all but the latest would not be present in his cloned repository.

git lfs fetch --all

Now his quitar is as complete as in the remote.

The cleaning part

The repository now has to be prepared to be pushed to it's new home. Let's exchange the origin frm the old one to the new one:

git remote remove origin
git remote add origin git@alexilaiho-gitea.dev/guitar-repository.git

Note that the repository URI does not need to be pre-existing. Remember, the repository will be created on push!

The putting part

So let's try it:

git push --all origin
git push --tags origin
git lfs push ---all  origin master

Now Alexi would find his lovely polished guitar in his new home. Note that this requires to have SSH access working for both repositories.

Wrapping it up

If the plan is to do this multiple times, it is handy to put it inside a script. I have made one that looks like this, but feel free to tweak it for your needs.



echo "Migrating $1"

git clone --recurse-submodules "$host/$1.git"
cd $1
git pull --all --tags
git lfs fetch --all
git remote remove origin
git remote add origin "$target/$1.git"
git push --all origin
git push --tags origin
git lfs push --all origin master
cd ..

Hopefully it will help you. I could not find an easy way to download multiple repositories from the BitBucket, so this still has some room for improvement. Please, let me know about your opitions.


In the beginning of the article I have asked why o people like to self host their services. We did not find it out here, but made our life a little bit easier with an automated solution to migrate a repository from BitBucket to gitea server to save a little bit of time and nerves.

If you happen to be in the similar position as me and find this post useful, I am curious why did you choose gitea among the alternatives. I find it to be a pleasant experience so far. If you enjoy it too, spread the word and help open source software to thrive!