gitea Documentation

Git with a cup of tea! Painless self-hosted all-in-one software development service, including Git hosting, code review, team collaboration, package...

58,542 stars Go Go 16 files ยท ~17,249 tokens #bitbucket#cicd#devops#docker-registry-v2#git#git-gui#git-lfs#git-server
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy gitea on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name gitea -p 22:22 --restart always go-gitea/gitea:latest

Technical Documentation: go-gitea/gitea

โ„น๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference

Overview (`README.md`)

Gitea








็น้ซ”ไธญๆ–‡ | ็ฎ€ไฝ“ไธญๆ–‡

Purpose

The goal of Gitea is to make the easiest, fastest, and most painless way of
setting up a self-hosted all-in-one software development service,
including Git hosting, code management, code review, issue tracking, project kanban, wiki,
team collaboration, package registry and CI/CD which can reuse GitHub Actions.

As Gitea is written in Go, it works across all the platforms and
architectures that are supported by Go, including Linux, macOS, FreeBSD/OpenBSD and Windows
on x86, amd64, ARM, RISC-V 64 and PowerPC architectures.

For online demonstrations, you can visit demo.gitea.com.

For accessing free Gitea service (with a limited number of repositories), you can visit gitea.com.

To quickly deploy your own dedicated Gitea instance on Gitea Cloud, you can start a free trial at cloud.gitea.com,
or use container (docker/podman/etc) to deploy on your own server with the official image.

Documentation

You can find comprehensive documentation on our official documentation website.

It includes installation, administration, usage, development, contributing guides, and more to help you get started and explore all features effectively.

If you have any suggestions or would like to contribute to it, you can visit the documentation repository

Building

See docs/build-setup.md for prerequisites
and docs/development.md for setting up a local development environment, linting, and testing.

If you'd like to build from source or make a distribution package, see docs/build-source.md for more information.

After building, you can run ./gitea web to start the server, or ./gitea help to see all available commands.

Contributing

Expected workflow is: Fork -> Patch -> Push -> Pull Request

[!NOTE]

  1. YOU MUST READ THE CONTRIBUTORS GUIDE BEFORE STARTING TO WORK ON A PULL REQUEST.
  2. New to the codebase? The development guide walks through setting up a local environment and building from source.
  3. If you have found a vulnerability in the project, please write privately to [email protected]. Thanks!

Translating

Translations are done through Crowdin. If you want to translate to a new language, ask one of the managers in the Crowdin project to add a new language there.

You can also just create an issue for adding a language or ask on Discord on the #translation channel. If you need context or find some translation issues, you can leave a comment on the string or ask on Discord.

Get more information from the translation section of our contributing guide.

Official and Third-Party Projects

We provide an official go-sdk, a CLI tool called tea and an action runner for Gitea Action.

We maintain a list of Gitea-related projects at gitea/awesome-gitea, where you can discover more third-party projects, including SDKs, plugins, themes, and more.

Communication

If you have questions that are not covered by the documentation, you can get in contact with us on our Discord server or create a post in the discourse forum.

Authors

Backers

Thank you to all our backers! ๐Ÿ™ [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]










FAQ

How do you pronounce Gitea?

Gitea is pronounced /ษกษชโ€™ti:/ as in "gi-tea" with a hard g.

How do I configure Gitea?

For dynamic config options, you can change it on your admin panel's configuration section.

For static config options, you can edit your app.ini file and restart the instance.
See app.example.ini or configuration documentation for more details.

Where can I find the security patches?

Check the release notes and security advisories for security patches.

(more FAQs are listed in FAQ documentation)

License

This project is licensed under the MIT License.
See the LICENSE file
for the full license text.

Further information

Looking for an overview of the interface? Check it out the screenshots!

Login/Register Page

User Dashboard

User Profile

Explore

Repository

Repository Issue

Repository Pull Requests

Repository Actions

Repository Activity

Organization


Overview (`docker/README.md`)

Gitea - Docker

Dockerfile is found in the root of the repository.

Docker image can be found on docker hub.

Documentation on using docker image can be found on Gitea Docs site.


Overview (`contrib/development/README.md`)

IDE and code editor configuration

Table of Contents

Microsoft Visual Studio Code

Download Microsoft Visual Studio Code at https://code.visualstudio.com/ and follow instructions at https://code.visualstudio.com/docs/languages/go to setup Go extension for it.

Create new directory .vscode in Gitea root folder and copy contents of folder contrib/development/vscode to it. You can now use Ctrl+Shift+B to build gitea executable and F5 to run it in debug mode.

Supported on Debian, Ubuntu, Red Hat, Fedora, SUSE Linux, MacOS and Microsoft Windows.


Overview (`contrib/grafana-monitoring-mixin/README.md`)

Gitea Mixin

Gitea Mixin is a set of configurable Grafana dashboards based on the metrics exported by the Gitea built-in metrics endpoint.

Generate config files

You can manually generate dashboards, but first you should install some tools:

bash
go install github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb@latest
go install github.com/google/go-jsonnet/cmd/jsonnet@latest
# or in brew: brew install go-jsonnet

For linting and formatting, you would also need mixtool and jsonnetfmt installed. If you
have a working Go development environment, it's easiest to run the following:

bash
go install github.com/monitoring-mixins/mixtool/cmd/mixtool@latest
go install github.com/google/go-jsonnet/cmd/jsonnetfmt@latest

The files in dashboards_out need to be imported
into your Grafana server. The exact details will be depending on your environment.

Edit config.libsonnet if required and then build JSON dashboard files for Grafana:

bash
make

For more advanced uses of mixins, see
https://github.com/monitoring-mixins/docs.


Overview (`routers/api/packages/README.md`)

Gitea Package Registry

This document gives a brief overview how the package registry is organized in code.

Structure

The package registry code is divided into multiple modules to split the functionality and make code reuse possible.

Module Description
models/packages Common methods and models used by all registry types
models/packages/<type> Methods used by specific registry type. There should be no need to use type specific models.
modules/packages Common methods and types used by multiple registry types
modules/packages/<type> Registry type specific methods and types (e.g. metadata extraction of package files)
routers/api/packages Route definitions for all registry types
routers/api/packages/<type> Route implementation for a specific registry type
services/packages Helper methods used by registry types to handle common tasks like package creation and deletion in routers
services/packages/<type> Registry type specific methods used by routers and services

