Photo by Ray Hennessy on Unsplash

Photo by Ray Hennessy on Unsplash

Migrate your Git repositories to Gitea

Exodus

Article from ADMIN 84/2024
By
Nothing is forever, not even a Git server. After the purchase of GitHub by Microsoft, I found a new home in Gitea for version control.

Anyone who uses Git will quickly see the true value of version management. I have set up my own Git server with all kinds of features on a Raspberry Pi with the Gogs self-hosted Git service software, but as of now, the Gogs repository has had very little activity, with releases only appearing every six months and offering very little in terms of new features. This situation led me to believe that the software will probably not survive much longer.

Unfortunately, I didn't realize the unhealthy state of Gogs until I was already dealing with versions that have no easy migration path to Gitea, a fork of Gogs and the new home I chose for my code. The two projects have drifted apart since the fork. In this article, I show how to migrate your repositories to Gitea.

Git Origin

Unlike veterans such as CVS or Subversion, Git is not a client-server application, but a distributed system, which means that no node is favored or disadvantaged compared with others. Git allows each repository to act as a server, making migration easier. You just have to make sure that the working copies contain all the branches and tags of the origin.

In the Git world, the origin is a local alias of a specific remote repository. It removes the need for you to enter the full URL for every fetch, pull, or push operation. In fact, you could even rename the origin alias to, say, source by typing:

git remote rename origin source

What is far more serious than these names in the context of a server migration is that all data from the previous origin is only available locally. If the previous server is deleted, development branches could be lost.

Checking for Completeness

If you want to migrate your repositories, first make sure all of them are fully available locally. I had no choice but to make all my remote repositories available locally with the git clone command. Once that was done, I was able to check each repository's branches and tags. For each individual repository, all the branches and tags had to be up to date in the local version. A few Git commands and a little shell scripting made this task easier.

The following script shows how to check out all the branches of a repository:

for mybranch in $(git branch -a | grep -o -E '(remote.*)' | grep -v ' -> ' | cut -f3 -d'/')
do
  git checkout "${mybranch}"
  git pull
done

The git branch -a command in the first line returns the names of all branches in the repository. For the purpose of migration, I was mainly interested in the branches that were not yet available locally, so I used grep to filter out the remote branches. I then removed the line that denoted my HEAD reference – that is, the currently active branch, which is marked with an arrow (->).

The for loop iterates over the branches it finds and executes the git checkout command, making the branch in question available locally. You just need to repeat this procedure for all tags (git fetch --tags).

Everything Is a File

True to my motto of "a lazy admin is a good admin" or "if you can do so, let the computer work for you," I thought about the easiest way to handle the migration. Looking at the operating system first, for me, one of the greatest strengths of free software is that practically everything that makes up the system is available as a file. This arrangement might sound trivial at first, but it will probably become clearer when you consider what you need to do in the scope of a server move.

The migration all starts with the Git software, which I want to change; the reverse proxy – NGINX in my case, the Exim4 mail server, and various shell scripts, cron tables, and so on. With no exceptions, I store global cron tables in the /etc/cron.d/ directory, global shell scripts in /usr/local/bin, and non-distribution software in /opt/. This structure makes it easy to create a backup of all the relevant files on this system with a one-liner:

$ sudo tar -vzcf /home/thomas/githorst.tar.gz /etc/ /opt/ /usr/local/bin/

The archive created in this way contains the files required to ensure the features on my old hardware exist in the same way on my future hardware.

My Raspberry Pi needs an operating system release change because a Raspbian version based on Debian 12 became available. The next step, then, is to copy the new Raspbian image to an SD card; Raspberry Pi Imager gives you a very convenient way of doing this. After booting the new system, it's time to install some software. A simple

sudo apt install postgres exim4 nginx

makes light work of this task. I then copied the required configuration files (Nginx, Exim4, and Gogs) to /etc/.

Installing Gitea, including setting up a systemd service, was quick and painless thanks to the good documentation [1]. The service can be accessed on port 3000. Because I wanted to transfer the configuration of my existing Gogs instance to the new Gitea instance to the extent possible, I had to edit app.ini, the central configuration file. Once again, Vim proves to be a great all-rounder, because vimdiff – assuming you have some experience with Vim – makes it easy to find the differences between the former and the current configuration files and merge them as required.

Once you have set up the configuration to suit your needs, I would recommend sending a test email to check the mail server settings. You will find the most important server settings under Configuration | Site Administration (Figures 1 and 2) and can send a test email by entering an email address (Figure 3).

Figure 1: The most important server settings can be found under Configuration.
Figure 2: You can access Site Administration (2) from a personal menu (1).
Figure 3: Test email can be sent from the SMTP Mailer Configuration dialog.

In general, I can warmly recommend the Gitea configuration cheat sheet [2], which contains every setting and every flag that can occur in the app.ini file. However, I would definitely recommend adjusting the logging settings here. By default, Gitea only logs on the console, which makes very little sense in server operation. I would recommend configuring the settings for logging to files in the log section:

[log]
#MODE = console
MODE              = file
LEVEL             = Warn
ROOT_PATH         = /opt/gitea/log
LOG_ROTATE        = true
DAILY_ROTATE      = true
MAX_DAYS          = 7
COMPRESS          = true
COMPRESSION_LEVEL = -2

Merging the settings and setting up NGINX as a reverse proxy – again, with the old configuration – gives you a running, clean, empty Gitea instance. This process was even easier than I originally thought it would be.

Now is the time for migration (i.e., physically moving the existing repositories to the new server). My Gitea server has the same fully qualified domain name (FQDN) as the former Gogs; moreover, Gitea has the same Let's Encrypt certificates, which was exactly the plan I had in mind when I backed up the original system. Later, I will look into tried and tested procedures for moving a repository to a new server. In my case, all the server settings remained the same, minus repositories.

My first attempt was a naive git push; after all, what could go wrong? To be honest, I was not so far off the mark and received a very informative error message, as well. Figure 4 shows the message in the first line of output, which sent me running to read the Gitea documentation, which clearly states:

Figure 4: The error message put me on the right track and pointed me toward the documentation.

In the app.ini file, set ENABLE_PUSH_CREATE_USER to true and ENABLE_PUSH_CREATE_ORG to true if you want to allow users to create repositories in their own user account and in organizations they are a member of respectively. Restart Gitea for the changes to take effect. You can read more about these two options in the Configuration Cheat Sheet. (Gitea push docs [3])

Voilà – exactly the information I needed.

I enabled two flags,

ENABLE_PUSH_CREATE_USER = true
ENABLE_PUSH_CREATE_ORG = true

in the [repository] section of the app.ini file. After restarting the Gitea service, I tried my luck again, and with success this time. As you can see in Figure 5, Gitea accepts push-and-create for both user and organization-owned repos. Given my fears that the move could turn into a major project, this outcome was really satisfying.

Figure 5: After I adjusted the configuration, pushing – which also creates the new branch – worked as desired.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus
Subscribe to our ADMIN Newsletters
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs



Support Our Work

ADMIN content is made possible with support from readers like you. Please consider contributing when you've found an article to be beneficial.

Learn More”>
	</a>

<hr>		    
			</div>
		    		</div>

		<div class=