Mirroring Gitea to Other Repository Management Services (GitHub, GitLab, etc.)
Posted on Mar 13 2019
NOTE: Gitea now supports this out-of-the-box and probably fits your use-case: https://docs.gitea.io/en-us/repo-mirror/
I have a Gitea instance I self-host at home. I keep most of my repositories there, but I recognize that most other developers and potential employers will want to see my work on GitHub.
- Setup an SSH key for your Gitea instance on the relevant external repositories
post-receivegit hooks in Gitea to push changes to the relevant external repositories while identifying with your new SSH key
Also, most of the magic is here.
In order to achieve this with minimal effort, I was going to need to utilize mirroring. Mirroring is a popular git concept that allow a repository to effectively exist in multiple places at once, though generally mirrors are read-only.
Mirroring isn’t exactly a specific procedure or command, it’s simply the act of reflecting all (or some specific subset) of commits that exist elsewhere, generally in an automated fashion. Forks might be considered “mirrors” of a repository at a given point in time.
GitLab, for example, supports mirroring pretty seamlessly. Gitea, however, is pretty minimal, which is one of its perks to me. That does not, however, mean that it is lacking in features.
Gitea supports a few git hooks, which are a simple way to run a script when something happens. As far as a repository manager is concerned, the only real hooks that matter are the following (which Gitea supports):
pre-receive: Runs when a client pushes code to the repository. You can use this to prevent, for example, code that fails linters, doesn’t pass tests, or even that can’t be merged using a specific merge strategy.
update: Runs for each branch being updated when a client pushes code to the repository. This is similar to pre-receive, but allows for more fine-grained control. Maybe you want to only make the previous restrictions on your
masterbranch. This would be the way to do it.
post-receive: Runs after your
updatehooks have finished when a client pushes code to the repository. This is what we’ll be leveraging to push code downstream!
With that lengthy introduction, let’s dive in!
Alrighty, this has a few simple steps, so let’s outline what we need to do first:
- Setup SSH keys for Gitea and your other repository management services
- Generate fresh keys (
ssh-keygen -f giteawill generate a private key in the
giteafile and a public key in the
- Add the public key (
gitea.pub) to your “mirrors-to-be” repositories with write access
- Note: I recommend at the very least to create one Gitea key and add it to the individual repositories, though individual keys for each repository is tighter security in case your Gitea instance becomes compromised
- Note: Your “mirrors-to-be” repositories must be blank or have related histories!
- Generate fresh keys (
- Setup the
post-receivehook on your Gitea repository to push using the newly generated private key to the mirror(s)
I’m not going to explain much on how to add Deploy Keys for the various repository management systems out there, so here’s a link explaining the process for GitHub.
Now we’re all set for the magic! Also, for reference and sanity, I’m running Gitea in Docker on an Arch Linux server with the following version (but this should work pretty much regardless):
- Gitea Version:
3b612ce built with go1.11.5 : bindata, sqlite, sqlite_unlock_notify
- Git Version:
Let’s go ahead and open up our Gitea repository’s index page.
And head to the repository’s “Settings” tab… (oh yes, you’ll need to have the proper permissions on the repository itself!)
And now to the “Git Hooks” tab…
Let’s edit the “Post Receive” hook…
And you will be presented with a form where you can put any kind of script you want! Remember the SSH keys you generated so long ago? We’re going to need the contents of the private key now. Here are the script contents you’re going to use, replacing the variables as necessary.
#!/usr/bin/env bash downstream_repo="firstname.lastname@example.org:lytedev/dotfiles.git" # if tmp worries you, put it somewhere else! pkfile="/tmp/gitea_dotfiles_to_github_dotfiles_id_rsa" if [ ! -e "$pkfile" ]; then # unindented block for heredoc's sake cat > "$pkfile" << PRIVATEKEY # ==> REMOVE THIS ENTIRE LINE & PASTE YOUR PRIVATE KEY HERE <== PRIVATEKEY fi chmod 400 "$pkfile" export GIT_SSH_COMMAND="ssh -oStrictHostKeyChecking=no -i \"$pkfile\"" # if you want strict host key checking, just add the host to the known_hosts for # your Gitea server/user beforehand git push --mirror "$downstream_repo"
Click “Update Hook” and you’re all set! Now just push to the repo and watch it magically become mirrored to the downstream repository!