Models

Every package registry implementation uses the same underlying models:

Model Description
Package The root of a package providing values fixed for every version (e.g. the package name)
PackageVersion A version of a package containing metadata (e.g. the package description)
PackageFile A file of a package describing its content (e.g. file name)
PackageBlob The content of a file (may be shared by multiple files)
PackageProperty Additional properties attached to Package, PackageVersion or PackageFile (e.g. used if metadata is needed for routing)

The following diagram shows the relationship between the models:

text
Package <1---*> PackageVersion <1---*> PackageFile <*---1> PackageBlob

Adding a new package registry type

Before adding a new package registry type have a look at the existing implementation to get an impression of how it could work.
Most registry types offer endpoints to retrieve the metadata, upload and download package files.
The upload endpoint is often the heavy part because it must validate the uploaded blob, extract metadata and create the models.
The methods to validate and extract the metadata should be added in the modules/packages/<type> package.
If the upload is valid the methods in services/packages allow to store the upload and create the corresponding models.
It depends if the registry type allows multiple files per package version which method should be called:

  • CreatePackageAndAddFile: error if package version already exists
  • CreatePackageOrAddFileToExisting: error if file already exists
  • AddFileToExistingPackage: error if package version does not exist or file already exists

services/packages also contains helper methods to download a file or to remove a package version.
There are no helper methods for metadata endpoints because they are very type specific.


Overview (`web_src/js/webcomponents/README.md`)

Web Components

This webcomponents directory contains the source code for the web components used in the Gitea Web UI.

https://developer.mozilla.org/en-US/docs/Web/Web_Components

Guidelines

  • These components are loaded in <head> (before DOM body) in a separate entry point, they need to be lightweight to not affect the page loading time too much.
  • Do not import svg.js into a web component because that file is currently not tree-shakeable, import svg files individually insteat.
  • Any custom element used inside a .vue file must be added to webComponents in vite.config.ts so Vue does not try to resolve it as a component. That list also covers custom elements from dependencies.

Overview (`services/auth/source/ldap/README.md`)

Gitea LDAP Authentication Module

About

This authentication module attempts to authorize and authenticate a user
against an LDAP server. It provides two methods of authentication: LDAP via
BindDN, and LDAP simple authentication.

LDAP via BindDN functions like most LDAP authentication systems. First, it
queries the LDAP server using a Bind DN and searches for the user that is
attempting to sign in. If the user is found, the module attempts to bind to the
server using the user's supplied credentials. If this succeeds, the user has
been authenticated, and his account information is retrieved and passed to the
Gogs login infrastructure.

LDAP simple authentication does not utilize a Bind DN. Instead, it binds
directly with the LDAP server using the user's supplied credentials. If the bind
succeeds and no filter rules out the user, the user is authenticated.

LDAP via BindDN is recommended for most users. By using a Bind DN, the server
can perform authorization by restricting which entries the Bind DN account can
read. Further, using a Bind DN with reduced permissions can reduce security risk
in the face of application bugs.

Usage

To use this module, add an LDAP authentication source via the Authentications
section in the admin panel. Both the LDAP via BindDN and the simple auth LDAP
share the following fields:

  • Authorization Name (required)

    • A name to assign to the new method of authorization.
  • Host (required)

    • The address where the LDAP server can be reached.
    • Example: mydomain.com
  • Port (required)

    • The port to use when connecting to the server.
    • Example: 636
  • Enable TLS Encryption (optional)

    • Whether to use TLS when connecting to the LDAP server.
  • Admin Filter (optional)

    • An LDAP filter specifying if a user should be given administrator
      privileges. If a user accounts passes the filter, the user will be
      privileged as an administrator.
    • Example: (objectClass=adminAccount)
  • First name attribute (optional)

    • The attribute of the user's LDAP record containing the user's first name.
      This will be used to populate their account information.
    • Example: givenName
  • Surname attribute (optional)

    • The attribute of the user's LDAP record containing the user's surname This
      will be used to populate their account information.
    • Example: sn
  • E-mail attribute (required)

    • The attribute of the user's LDAP record containing the user's email
      address. This will be used to populate their account information.
    • Example: mail

LDAP via BindDN adds the following fields:

  • Bind DN (optional)

    • The DN to bind to the LDAP server with when searching for the user. This
      may be left blank to perform an anonymous search.
    • Example: cn=Search,dc=mydomain,dc=com
  • Bind Password (optional)

    • The password for the Bind DN specified above, if any. Note: The password
      is stored in plaintext at the server. As such, ensure that your Bind DN
      has as few privileges as possible.
  • User Search Base (required)

    • The LDAP base at which user accounts will be searched for.
    • Example: ou=Users,dc=mydomain,dc=com
  • User Filter (required)

    • An LDAP filter declaring how to find the user record that is attempting to
      authenticate. The '%[1]s' matching parameter will be substituted with the
      user's username.
    • Example: (&(objectClass=posixAccount)(|(uid=%[1]s)(mail=%[1]s)))

LDAP using simple auth adds the following fields:

  • User DN (required)

    • A template to use as the user's DN. The %s matching parameter will be
      substituted with the user's username.
    • Example: cn=%s,ou=Users,dc=mydomain,dc=com
    • Example: uid=%s,ou=Users,dc=mydomain,dc=com
  • User Search Base (optional)

    • The LDAP base at which user accounts will be searched for.
    • Example: ou=Users,dc=mydomain,dc=com
  • User Filter (required)

    • An LDAP filter declaring when a user should be allowed to log in. The %[1]s
      matching parameter will be substituted with the user's username.
    • Example: (&(objectClass=posixAccount)(|(cn=%[1]s)(mail=%[1]s)))
    • Example: (&(objectClass=posixAccount)(|(uid=%[1]s)(mail=%[1]s)))

