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]
- YOU MUST READ THE CONTRIBUTORS GUIDE BEFORE STARTING TO WORK ON A PULL REQUEST.
- New to the codebase? The development guide walks through setting up a local environment and building from source.
- 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:
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-jsonnetFor 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:
go install github.com/monitoring-mixins/mixtool/cmd/mixtool@latest
go install github.com/google/go-jsonnet/cmd/jsonnetfmt@latestThe 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:
makeFor 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:
Package <1---*> PackageVersion <1---*> PackageFile <*---1> PackageBlobAdding 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 existsCreatePackageOrAddFileToExisting: error if file already existsAddFileToExistingPackage: 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.jsinto a web component because that file is currently not tree-shakeable, import svg files individually insteat. - Any custom element used inside a
.vuefile must be added towebComponentsinvite.config.tsso 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)
- An LDAP filter specifying if a user should be given administrator
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
- The attribute of the user's LDAP record containing the user's first name.
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
- The attribute of the user's LDAP record containing the user's surname This
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
- The attribute of the user's LDAP record containing the user's email
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
- The DN to bind to the LDAP server with when searching for the user. This
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.
- The password for the Bind DN specified above, if any. Note: The password
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)))
- An LDAP filter declaring how to find the user record that is attempting to
LDAP using simple auth adds the following fields:
User DN (required)
- A template to use as the user's DN. The
%smatching 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
- A template to use as the user's DN. The
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)))
- An LDAP filter declaring when a user should be allowed to log in. The
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]
Somemaketasks build external Go tools on demand (for examplemake watch-backend). To use them, the"$GOPATH"/bindirectory must be on your
executablePATH; 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 inpackage.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 runmake 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:
git clone https://github.com/go-gitea/giteaTo 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):
git fetch origin pull/123456/head:pr-123456Build
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:
TAGS="bindata" make buildChanging 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 likeLDFLAGS='-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:
GOOS=linux GOARCH=arm64 TAGS="bindata" make buildAdding shell autocompletion
Shell completion can be generated directly from binary with:
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=truegenerates all source maps, the default for development buildsENABLE_SOURCEMAP=reducedgenerates limited source maps, the default for production buildsENABLE_SOURCEMAP=falsegenerates 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
- Community governance and review process
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-bugorlgtm/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:
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 anymorewith 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
$PR_TITLE ($PR_INDEX)
$REWRITTEN_PR_SUMMARYBackport PRs
The commit message of backport PRs is always
$PR_TITLE ($INITIAL_PR_INDEX) ($BACKPORT_PR_INDEX)
$REWRITTEN_PR_SUMMARYContribution 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:
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
- 2026-06-14 ~ 2026-12-31
Previous TOC/owners members
Here's the history of the owners and the time they served:
- Lunny Xiao - 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023
- Kim Carlbรคcker - 2016, 2017
- Thomas Boerger - 2016, 2017
- Lauris Bukลกis - 2018, 2019, 2020, 2021, 2025
- Matti Ranta - 2019, 2020, 2021, 2022, 2023
- Andrew Thornton - 2020, 2021, 2022, 2023
- 6543 - 2023, 2025
- John Olheiser - 2023, 2024
- Jason Song - 2023, 2025
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:
make buildNo 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:
# 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-backendWatching 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:
make fmtThen lint:
# lint everything
make lint
# or only one side
make lint-backend
make lint-frontendMany linters can fix issues automatically with make lint-fix (or the scopedmake 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 intopublic/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:
make generate-swagger
make swagger-validateCI verifies the committed spec is up to date with:
make swagger-checkCreating new configuration options
When adding configuration options it is not enough to add them to themodules/setting files. Also updatecustom/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 incontrib/development/vscode. Seecontrib/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 timecmd: subcommands such asweb,serv,hooks,doctor, and admin utilitiesmodels: data structures and database operations (XORM); keeps external
dependencies to a minimummodels/db: core database operationsmodels/fixtures: sample data used by tests
modelmigration: schema migration scriptsmodules: standalone functionality with few dependenciesmodules/setting: configuration handlingmodules/git: interaction with the Git command line
routers: request handlers, split intoapi,web,install, andprivateservices: business logic that ties routers and models togethertemplates: Go HTML templatespublic: compiled frontend assetstests: integration and end-to-end test helpers
Dependency direction
Dependencies only flow in one direction:
cmd โ routers โ services โ models โ modulesA 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:
import user_service "gitea.dev/services/user"Database transactions
Operations that must roll back together should run inside db.WithTx() (ordb.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 explicitWHEREclause โ it updates
every row in the table. - Partial table migrations must use
SyncWithOptions(IgnoreDrop...)rather than a
plainSync. - When inserting rows with preset IDs, MSSQL requires
SET IDENTITY_INSERTto 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. Runmake 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 inrouters/api/v1/swagger/options.go. - Every JSON response must be defined as a struct in
modules/structs/and
registered with its category underrouters/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 (
pageandlimitquery
options) and set theX-Total-Countheader viactx.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 stylesweb_src/js/: JavaScript and TypeScriptweb_src/js/components/: Vue componentsweb_src/js/features/: feature modules wired up at page loadtemplates/: 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
.fieldelement,
no need to writeid/forattributes 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 (seeweb_src/css/helpers.css); use these only when a Tailwind utility does not exist.
Write class attributes as a single readable unit in templates:
<div class="flex-text-inline {{if .IsFoo}}tw-hidden{{end}}"></div>TypeScript
- Use
import typefor type-only imports. - Use the
!non-null assertion (rather than?./??) when a value is known to always exist. - Only mark a function
asyncwhen it actually usesawaitor returns aPromise.
Avoid async event listeners; if unavoidable, calle.preventDefault()before the firstawait.
Data fetching
Use the GET, POST, PUT, PATCH, and DELETE wrappers fromweb_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-ifandv-show. If an element contains unmanaged DOM, usev-showto avoid losing the DOM state. - In Go templates and plain JavaScript, use the
.tw-hiddenclass together with theshowElem(),hideElem(), andtoggleElem()helpers fromweb_src/js/utils/dom.ts.
UI component gallery
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:
- We backport bug- and security-fixes and small enhancements. Large changes such as refactors are not backported.
- We never backport new features.
- We never backport breaking changes except when
- The breaking change has no effect on the vast majority of users
- 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
<original PR title> (#<original pr number>)The first two lines of the summary of the backporting PR should be
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
mainas the next version's-devtag, e.g.v30.0.0-devforrelease/v29. - In the GitHub Actions tab, open the
release-create-tagworkflow, click "Run workflow", select the release branch and enter a version such as28.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:
- verify the automated update of https://dl.gitea.com/gitea/version.json, where applicable to the release line
- merge the blog post PR
- announce the release in discord
#announcements
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. SetGITEA_TEST_LOG_SQL=1 to log all SQL statements executed during the tests.
make test-backendTo run a single backend test, use go test directly or the # selector:
go test -run '^TestName$' ./modulepath/
make test-backend#TestNameFrontend unit tests run with Vitest browser mode:
make test-frontend
# single file:
pnpm exec vitest <path-filter>Integration tests
Integration tests exercise Gitea against a real database. They live intests/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:
make test-integrationRun a single integration test with the # selector:
make test-integration#TestNameIf you hit errors such as a mismatched database version or SSH push failures, try a
clean rebuild first:
make clean buildRunning 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
docker run -e "MYSQL_DATABASE=test" -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" -p 3306:3306 --rm --name mysql mysql:latestGITEA_TEST_DATABASE=mysql TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test TEST_MYSQL_USERNAME=root TEST_MYSQL_PASSWORD='' make test-integrationPostgreSQL
PostgreSQL tests also use a MinIO container for object storage:
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.31GITEA_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-integrationMSSQL
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_PID=Standard" -e "SA_PASSWORD=MwantsaSecurePassword1" -p 1433:1433 --rm --name mssql microsoft/mssql-server-linux:latestGITEA_TEST_DATABASE=mssql TEST_MSSQL_HOST=localhost:1433 TEST_MSSQL_DBNAME=gitea_test TEST_MSSQL_USERNAME=sa TEST_MSSQL_PASSWORD=MwantsaSecurePassword1 make test-integrationRunning 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:
gitea-runner exec -W ./.github/workflows/pull-db-tests.yml --event=pull_request --default-actions-url="https://github.com" -i catthehacker/ubuntu:runner-latestList the available job names, then run a single one:
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:
make test-e2eTo run a single e2e test file, pass it via GITEA_TEST_E2E_FLAGS:
GITEA_TEST_E2E_FLAGS='<filepath>' make test-e2eUseful 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:
make test-migrationContinuous 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 ---
- Files Extracted: 16
- Estimated Token Budget: ~17171 tokens
- Canonical Reference: https://codewiki.google/github.com/go-gitea/gitea