Gitea Notes

Posted on Mon 25 August 2025 in lessons

Here are some notes on using Gitea as a git forge and issue tracker after using it for around 6 months.

The Good

In general, everything pretty much works as expected, and I didn't run into any problems provisioning it..

  • It's mostly deployed as a single go executable on the git server, and then a single go executable on each build server.

    There were no external dependencies to wrangle, or pull you down into dependency hell.

  • I didn't run into any issues porting my existing repos into Gitea.

    After that the workflow feels like using GitLab or GitHub.

    For the most part, it works, and it's been a joy.

  • The workflow support mirrors GitHub actions a bit too closely, as per below, but for the most part, workflows are working as expected.

  • Template repos work surprisingly well, as per below.

The Bad/Ugly

Most of these are minor UI choices Gitea made that I don't like. There's certainly nothing here to force me to switch to another forge.

  • I don't really like that issues have to be opened against a repo, and that there's not a good way to move issues between repos.

    If you end up opening an issue against the wrong repo, you have to close the first issue and open a second issue in the correct repo.

  • For some reason, I always have trouble adding new users to a repo.

    It's done through the https://<git-server>/<organization-name>/<repo-name>/settigs/collaboration page.

    You can also define a collection of users called a 'team' for an organization at https://<git-server>/<organization-name>/teams and then add the team to the repo.

    I don't like the 'collaborator' terminology since it makes me feel like a quisling. 🤷

  • Gitea will convert issue instances to links, but you have to use a kludgy '<organization-name>/<repo-name>#<issue-number>' format.

    It would be better if the organization-name and repo-name weren't needed and defaulted to the current repo's values.

  • I always have trouble finding the commit graph for a repo.

    Go to the '<> Code' link for the repo, then the 'Commits' link, and there should be a 'Commit Graph' link next to the branch name.

    It should also be available at https://<gitea-server>/<org-name>/<repo-name>/graph.

  • Setting up branch protection was a little hard.

    To do it, go the Settings for the repo, then click the 'Branch' button, then click on the 'Add New Rule' button.

    I enabled the 'Require Signed Commits' and 'Enable Status Check' checks.

    The Status check pattern format is '<name of .gitea/workflows workflow> /  < job name> (<git trigger>)'.

    For example, my workflow file looks like below, making the status check 'On Push Workflows / On-Push-Job (push)".

    If you've already triggered the workflow, it should show up on the page in a text box below the setting.

    name: On Push Workflow
    run-name: ${{ gitea.actor }} pushed out some changes. 🚀
    on:
      push:
        branches:
          - "*"
    
    jobs:
      On-Push-Job:
    <<clipped the rest of the workflow>>
    

The Surprising

I ran into one pleasant surprise and two that weren't as pleasant.

  • Cloning from Gitea template repos worked really well, even working on file names.

    I had a file named test_${REPO_NAME_CAMEL}.py in the tests directory of my template repo, and Gitea successfully created the file with the correct name.

    Make sure the .gitea/template file in the template repo includes the files where the templates should be applied. It wasn't enough for me to add a tests directory .gitea/template. I had to add tests/** to get Gitea to apply the templates to everything under the tests directory.

  • Setting up Gitea to sign merge commits was a big hassle

    I spent a lot of time trying to add the key to /home/git/.gnupg, but Gitea expects the key to be at /var/lib/gitea/home/data/.gnupg.

    Thanks to Ivan's post for pointing out the correct directory.

  • I'll close with the biggest gotcha I've run into: The actions/checkout@v4 steps used to checkout repo code during .gitea/workflows was cloning the actions repo from Github.

    The whole reason for spinning up a local forge was to be able to keep working when GitHub was down, or when it was enshitttenfied past the point of usefulness.

    To avoid this GitHub dependency, I added the block below to /etc/gitea/app.ini, then created an 'actions' organization and pushed a mirror of https://github/actions/checkout.git into the 'actions' organization.

    Once I did this, and restarted Gitea, I saw the workflows cloning from https://<my-gitea-server>/actions/checkout instead of https://github/actions/checkout.

    [actions]
    DEFAULT_ACTIONS_URL = self
    

    Note the Gitea FAQs do call out this behavior so I shouldn't have been as surprised as I was.