Verify group membership in LDAP uses the following fields:

  • Group Search Base (optional)

    • The LDAP DN used for groups.
    • Example: ou=group,dc=mydomain,dc=com
  • Group Name Filter (optional)

    • An LDAP filter declaring how to find valid groups in the above DN.
    • Example: (|(cn=gitea_users)(cn=admins))
  • User Attribute in Group (optional)

    • The user attribute that is used to reference a user in the group object.
    • Example: uid if the group objects contains a member: bender and the user object contains a uid: bender.
    • Example: dn if the group object contains a member: uid=bender,ou=users,dc=planetexpress,dc=com.
  • Group Attribute for User (optional)

    • The attribute of the group object that lists/contains the group members.
    • Example: memberUid or member
  • Team group map (optional)

    • Automatically add users to Organization teams, depending on LDAP group memberships.
    • Note: this function only adds users to teams, it never removes users.
    • Example: {"cn=MyGroup,cn=groups,dc=example,dc=org": {"MyGiteaOrganization": ["MyGiteaTeam1", "MyGiteaTeam2", ...], ...}, ...}
  • Team group map removal (optional)

    • If set to true, users will be removed from teams if they are not members of the corresponding group.

Build Setup (`docs/build-setup.md`)

Setup and requirements

This document lists the tools you need to build Gitea from source and how to get
the code. Once your environment is ready, see development.md for
the build and development workflow, and testing.md for running tests.

For the contribution workflow and review process, see CONTRIBUTING.md.

Requirements

Go

Install Go and set up your Go environment. The
required version is the one declared in go.mod; installing the same
version your continuous integration uses avoids gofmt differences between Go
releases.

[!NOTE]
Some make tasks build external Go tools on demand (for example make watch-backend). To use them, the "$GOPATH"/bin directory must be on your
executable PATH; otherwise you have to manage those tools yourself.

Node.js and pnpm

Install Node.js to build the JavaScript and CSS
files. The minimum supported version is the one declared in
package.json (engines.node); the latest LTS is recommended.

Gitea manages frontend dependencies with pnpm. The make
targets invoke it for you, so installing pnpm manually is only needed if you want
to run pnpm commands directly.

Make

Gitea uses Make to drive builds, linting, and
tests. On Windows it can be installed via MSYS2 or
Chocolatey.

Python with uv (optional)

Linting the templates, workflow files, and YAML requires Python tooling that Gitea
runs through uv. After installing uv, make creates
the environment automatically (uv sync); you only need this if you run
make lint-templates, make lint-yaml, or make lint-actions locally.

Git LFS

The integration tests require Git LFS to be installed.

Getting the source code

Clone the repository:

bash
git clone https://github.com/go-gitea/gitea

To contribute changes, fork the repository on
GitHub and add your fork as a git remote so you can push branches and open pull
requests. See GitHub's working with forks
documentation for the details.

Installing dependencies

Most build and test targets install the dependencies they need on their own. To
fetch everything up front, run make deps (or the per-group make deps-frontend,
make deps-backend, make deps-tools, make deps-py).


Build Source (`docs/build-source.md`)

Prepare build environment

Complete the steps in build-setup.md to prepare your environment for building Gitea from source.

Choose a branch

By default, the cloned repository is on main branch (the current development branch for next major release, aka: main nightly).

You can switch to a versioned branch (the branch for the next minor stable release, aka: stable nightly )
or a versioned tag (matches the official releases with version numbers)

To test a Pull Request, you can fetch its code by its Pull Request number (take PR #123456 as example):

bash
git fetch origin pull/123456/head:pr-123456

Build

Various make tasks
are provided to keep the build process as simple as possible.

Depending on requirements, the following build tags can be included.

  • bindata: Build a single monolithic binary, with all assets included. Required for distribution and production build.
  • pam: Enable support for PAM (Linux Pluggable Authentication Modules).
    Can be used to authenticate local users or extend authentication to methods available to PAM.

To include all assets, use the bindata tag:

bash
TAGS="bindata" make build

Changing default paths

Gitea will search for a number of things from the CustomPath.
By default, this is the custom/ directory in the current working directory when running Gitea.
It will also look for its configuration file CustomConf in $(CustomPath)/conf/app.ini,
and will use the current working directory as the relative base path AppWorkPath.

These values, although useful when developing, may conflict with downstream users preferences.

For packagers who need to use paths like /etc/gitea/app.ini,
they should define these values at build time for make build by environment variable like
LDFLAGS='-X "module.Var1=Value1" -X "module.Var2=Value2"' TAGS="bindata" make build.

  • CustomConf: -X "gitea.dev/modules/setting.CustomConf=/etc/gitea/app.ini"
  • AppWorkPath: -X "gitea.dev/modules/setting.AppWorkPath=/var/lib/gitea"
  • CustomPath: -X "gitea.dev/modules/setting.CustomPath=/var/lib/gitea/custom"
  • Default PID file location: -X "gitea.dev/cmd.PIDFile=/run/gitea.pid"

Add as many of the strings with their preceding -X to the LDFLAGS variable and run make build
with the appropriate TAGS as above.

Running gitea help will allow you to review what the computed settings will be for your gitea.

Cross Build

Gitea use's Golang's toolchain variables for cross-building.

For example, to cross build for Linux ARM64:

text
GOOS=linux GOARCH=arm64 TAGS="bindata" make build

Adding shell autocompletion

Shell completion can be generated directly from binary with:

sh
gitea completion <shell>

Supported values for <shell> are bash, fish, pwsh and zsh.
Details on how to load the completion for your shell can be found in the completion command help.

Source Maps

By default, gitea generates reduced source maps for frontend files to conserve space. This can be controlled with the ENABLE_SOURCEMAP environment variable:

  • ENABLE_SOURCEMAP=true generates all source maps, the default for development builds
  • ENABLE_SOURCEMAP=reduced generates limited source maps, the default for production builds
  • ENABLE_SOURCEMAP=false generates no source maps

Community Governance (`docs/community-governance.md`)

Community governance and review process

This document describes maintainer expectations, project governance, and the detailed pull request review workflow (labels, merge queue, commit message format for mergers). For what contributors should do when opening and updating a PR, see CONTRIBUTING.md.

Table of contents

Code review

Milestone

A PR should only be assigned to a milestone if it will likely be merged into the given version.
PRs without a milestone may not be merged.

Labels

Almost all labels used inside Gitea can be classified as one of the following:

  • modifies/โ€ฆ: Determines which parts of the codebase are affected. These labels will be set through the CI.
  • topic/โ€ฆ: Determines the conceptual component of Gitea that is affected, i.e. issues, projects, or authentication. At best, PRs should only target one component but there might be overlap. Must be set manually.
  • type/โ€ฆ: Determines the type of an issue or PR (feature, refactoring, docs, bug, โ€ฆ). If GitHub supported scoped labels, these labels would be exclusive, so you should set exactly one, not more or less (every PR should fall into one of the provided categories, and only one).
  • issue/โ€ฆ / lgtm/โ€ฆ: Labels that are specific to issues or PRs respectively and that are only necessary in a given context, i.e. issue/not-a-bug or lgtm/need 2

Every PR should be labeled correctly with every label that applies.

There are also some labels that will be managed automatically.
In particular, these are

  • the amount of pending required approvals
  • has all backports or needs a manual backport

Reviewing PRs

Maintainers are encouraged to review pull requests in areas where they have expertise or particular interest.

For reviewers

  • Verification: Verify that the PR accurately reflects the changes, and verify that the tests and documentation are complete and aligned with the implementation.
  • Actionable feedback: Say what should change and why, and distinguish required changes from optional suggestions.
  • Feedback: Focus feedback on the issue itself and avoid comments about the contributor's abilities.
  • Request changes: If you request changes (i.e., block a PR), give a clear rationale and, whenever possible, a concrete path to resolution.
  • Approval: Only approve a PR when you are fully satisfied with its current state - "rubber-stamp" approvals need to be highlighted as such.

Getting PRs merged

Changes to Gitea must be reviewed before they are accepted, including changes from owners and maintainers. The exception is critical bugs that prevent Gitea from compiling or starting.

We require two maintainer approvals for every PR. When that is satisfied, your PR gets the lgtm/done label. After that, you mainly fix merge conflicts and respond to or implement maintainer requests; maintainers drive getting the PR merged.

If a PR has lgtm/done, no open discussions, and no merge conflicts, any maintainer may add reviewed/wait-merge. That puts the PR in the merge queue. PRs are merged from the queue in the order of this list:

https://github.com/go-gitea/gitea/pulls?q=is%3Apr+label%3Areviewed%2Fwait-merge+sort%3Acreated-asc+is%3Aopen

Gitea uses its own tool, https://github.com/go-gitea/gitea/blob/main/.github/workflows/giteabot.yml, to automate parts of the review process. The backporter:

  • Creates a backport PR when needed after the initial PR merges.
  • Removes the PR from the merge queue after it merges.
  • Keeps the oldest branch in the merge queue up to date with merges.

Final call

If a PR has been ignored for more than 7 days with no comments or reviews, and the author or any maintainer believes it will not survive a long wait (such as a refactoring PR), they can send "final call" to the TOC by mentioning them in a comment.

After another 7 days, if there is still zero approval, this is considered a polite refusal, and the PR will be closed to avoid wasting further time. Therefore, the "final call" has a cost, and should be used cautiously.

However, if there are no objections from maintainers, the PR can be merged with only one approval from the TOC (not the author).

Commit messages

Mergers are required to rewrite the PR title and the first comment (the summary) when necessary so the squash commit message is clear.
Usually the Pull Request description and commit message body should not be empty, unless the title is already clear enough or the description would be a copy of the comments in code.

The final commit message:

  • should match the code changes.
  • should only keep true co-authors, false-positive co-authors should be removed.
  • should not hedge: replace phrases like hopefully, <x> won't happen anymore with definite wording.
  • should not contain hidden information like `` or extra information after the description's divider ----.
  • should not contain unrelated contents (e.g.: Release Notes, Configuration, etc.) from a Renovate update PR.

PR Co-authors

A person counts as a PR co-author once they (co-)authored a commit that is not simply a Merge base branch into branch commit. Mergers must remove such false-positive co-authors when writing the squash message. Every true co-author must remain in the commit message.

PRs targeting `main`

The commit message of PRs targeting main is always

bash
$PR_TITLE ($PR_INDEX)

$REWRITTEN_PR_SUMMARY

Backport PRs

The commit message of backport PRs is always

bash
$PR_TITLE ($INITIAL_PR_INDEX) ($BACKPORT_PR_INDEX)

$REWRITTEN_PR_SUMMARY

Contribution Roles

Maintainers

We list maintainers so every PR gets proper review.

Review expectations

Every PR must be reviewed by at least two maintainers (or owners) before merge. Exception: after one week, refactoring PRs and documentation-only PRs need only one maintainer approval.

Maintainers are expected to spend time on code reviews.

Becoming a maintainer

A maintainer should already be a Gitea contributor with at least four merged PRs. To apply, use the Discord #develop channel. Maintainer teams may also invite contributors.

Stepping down, advisors, and inactivity

If you cannot keep reviewing, apply to leave the maintainers team. You can join the advisors team; advisors who want to review again are welcome back as maintainers.

If a maintainer is inactive for more than three months and has not left the team, owners may move them to the advisors team.

Account security

For security, maintainers should enable 2FA and sign commits with GPG when possible:

Any account with write access (including bots and TOC members) must use 2FA.

Mergers

Mergers are the maintainers who carry out the final merge of approved PRs. Their responsibilities, described throughout this guide, are:

  • Merging PRs from the merge queue in order, once a PR has lgtm/done, no open discussions, and no merge conflicts.
  • Rewriting the PR title and description prior to the merge, making the commit message clear.
    In particular, mergers should edit the PR description.
    Mergers should not edit the actual commit message except to remove unnecessary information. Because of that, even if users are looking at the PR, they can understand what changed.
  • Assigning the correct labels (including type/โ€ฆ) needed for changelog and backport decisions.
  • Agreeing, together with the owners, on when a release is ready (see release management).
  • Merging a PR also means the PR looks good to the merger and is approved by the merger.

If a merger violates these merge guides more than 3 times in the past 365 days
(e.g.: merge with unresolved reviews without TOC decision to ignore the review, merge with garbage commit messages),
they may lose their merging privileges for at least three months.

Becoming a merger

A merger must already be a Gitea maintainer.
To apply, use the Discord #maintainers channel.
The minimum requirement for applications to become a merger is to have participated actively in the community for at least four months before applying.
Ultimately, regardless of previous participation, you can only become a merger if the TOC votes in your favor.

You may also be invited by the TOC to become a merger.

Technical Oversight Committee (TOC)

At the start of 2023, the Owners team was dissolved. Instead, the governance charter proposed a technical oversight committee (TOC) which expands the ownership team of the Gitea project from three elected positions to six positions. Three positions are elected as it has been over the past years, and the other three consist of appointed members from the Gitea company.
https://blog.gitea.com/quarterly-23q1/

TOC election process

Any maintainer is eligible to be part of the community TOC if they are not associated with the Gitea company.
A maintainer can either nominate themselves, or can be nominated by other maintainers to be a candidate for the TOC election.
If you are nominated by someone else, you must first accept your nomination before the vote starts to be a candidate.

The TOC is elected for one year, the TOC election happens yearly.
After the announcement of the results of the TOC election, elected members have two weeks time to confirm or refuse the seat.
If an elected member does not answer within this timeframe, they are automatically assumed to refuse the seat.
Refusals result in the person with the next highest vote getting the same choice.
As long as seats are empty in the TOC, members of the previous TOC can fill them until an elected member accepts the seat.

If an elected member that accepts the seat does not have 2FA configured yet, they will be temporarily counted as answer pending until they manage to configure 2FA, thus leaving their seat empty for this duration.

If multiple persons have the same amount of votes, a random draw will be used to determine the order of the candidates with the same amount of votes, and thus who gets the seat first.
The candidates will be placed in the list in an alphabetical insensitive order by their username.
We use this script to determine the order of candidates with the same amount of votes:

python
import random
random.seed("Gitea TOC <YEAR> Election")
random.choice([<CANDIDATE_1>, <CANDIDATE_2>, ...])

The result of this script needs then to be published in the TOC election issue to ensure transparency of the process.

Current TOC members

Previous TOC/owners members

Here's the history of the owners and the time they served:

Governance Compensation

Each member of the community elected TOC will be granted $500 each month as compensation for their work.

Furthermore, any community release manager for a specific release or LTS will be compensated $500 for the delivery of said release.

These funds will come from community sources like the OpenCollective rather than directly from the company.
Only non-company members are eligible for this compensation, and if a member of the community TOC takes the responsibility of release manager, they would only be compensated for their TOC duties.
Gitea Ltd employees are not eligible to receive any funds from the OpenCollective unless it is reimbursement for a purchase made for the Gitea project itself.

Roadmap

Each year a roadmap will be discussed with the entire Gitea maintainers team, and feedback will be solicited from various stakeholders.
TOC members need to review the roadmap every year and work together on the direction of the project.

When a vote is required for a proposal or other change, the vote of community elected TOC members count slightly more than the vote of company elected TOC members. With this approach, we both avoid ties and ensure that changes align with the mission statement and community opinion.

You can visit our roadmap on the wiki.


Development (`docs/development.md`)

Development

This document describes how to build Gitea from source and the day-to-day
development workflow. For prerequisites and how to obtain the code, see
build-setup.md. For running tests, see testing.md. For the
contribution workflow and review process, see CONTRIBUTING.md.

Area-specific guidelines:

Building

To build Gitea for development, run:

bash
make build

No build tags are required: SQLite support is compiled in by default, which is
enough for local development. The build target runs two sub-targets, frontend
and backend. The bindata tag embeds the frontend assets into the binary and is
only needed when packaging a self-contained build, so leave it out during
development.

See make help for all available targets, and the workflows in
.github/workflows
to see how continuous integration builds and checks Gitea.

Building continuously

To rebuild automatically when source files change:

bash
# watch both frontend and backend
make watch

# or watch only the frontend (starts the Vite dev server)
make watch-frontend

# or watch only the backend (Go)
make watch-backend

Watching all backend source files may hit the default open-files limit on macOS or
Linux; raise it with ulimit -n 12288 for the current shell, or in your shell
startup file to make it permanent.

Formatting, linting and checks

Continuous integration rejects pull requests that fail formatting, linting, or
consistency checks. Format your code first:

bash
make fmt

Then lint:

bash
# lint everything
make lint
# or only one side
make lint-backend
make lint-frontend

Many linters can fix issues automatically with make lint-fix (or the scoped
make lint-backend-fix / make lint-frontend-fix). The combined consistency
checks that CI runs are available as make checks.

Building and adding SVGs

SVG icons are built with make svg, which compiles the icon sources into
public/assets/img/svg. Custom icons can be added under web_src/svg.

Updating the API

When you create or change API routes, you must update the
Swagger documentation
using go-swagger comments. See the
backend development guidelines for how API routes,
request/response structs, and swagger definitions fit together.

Regenerate and validate the spec after changing an endpoint, then commit the
updated JSON:

bash
make generate-swagger
make swagger-validate

CI verifies the committed spec is up to date with:

bash
make swagger-check

Creating new configuration options

When adding configuration options it is not enough to add them to the
modules/setting files. Also update
custom/conf/app.example.ini, and document them in
the configuration cheat sheet,
which lives in the documentation repository.

Database migrations

If you make breaking changes to a database-persisted struct under models/, add a
new migration in modelmigration/. See testing.md
for running the migration tests.

Testing

For unit, integration, end-to-end, and migration tests, see testing.md.

IDE configuration

Visual Studio Code

A launch.json and tasks.json are provided in
contrib/development/vscode. See
contrib/development/README.md for details.

GoLand

Clicking the Run Application arrow on func main() in /main.go starts a
debuggable Gitea instance.

The Output Directory in Run/Debug Configuration must be set to the Gitea
project directory (the one containing main.go and go.mod). Otherwise the working
directory is a GoLand temporary directory, which prevents Gitea from loading dynamic
resources (such as templates) in development.

Submitting your changes

Push your branch and open a pull request. See CONTRIBUTING.md
for the review process and PR requirements. For help, join the #Develop channel on
Discord.


Guidelines Backend (`docs/guidelines-backend.md`)

Backend development guidelines

This document covers backend-specific architecture and contribution expectations.
For the general workflow see CONTRIBUTING.md, and for building
and testing see development.md and testing.md.

Background

The backend is written in Go. Web routing is handled by
chi and database access goes through the
XORM ORM. Understanding how the packages depend on each other is
essential before contributing backend code.

Package design

Package layout

The backend is split into top-level packages, each with a focused responsibility:

  • build: helper scripts used at compile time
  • cmd: subcommands such as web, serv, hooks, doctor, and admin utilities
  • models: data structures and database operations (XORM); keeps external
    dependencies to a minimum
    • models/db: core database operations
    • models/fixtures: sample data used by tests
  • modelmigration: schema migration scripts
  • modules: standalone functionality with few dependencies
    • modules/setting: configuration handling
    • modules/git: interaction with the Git command line
  • routers: request handlers, split into api, web, install, and private
  • services: business logic that ties routers and models together
  • templates: Go HTML templates
  • public: compiled frontend assets
  • tests: integration and end-to-end test helpers

Dependency direction

Dependencies only flow in one direction:

text
cmd โ†’ routers โ†’ services โ†’ models โ†’ modules

A package on the left may import a package on its right, but never the reverse.

Naming conventions

  • Top-level packages use the plural form: services, models, routers.
  • Subpackages use the singular form: services/user, models/repository.

When packages from different layers share a name, use a snake_case import alias to
disambiguate:

go
import user_service "gitea.dev/services/user"

Database transactions

Operations that must roll back together should run inside db.WithTx() (or
db.WithTx2() when a value must be returned), defined in models/db/context.go.
Functions that participate in a transaction take a context.Context as their first
parameter so the transaction can be propagated.

PostgreSQL, MySQL and MSSQL (via READ_COMMITTED_SNAPSHOT) read the last committed
row version, so reads never wait for writers. Guard read-then-write logic with a
conditional UPDATE or a lock.

XORM gotchas

  • Never call x.Update(exemplar) without an explicit WHERE clause โ€” it updates
    every row in the table.
  • Partial table migrations must use SyncWithOptions(IgnoreDrop...) rather than a
    plain Sync.
  • When inserting rows with preset IDs, MSSQL requires SET IDENTITY_INSERT to be
    enabled and PostgreSQL requires the sequence to be updated afterwards.

Dependencies

Go dependencies are managed with Go Modules.

Pull requests should only modify go.mod and go.sum where it relates to the
change at hand, be it a bug fix or a new feature. Otherwise, these files should only
be touched by pull requests whose sole purpose is updating dependencies. Run
make tidy after any change to go.mod.

Any go.mod / go.sum update must be justified in the PR description and must be
verified by reviewers and the merger to reference an existing upstream commit.

Golang HTML template

Gitea uses Go's built-in HTML template engine which is dynamically & weakly typed.
To make template code maintainable:

  • Go code should take over complex logic and prepare template data as much as possible, templates only render the data.
  • Prefer struct types provided by Go code instead of map types for template data.
  • Avoid using single word names for non-local variables.
  • Avoid passing "root" $ or "." . to sub-templates, instead pass the specific data needed by the sub-template.
  • Use explicit variable names instead of . to access data: {{range $item := $.TargetItems}}{{ $item.Name }}{{end}}
  • Use Go code to implement render helpers if the render logic is too complex.

Using a modern and statically & strongly typed template engine to replace Golang HTML template might be good,
but the challenge is huge, the requisites are:

  • A working and maintainable proof-of-concept for the most complex templates (like "PR View" and "PR Diff").
  • A firm commitment of sufficient engineering resources.

API v1

The API is documented with Swagger and is modelled
on the GitHub API.

GitHub API compatibility

Gitea's API should use the same endpoints and fields as the GitHub API where
possible, unless there is a good reason to deviate.

  • If Gitea offers functionality GitHub does not, a new endpoint may be added.
  • If Gitea exposes information the GitHub API does not, a new field may be added as
    long as it does not collide with a GitHub field.
  • Existing fields should not be removed unless there is a strong reason; the same
    applies to status responses.

If you notice a problem that would require a breaking change, leave a comment in the
code for a future refactor to API v2 (which is currently not planned) rather than
breaking v1.

Adding and maintaining API routes

  • All possible results (errors, success, and failure messages) must be documented in
    the swagger comments on the route.
  • Every JSON request body must be defined as a struct in modules/structs/ and
    registered in routers/api/v1/swagger/options.go.
  • Every JSON response must be defined as a struct in modules/structs/ and
    registered with its category under routers/api/v1/swagger/.

HTTP methods and status codes

In general, choose HTTP methods as follows:

  • GET returns the requested object(s) with status 200 OK.
  • POST creates a new object (e.g. a user) and returns 201 Created with the
    created object.
  • PUT adds or assigns an existing object (e.g. a user to a team) and returns
    204 No Content with no response body.
  • PATCH edits an existing object and returns the changed object with 200 OK.
  • DELETE removes an object and returns 204 No Content with no body.

Requirements for API routes

  • All parameters of endpoints that edit an object must be optional, except those
    needed to identify the object, which are required.
  • Endpoints returning lists must support pagination (page and limit query
    options) and set the X-Total-Count header via ctx.SetTotalCountHeader(...).

Guidelines Frontend (`docs/guidelines-frontend.md`)

Frontend development guidelines

This document covers frontend-specific architecture and contribution expectations.
For the general workflow see CONTRIBUTING.md, and for building
and testing see development.md and testing.md.

Background

The frontend uses Vue 3, hard-forked Fomantic-UI (built on jQuery)
and Tailwind CSS. Pages are rendered with Go HTML templates.
Source files live in:

  • web_src/css/: CSS styles
  • web_src/js/: JavaScript and TypeScript
  • web_src/js/components/: Vue components
  • web_src/js/features/: feature modules wired up at page load
  • templates/: Go HTML templates

Dependencies

Frontend dependencies are managed with pnpm. The same rules as
for backend dependencies apply, except the
relevant files are package.json and pnpm-lock.yaml, and new versions must always
reference an existing published version.

Framework usage

Mixing frameworks arbitrarily makes code hard to maintain. Recommended combinations:

  • Vue3
  • Vanilla JavaScript
  • Fomantic-UI (jQuery), deprecated, we vendored a specific version with a lot of changes.

Avoid combinations such as Vue with Fomantic-UI.
Vue components may reuse Fomantic-UI CSS classes for visual consistency.
Use Go templates for simple or SEO-relevant pages and Vue for complex, interactive pages.
Gitea uses Vue 3 without JSX to keep HTML and JavaScript separate.

[!NOTE]
Fomantic-UI is not an accessibility-friendly framework. Gitea patches some ARIA
behavior, but accessibility work is ongoing โ€” prefer semantic HTML and test
keyboard/screen-reader behavior where you can.

Gitea-specific conventions

  • Keep features in their own files or directories.
  • Use kebab-case for HTML ids and classes with 2-3 feature keywords.
  • Prefix classes to avoid short-name conflicts between different frameworks.
  • Our framework can automatically link "input" and "label" if they are the children of a .field element,
    no need to write id/for attributes for them unless there are reasons to do so.
  • Create a new class name when overriding framework styles instead of editing the framework's own classes,
    or fix the framework's source to fix all cases.
  • Prefer semantic elements such as over generics.
  • Avoid !important; when it is unavoidable, document why.
  • Prefix custom DOM events with ce-.

CSS

Prefer Tailwind utility classes with the tw- prefix, and the flex-* layout
helpers over per-child margins. Gitea also ships a small set of custom helpers:
gt- for general helpers and g- for framework-level helpers (see
web_src/css/helpers.css); use these only when a Tailwind utility does not exist.

Write class attributes as a single readable unit in templates:

html
<div class="flex-text-inline {{if .IsFoo}}tw-hidden{{end}}"></div>

TypeScript

  • Use import type for type-only imports.
  • Use the ! non-null assertion (rather than ?./??) when a value is known to always exist.
  • Only mark a function async when it actually uses await or returns a Promise.
    Avoid async event listeners; if unavoidable, call e.preventDefault() before the first await.

Data fetching

Use the GET, POST, PUT, PATCH, and DELETE wrappers from
web_src/js/modules/fetch.ts.

Prefer to use our fetch-action.ts framework
for form submissions, button clicks and network requests, which provides a consistent UX and error handling.

DOM attributes

Avoid node.dataset because of its camel-casing behavior; use node.getAttribute
in new code. Never bind user-provided data directly onto DOM nodes.

Showing and hiding elements

  • In Vue, use v-if and v-show. If an element contains unmanaged DOM, use v-show to avoid losing the DOM state.
  • In Go templates and plain JavaScript, use the .tw-hidden class together with the
    showElem(), hideElem(), and toggleElem() helpers from
    web_src/js/utils/dom.ts.

When running Gitea in development mode, standardized UI components are available at
/devtest (for example http://localhost:3000/devtest). These pages are also used
by the e2e tests.


Guidelines Refactoring (`docs/guidelines-refactoring.md`)

Refactoring guidelines

This document covers expectations for refactoring work. For the general workflow see
CONTRIBUTING.md.

Background

Gitea is a large, long-lived project. Over time the codebase has accumulated
outdated mechanisms, mixed frameworks, and legacy code that can cause bugs or slow
down new features. Refactoring keeps the codebase maintainable, but it needs to be
done carefully so it improves things without introducing regressions.

Writing a refactoring PR

  • Be forward-looking: address the root cause, not just the immediate symptom.
  • Aim to reduce ambiguity and conflicts and to improve maintainability.
  • Explain the rationale in the PR description: why the refactor is necessary, how it
    resolves the legacy problem, and its advantages and disadvantages.
  • Keep the scope tight: preserve existing behavior where feasible and avoid bundling
    unrelated changes.
  • Break large refactors into intermediate steps across multiple PRs so each one is
    easy to review.
  • Include tests that verify the behavior stays correct.
  • Prefer scheduling non-bugfix refactoring early in a milestone, so any issues
    surface well before a release.
  • If there is disagreement about a refactor, escalate to the Technical Oversight
    Committee (TOC) for a decision.

Reviewing and merging

  • Keep refactoring PRs short-lived (typically no more than 7 days) with quick review
    cycles, and merge them promptly so they do not block on unrelated work.
  • A non-author core member may approve and merge a refactoring PR after 7 days if the
    TOC has raised no objection.
  • Accept imperfect intermediate implementations as long as the final result improves
    the codebase.
  • A temporary regression caused by a necessary refactor is acceptable if it is fixed
    promptly afterwards.

Release Management (`docs/release-management.md`)

Release management

This document describes the release cycle, backports, versioning, and the release manager checklist. For everyday contribution workflow, see CONTRIBUTING.md.

Backports and Frontports

What is backported?

We backport PRs given the following circumstances:

  1. We backport bug- and security-fixes and small enhancements. Large changes such as refactors are not backported.
  2. We never backport new features.
  3. We never backport breaking changes except when
    1. The breaking change has no effect on the vast majority of users
    2. The component triggering the breaking change is marked as experimental

How to backport?

In the past, it was necessary to manually backport your PRs.
Now, that's not a requirement anymore as our backport bot tries to create backports automatically once the PR is merged when the PR

  • does not have the label backport/manual
  • has the label backport/<version>

The backport/manual label signifies either that you want to backport the change yourself, or that there were conflicts when backporting, thus you must do it yourself.

Format of backport PRs

The title of backport PRs should be

text
<original PR title> (#<original pr number>)

The first two lines of the summary of the backporting PR should be

text
Backport #<original pr number>

with the rest of the summary and labels matching the original PR.

Frontports

Frontports behave exactly as described above for backports.

Release Cycle

We use a release schedule so work, stabilization, and releases stay predictable.

Cadence

  • Aim for a major release about every three or four months.
  • Starting with v1.26 the release cycle will be more predictable and follow a more regular schedule.

Release schedule

We will try to publish a new major version every three months:

  • v1.26.0 in April 2026
  • v1.27.0 in June 2026
  • v1.28.0 in September 2026
  • v1.29.0 in December 2026

Patch releases

During a cycle we may ship patch releases for an older line. For example, if the latest release is v1.2, we can still publish v1.1.1 after v1.1.0.

End of life (EOL)

We support per standard the last major release. For example, if the latest release is v1.26, we support v1.26 and v1.25, but not v1.24 anymore. We will only publish security fixes for the last major release, so if you are using an older release, please upgrade to a supported release as soon as possible.
Also we always try to support the latest on main branch, so if you are using the latest on main, you should be fine.

Versions

Gitea has the main branch as a tip branch and has version branches
such as release/v1.19. release/v1.19 is a release branch and we will
tag v1.19.0 for binary download. If v1.19.0 has bugs, we will accept
pull requests on the release/v1.19 branch and publish a v1.19.1 tag,
after bringing the bug fix also to the main branch.

Since the main branch is a tip version, if you wish to use Gitea
in production, please download the latest release tag version. All the
branches will be protected via GitHub, all the PRs to every branch must
be reviewed by two maintainers and must pass the automatic tests.

Releasing Gitea

Track each release using the release issue template.

  • Before releasing, confirm all the version's milestone issues or PRs have been resolved. Then discuss the release on Discord channel #maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody is against it in about several hours.
  • When creating a release branch, tag its fork point on main as the next version's -dev tag, e.g. v30.0.0-dev for release/v29.
  • In the GitHub Actions tab, open the release-create-tag workflow, click "Run workflow", select the release branch and enter a version such as 28.0.1. After maintainer approval, it pushes a signed tag and CI publishes the release with generated notes.
  • Optionally send a PR to the blog repository announcing the release.
  • Verify all release assets were correctly published through CI on dl.gitea.com and GitHub releases. Once ACKed:

Testing (`docs/testing.md`)

Testing

Gitea has four kinds of automated tests: backend unit tests, integration tests,
end-to-end (e2e) tests, and migration tests. Local runs default to SQLite, so no
extra services are required to get started.

For prerequisites see build-setup.md; for the build workflow see
development.md.

Unit tests

Backend unit tests live in *_test.go files next to the code they cover. Set
GITEA_TEST_LOG_SQL=1 to log all SQL statements executed during the tests.

bash
make test-backend

To run a single backend test, use go test directly or the # selector:

bash
go test -run '^TestName$' ./modulepath/
make test-backend#TestName

Frontend unit tests run with Vitest browser mode:

bash
make test-frontend
# single file:
pnpm exec vitest <path-filter>

Integration tests

Integration tests exercise Gitea against a real database. They live in
tests/integration/ and require Git LFS to be installed.
The database is selected with GITEA_TEST_DATABASE; an empty value defaults to
SQLite, which needs no external service:

bash
make test-integration

Run a single integration test with the # selector:

bash
make test-integration#TestName

If you hit errors such as a mismatched database version or SSH push failures, try a
clean rebuild first:

bash
make clean build

Running against other databases

Set GITEA_TEST_DATABASE together with the matching TEST_* connection variables.
The commands below start a throwaway database container (press Ctrl-C to stop and
remove it) and then run the tests against it.

MySQL

bash
docker run -e "MYSQL_DATABASE=test" -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" -p 3306:3306 --rm --name mysql mysql:latest
bash
GITEA_TEST_DATABASE=mysql TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test TEST_MYSQL_USERNAME=root TEST_MYSQL_PASSWORD='' make test-integration

PostgreSQL

PostgreSQL tests also use a MinIO container for object storage:

bash
docker run -e "POSTGRES_DB=test" -e "POSTGRES_USER=postgres" -e "POSTGRES_PASSWORD=postgres" -p 5432:5432 --rm --name pgsql postgres:latest
docker run --rm -p 9000:9000 -e MINIO_ROOT_USER=123456 -e MINIO_ROOT_PASSWORD=12345678 --name minio bitnamilegacy/minio:2023.8.31
bash
GITEA_TEST_DATABASE=pgsql TEST_MINIO_ENDPOINT=localhost:9000 TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=postgres TEST_PGSQL_USERNAME=postgres TEST_PGSQL_PASSWORD=postgres make test-integration

MSSQL

bash
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_PID=Standard" -e "SA_PASSWORD=MwantsaSecurePassword1" -p 1433:1433 --rm --name mssql microsoft/mssql-server-linux:latest
bash
GITEA_TEST_DATABASE=mssql TEST_MSSQL_HOST=localhost:1433 TEST_MSSQL_DBNAME=gitea_test TEST_MSSQL_USERNAME=sa TEST_MSSQL_PASSWORD=MwantsaSecurePassword1 make test-integration

Running the database test workflow with Gitea Runner

The CI database test jobs can be run locally with
Gitea Runner. Running every job is
resource-intensive and not recommended:

bash
gitea-runner exec -W ./.github/workflows/pull-db-tests.yml --event=pull_request --default-actions-url="https://github.com" -i catthehacker/ubuntu:runner-latest

List the available job names, then run a single one:

bash
gitea-runner exec -W ./.github/workflows/pull-db-tests.yml --event=pull_request --default-actions-url="https://github.com" -i catthehacker/ubuntu:runner-latest -l
gitea-runner exec -W ./.github/workflows/pull-db-tests.yml --event=pull_request --default-actions-url="https://github.com" -i catthehacker/ubuntu:runner-latest -j <job_name>

Recorded API responses

Repository migration unit and integration tests replay API responses recorded under
_mock_data/, so they run offline. Setting the environment variables a test reads, usually
API credentials, makes it record from the live API instead. To re-record, delete the test's
_mock_data directory, run the test with those variables set, and update its assertions.

End-to-end tests

End-to-end tests drive a running Gitea instance with Playwright:

bash
make test-e2e

To run a single e2e test file, pass it via GITEA_TEST_E2E_FLAGS:

bash
GITEA_TEST_E2E_FLAGS='<filepath>' make test-e2e

Useful environment variables:

Variable Description
GITEA_TEST_E2E_DEBUG When set, show the Gitea server output.
GITEA_TEST_E2E_FLAGS Additional flags passed to Playwright, e.g. --ui.
GITEA_TEST_E2E_TIMEOUT_FACTOR Timeout multiplier (default: 4 on CI, 1 locally).

Migration tests

If you change a database-persisted struct under models/ you will usually need a
new migration in modelmigration. Run the migration tests with:

bash
make test-migration

Continuous integration

CI runs the unit tests, runs the integration tests against every supported database,
and tests migration from several recent Gitea versions. Please submit your pull
request with additional unit and integration tests as appropriate. Prefer unit tests
when the logic can be tested in isolation, and keep local integration and e2e tests
fast (aim for sub-2s runtime).


--- METRICS ---