Working with repositories

Tags and Releases

What are tags?

Tags are a feature in Git that can be used to make a snapshot of a repository from a point in time. It is generally used to mark releases (e.g., v1.2.4), and it functions as a shortcut to see what the repo looked like at that time.

What are releases?

Releases are a feature in Forgejo, independent of Git, that allows you to attach files and release notes along with the source code at the time, and share it in Forgejo, linking to a Git tag.

Wait, what is the difference between tags and releases?

They are very similar. The difference is that tags are just the repository frozen in time and are part of Git (you can make a tag inside of Git), but releases are tags accompanied by a binary file and are not part of Git (you need to go to your repository page in the web interface to create a release).

Creating tags and releases

If you only want to create tags, using Git is recommended. If you want to create a full release, this is only possible through Forgejo's web interface, or through its API.

Creating a Tag with Git

To create a tag using Git, use the following command in your local repository:

git tag -a <tag name> -m "<my tag message>"

You can omit "<my tag message>" to write a longer tag message in an editor window.

Tip: Tags are generally labeled by version numbers. It is good practice to prefix a version number with a v (e.g., v1.2.3) and to use the Semantic Versioning specification for assigning and incrementing version numbers.

Tags are not automatically pushed when you run git push (compared to commits or branches). They have to be pushed manually to the remote target, like so:

git push --tags <remote target, probably "origin">

The argument --tags pushes all local tags to the remote target. If you want to push only a specific tag, use:

git push <remote target, probably "origin"> <tag name, e.g., "v1.2.3">

Creating a Release in the Web Interface

To create a release in the web interface, first go to the Releases tab of your repository (1), and click on New Release (2):

Here, you need to enter a version number for your new release (1), select the branch that contains the code you want to release (2), and add a title (3). Optionally, you can also add a description (4) or add assets to the release in the form of attaching files (5) or adding external links (6):

You can now either save it as a draft, or publish the release outright.

You are then redirected to the Releases tab of your repository. The newly created release is now listed there:

Here, you can edit the release if needed (1). You will also see options to download the source code of the repository at the commit the release was created at as .zip or .tar.gz files (2). Finally, if on the previous page you added assets like an attached file or an external link, they will also show up here (3).

Creating a Release through the API

All the operations accessible in the web interface are also available through the API. You can use the following endpoints to:

Branch and tag protection

Protected branches

Protected branches enforce restrictions such as force pushing or merging unless a given number of approvals are obtained on a pull request.

To protect a branch, you need to go to the repository’s Settings > Branches page and add a new rule.

Branch protection settings

The name of the branch can be a glob where / is the separator and ** spans across separators, for instance main, release/** or precious*.

If two rules apply to the same branch, the one that has no glob takes precedence.

Protected tags

Protected tags allow control over who has permission to create or update Git tags. Each rule allows you to match either an individual tag name, or use an appropriate pattern to control multiple tags at once.

Setting up protected tags

To protect a tag, you need to follow these steps:

  1. Go to the repository’s Settings > Tags page.
  2. Type a pattern to match a name. You can use a single name, a glob pattern or a regular expression.
  3. Choose the allowed users and/or teams. If you leave these fields empty, no one is allowed to create or modify this tag.
  4. Select Save to save the configuration.

Tag protection settings

Protected tag patterns

The pattern uses glob or regular expressions to match a tag name. For regular expressions, you need to enclose the pattern in slashes.

Examples:

Type Protected tag pattern Possible matching tags
Glob v* v, v-1, version2
Glob v[0-9] v0, v1 up to v9
Glob *-release 2.1-release, final-release
Glob forgejo only forgejo
Glob *forgejo* forgejo, 2.1-forgejo, 1_forgejo-r
Glob {v,rel}-* v-, v-1, v-final, rel-, rel-x
Glob * matches all possible tag names
Regex /\Av/ v, v-1, version2
Regex /\Av[0-9]\z/ v0, v1 up to v9
Regex /\Av\d+\.\d+\.\d+\z/ v1.0.17, v2.1.0
Regex /\Av\d+(\.\d+){0,2}\z/ v1, v2.1, v1.2.34
Regex /-release\z/ 2.1-release, final-release
Regex /forgejo/ forgejo, 2.1-forgejo, 1_forgejo-r
Regex /\Aforgejo\z/ only forgejo
Regex /^forgejo$/ only forgejo
Regex /\A(v|rel)-/ v-, v-1, v-final, rel-, rel-x
Regex /.+/ matches all possible tag names

Blame File View

Forgejo supports viewing the line-by-line revision history for a file, also known as blame view. You can also use git blame on the command line to view the revision history of lines within a file.

Blame view of a file

  1. Navigate to and open the file whose line history you want to view.
  2. Click the Blame button in the file header bar.
  3. The new view shows the line-by-line revision history for a file with author and commit information on the left side.
  4. To navigate to an older commit, click the icon.

Ignore commits in the blame view

All revisions specified in the .git-blame-ignore-revs file are hidden from the blame view. This is especially useful to hide reformatting changes and keep the benefits of git blame. Lines that were changed or added by an ignored commit will be blamed on the previous commit that changed that line or nearby lines. The .git-blame-ignore-revs file must be located in the root directory of the repository. For more information, like the file format, see the git blame --ignore-revs-file documentation.

Bypassing .git-blame-ignore-revs in the blame view

If the blame view for a file shows a message about ignored revisions, you can see the normal blame view by appending the URL parameter ?bypass-blame-ignore=true.

README badges

If the badges service is enabled, Forgejo makes it possible to add badges - transparently generated by a service like shields.io - to your READMEs and other documentation. These badges let you display useful information about your repository within documentation that might also be displayed elsewhere, outside of the forge itself (such as on container information pages, library documentation sites, and so on). Information such as the latest release, stars, pull request and issue information, or Actions workflow statuses.

The badges are returned in SVG format and are available under the https://forgejo.example.com/{username}/{repository}/badges path. Forgejo currently supports generating the following badges:

All query parameters not known to Forgejo will be passed along to the badge generator service as is. If using the default - shields.io-based - generator, this means that query parameters such as style and color will be respected.

Issue and Pull Request Templates

Some projects have a standard list of questions that users need to answer when creating an issue or pull request. Forgejo supports adding templates to the default branch of the repository so that they can autopopulate the form when users are creating issues and pull requests. This will cut down on the initial back-and-forth of getting some clarifying details. It is currently not possible to provide generic issue/pull-request templates globally. In general, there is the choice of using either multiple or a single issue template file(s), a single pull-request template file and additionally the possibility of adding an issue config.

Additionally, the New Issue page URL can be suffixed with ?title=Issue+Title&body=Issue+Text and the form will be populated with those strings. Those strings will be used instead of the template if there is one.

Directory names

Users can create multiple template files inside a special directory and this allows different use cases: users can choose to use the template that is suited to address their specific problem. Please note that there can be multiple issue templates. However, there may only be a single pull request template in one repository.

Forgejo will check for template files in the following directories, since Forgejo checks these services to make migration from them easier:

Inside the directory can be multiple markdown (.md) or yaml (.yaml/.yml) files for templates of the form - these are the three allowed file extensions.

File names

For the three file types - issue templates, pull request templates, and issue configs, there are various possible file names that may be used in the directories listed above.

Issue templates are arbitrarily named files with any of the three file extensions mentioned above, and there may be any number of them, so they each get their dedicated subdirectory: issue_template and ISSUE_TEMPLATE are the possible names for the subdirectory that the issue templates go into.

In contrast, there may only be a single pull request template per repository, so there is no extra subdirectory for it. It can reside in any of the .<service_name> directories (with the exception of the .gitlab directory, this is not supported!) listed in the previous section. A pull request template has a fixed name (see options below) and can end with any of the three file extensions mentioned above.

Possible file names and file extensions for PR templates:

Issue config template files need to go into the same subdirectory as issue template files (see above section). Possible file names and file extensions for issue config:

An example setup for a single issue template file together with a single pull request template file could look like this:

.forgejo/
  ISSUE_TEMPLATE/
    issue_template.yaml
  pull_request_template.yml

Another example setup but with multiple issue template files instead could look like this:

.forgejo/
  issue_template/
    bug.yaml
    config.yml
    feature.yaml
  pull_request_template.md

Syntax for markdown template

---
name: 'Template Name'
about: 'This template is for testing!'
title: '[TEST] '
ref: 'main'
labels:
  - bug
  - 'help needed'
---

This is the template!

In the above example, when a user is presented with the list of issues they can submit, this would show as Template Name with the description This template is for testing!. When submitting an issue with the above example, the issue title would be pre-populated with [TEST] while the issue body would be pre-populated with This is the template!. The issue would also be assigned two labels, bug and help needed, and the issue will have a reference to main.

Syntax for yaml template

This example YAML configuration file defines an issue form using several inputs to report a bug.

name: Bug Report
about: File a bug report
title: '[Bug]: '
ref: 'main'
labels:
  - bug
  - 'help needed'
body:
  - type: markdown
    attributes:
      value: |
        Thanks for taking the time to fill out this bug report!
  # some markdown that will only be visible once the issue has been created
  - type: markdown
    attributes:
      value: |
        This issue was created by an issue **template** :)
    visible: [content]
  - type: input
    id: contact
    attributes:
      label: Contact Details
      description: How can we get in touch with you if we need more info?
      placeholder: ex. email@example.com
    validations:
      required: false
  - type: textarea
    id: what-happened
    attributes:
      label: What happened?
      description: Also tell us, what did you expect to happen?
      placeholder: Tell us what you see!
      value: 'A bug happened!'
    validations:
      required: true
  - type: dropdown
    id: version
    attributes:
      label: Version
      description: What version of our software are you running?
      options:
        - 1.0.2 (Default)
        - 1.0.3 (Edge)
    validations:
      required: true
  - type: dropdown
    id: browsers
    attributes:
      label: What browsers are you seeing the problem on?
      multiple: true
      options:
        - Firefox
        - Chrome
        - Safari
        - Microsoft Edge
  - type: textarea
    id: logs
    attributes:
      label: Relevant log output
      description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
      render: shell
  - type: checkboxes
    id: terms
    attributes:
      label: Code of Conduct
      description: By submitting this issue, you agree to follow our [Code of Conduct](https://example.com)
      options:
        - label: I agree to follow this project's Code of Conduct
          required: true
        - label: I have also read the CONTRIBUTION.MD
          required: true
          visible: [form]
        - label: This is a TODO only visible after issue creation
          visible: [content]

Markdown

You can use a markdown element to display Markdown in your form that provides extra context to the user, but is not submitted by default.

Attributes:

Key Description Required Type Default Valid values
value The text that is rendered. Markdown formatting is supported. Required String - -

visible: Default is [form]

Textarea

You can use a textarea element to add a multi-line text field to your form. Contributors can also attach files in textarea fields.

Attributes:

Key Description Required Type Default Valid values
label A brief description of the expected user input, which is also displayed in the form. Required String - -
description A description of the text area to provide context or guidance, which is displayed in the form. Optional String Empty String -
placeholder A semi-opaque placeholder that renders in the text area when empty. Optional String Empty String -
value Text that is pre-filled in the text area. Optional String - -
render If a value is provided, submitted text will be formatted into a codeblock. When this key is provided, the text area will not expand for file attachments or Markdown editing. Optional String - Languages known to Forgejo.

Validations:

Key Description Required Type Default Valid values
required Prevents form submission until element is completed. Optional Boolean false -

visible: Default is [form, content]

Input

You can use an input element to add a single-line text field to your form.

Attributes:

Key Description Required Type Default Valid values
label A brief description of the expected user input, which is also displayed in the form. Required String - -
description A description of the field to provide context or guidance, which is displayed in the form. Optional String Empty String -
placeholder A semi-transparent placeholder that renders in the field when empty. Optional String Empty String -
value Text that is pre-filled in the field. Optional String - -

Validations:

Key Description Required Type Default Valid values
required Prevents form submission until element is completed. Optional Boolean false -
is_number Prevents form submission until element is filled with a number. Optional Boolean false -
regex Prevents form submission until element is filled with a value that match the regular expression. Optional String - a regular expression

visible: Default is [form, content]

Dropdown

You can use a dropdown element to add a dropdown menu in your form.

Attributes:

Key Description Required Type Default Valid values
label A brief description of the expected user input, which is displayed in the form. Required String - -
description A description of the dropdown to provide extra context or guidance, which is displayed in the form. Optional String Empty String -
multiple Determines if the user can select more than one option. Optional Boolean false -
options An array of options the user can choose from. Cannot be empty and all choices must be distinct. Required String array - -

Validations:

Key Description Required Type Default Valid values
required Prevents form submission until element is completed. Optional Boolean false -

visible: Default is [form, content]

Checkboxes

You can use the checkboxes element to add a set of checkboxes to your form.

Attributes:

Key Description Required Type Default Valid values
label A brief description of the expected user input, which is displayed in the form. Required String - -
description A description of the set of checkboxes, which is displayed in the form. Supports Markdown formatting. Optional String Empty String -
options An array of checkboxes that the user can select. For syntax, see below. Required Array - -

For each value in the options array, you can set the following keys.

Key Description Required Type Default Options
label The identifier for the option, which is displayed in the form. Markdown is supported for bold or italic text formatting, and hyperlinks. Required String - -
required Prevents form submission until element is completed. Optional Boolean false -
visible Whether a specific checkbox appears in the form only, in the created issue only, or both. Valid options are "form" and "content". Optional String array false -

visible: Default is [form, content]

Syntax for issue config

This is an example for an issue config file

blank_issues_enabled: true
contact_links:
  - name: Forgejo
    url: https://forgejo.org/
    about: Visit the Forgejo Website

Possible Options

Key Description Type Default
blank_issues_enabled If set to false, the user is forced to use a template Boolean true
contact_links Custom links to show in the choose box Contact Link Array Empty Array
Key Description Type Required
name the name of your link String true
url The URL of your link String true
about A short description of your link String true

Merge Message Templates

File Names

Possible file names for PR (Pull Request) default merge message templates:

Note: .gitea as the root directory is also recognized and kept only for compatibility reasons.

If Forgejo cannot find the file in the repository, it will search the CustomPath for a folder named default_merge_message which may contain site-wide templates.

Title/Body separation

The first line of the template creates the title, the rest makes the body of the message. Without a template, the default texts are:

You can customize the title and body of the default message following these rules:

Examples

Replace the default title and keep the default body:

Merge Title

Replace the default title and make the default body empty:

Merge Title\n

Keep the default title and replace the default body:

\n
Merge Body

The space in the first line makes the default title empty and replace the default body:

 \n
Merge body

Variables

You can use the following variables enclosed in ${} inside these templates, which follow os.Expand syntax:

Rebase

When rebasing without a merge commit, REBASE_TEMPLATE.md modifies the message of the last commit. The following additional variables are available in this template:

Webhooks

Forgejo supports webhooks for repository events. This can be configured on the settings page /:username/:reponame/settings/hooks by a repository admin. Webhooks can also be configured on a per-organization and whole-system basis (default webhooks on repository creation or instance-wide webhooks). The currently supported webhook types are:

Raw event as JSON or FORM payload:

Dedicated integration:

Generic notification messages in chosen channel/chat:

These channels don't implement all webhook types. Those types that are implemented have to be manually tested. Try them and open an issue if they do not work for your use case.

Event information

The following is an example of event information that will be sent by Forgejo to a Payload URL:

X-Forgejo-Delivery: f6266f16-1bf3-46a5-9ea4-602e06ead473
X-Forgejo-Event: push
X-GitHub-Delivery: f6266f16-1bf3-46a5-9ea4-602e06ead473
X-GitHub-Event: push
X-Gogs-Delivery: f6266f16-1bf3-46a5-9ea4-602e06ead473
X-Gogs-Event: push
X-Gitea-Delivery: f6266f16-1bf3-46a5-9ea4-602e06ead473
X-Gitea-Event: push
{
  "ref": "refs/heads/develop",
  "before": "28e1879d029cb852e4844d9c718537df08844e03",
  "after": "bffeb74224043ba2feb48d137756c8a9331c449a",
  "compare_url": "http://localhost:3000/forgejo/webhooks/compare/28e1879d029cb852e4844d9c718537df08844e03...bffeb74224043ba2feb48d137756c8a9331c449a",
  "commits": [
    {
      "id": "bffeb74224043ba2feb48d137756c8a9331c449a",
      "message": "Webhooks Yay!",
      "url": "http://localhost:3000/forgejo/webhooks/commit/bffeb74224043ba2feb48d137756c8a9331c449a",
      "author": {
        "name": "Forgejo",
        "email": "someone@forgejo.org",
        "username": "forgejo"
      },
      "committer": {
        "name": "Forgejo",
        "email": "someone@forgejo.org",
        "username": "forgejo"
      },
      "timestamp": "2017-03-13T13:52:11-04:00"
    }
  ],
  "repository": {
    "id": 140,
    "owner": {
      "id": 1,
      "login": "forgejo",
      "full_name": "Forgejo",
      "email": "someone@forgejo.org",
      "avatar_url": "https://localhost:3000/avatars/1",
      "username": "forgejo"
    },
    "name": "webhooks",
    "full_name": "forgejo/webhooks",
    "description": "",
    "private": false,
    "fork": false,
    "html_url": "http://localhost:3000/forgejo/webhooks",
    "ssh_url": "ssh://forgejo@localhost:2222/forgejo/webhooks.git",
    "clone_url": "http://localhost:3000/forgejo/webhooks.git",
    "website": "",
    "stars_count": 0,
    "forks_count": 1,
    "watchers_count": 1,
    "open_issues_count": 7,
    "default_branch": "master",
    "created_at": "2017-02-26T04:29:06-05:00",
    "updated_at": "2017-03-13T13:51:58-04:00"
  },
  "pusher": {
    "id": 1,
    "login": "forgejo",
    "full_name": "Forgejo",
    "email": "someone@forgejo.org",
    "avatar_url": "https://localhost:3000/avatars/1",
    "username": "forgejo"
  },
  "sender": {
    "id": 1,
    "login": "forgejo",
    "full_name": "Forgejo",
    "email": "someone@forgejo.org",
    "avatar_url": "https://localhost:3000/avatars/1",
    "username": "forgejo"
  }
}

Example

This is an example of how to use webhooks to run a PHP script upon push requests to the repository. In your repository Settings, under Webhooks, set up a Forgejo webhook as follows:

Now, on your server, create the PHP file webhook.php.

<?php

$secret_key = '123';

// check for POST request
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
    error_log('FAILED - not POST - '. $_SERVER['REQUEST_METHOD']);
    exit();
}

// get content type
$content_type = isset($_SERVER['CONTENT_TYPE']) ? strtolower(trim($_SERVER['CONTENT_TYPE'])) : '';

if ($content_type != 'application/json') {
    error_log('FAILED - not application/json - '. $content_type);
    exit();
}

// get payload
$payload = trim(file_get_contents("php://input"));

if (empty($payload)) {
    error_log('FAILED - no payload');
    exit();
}

// get header signature
$header_signature = isset($_SERVER['HTTP_X_FORGEJO_SIGNATURE']) ? $_SERVER['HTTP_X_FORGEJO_SIGNATURE'] : '';

if (empty($header_signature)) {
    error_log('FAILED - header signature missing');
    exit();
}

// calculate payload signature
$payload_signature = hash_hmac('sha256', $payload, $secret_key, false);

// check payload signature against header signature
if ($header_signature !== $payload_signature) {
    error_log('FAILED - payload signature');
    exit();
}

// convert json to array
$decoded = json_decode($payload, true);

// check for json decode errors
if (json_last_error() !== JSON_ERROR_NONE) {
    error_log('FAILED - json decode - '. json_last_error());
    exit();
}

// success, do something

There is a Test Delivery button in the webhook settings that allows testing the configuration as well as a list of the most Recent Deliveries.

Authorization header

Forgejo webhooks can be configured to send an authorization header to the target.

screenshot of the webhook definition webpage

The authentication string is stored encrypted in the database.

Programming language detection

Forgejo tries to detect the languages used in a repository, for each file, to use this information in a number of different ways. The most prominent use is for the display of the language statistics line at the top of the repository's home view, but the same information is also used to exclude generated and vendored files from diffs.

Repository language statistics

This comes with sensible defaults that should work for most cases, but it is not without faults or compromises, and there are scenarios where the detection needs a little guidance. Further below, we will explain how it can be influenced, but let's look at the defaults first!

Built-in language detection

Whenever the contents of a repository change, Forgejo will look at the files, and try to put them into one of the following categories: "Programming language", "Markup language", "Documentation", "Dotfile", "Configuration", "Generated", "Vendored". The sorting into categories is done by the go-enry package, please consult its documentation for the specifics. The library is mostly compatible with linguist, which is used by some other forges. The statistics are calculated based on the main branch of the repository, only update when the main branch changes, and the update may take some time.

For the repository language statistics, with the default configuration, only those files are considered that match the "Programming language" or "Markup" language categories, everything else is ignored. When viewing a diff, all files are shown, but "Generated" files are collapsed by default, and "Vendored" files are marked as such.

A short explanation of categories

While some of the categories are rather straightforward, a little explanation about them does not hurt, especially if you are considering reclassifying files into another category.

Vendored files are any file you have checked into your repository that you didn't write, but imported from elsewhere. These may include dependencies you want a local copy of, at a specific version - such as JavaScript libraries or Go packages. These may inflate your project's language stats, and may even cause it to be labeled as another language. Marking these files as vendored makes it possible to ignore them for statistics.

Generated files are - as the name implies - files that are generated, but still checked into the repository for one reason or another. These may include minified JavaScript, compiled CoffeeScript, various lock files, and so on. Similar to vendored files, you usually do not want these to show up in language stats. They're - unlike vendored files - hidden by default when viewing diffs.

Documentation are just as the name says, documentation. This includes files written in Markdown, AsciiDoc, Org Mode, and a number of others.

Configuration files are typically used to configure software, and as such, the category is not included in language statistics. Languages like JSON, TOML, YAML, SQL, and XML - among other things - are considered documentation by default.

Dotfiles are files whose name starts with a dot, which by convention, suggests they should be hidden, and as such, they are excluded from language statistics.

Programming languages and Markup languages are more or less self-explanatory. The former category includes languages like C, Go, Rust, JavaScript, and many, many others. Markup languages are CSS, HTML, Jinja templates, Jupyter Notebooks, and numerous other formats.

Please consult the enry or linguist documentation for more details.

Adjusting the language detection

Sometimes the programming language of a file is not recognized properly, or it is miscategorized. Forgejo provides a mechanism where the language detection can be told about the language of a file, and its category can be adjusted as well. The same mechanism can also force a file to be considered for language statistics, regardless of its category - or the opposite, too: to tell Forgejo never to consider it.

The way to do this is via a .gitattributes file. This file has a simple syntax where each line is made up of a pattern, followed by a space separated list of attributes. There are many attributes that git itself supports, but we're only going to talk about the custom attributes for language detection. All of these have a linguist- prefix, as that is where they originate from.

Overriding the language

In case Forgejo does not correctly recognize a file's language, you can use the linguist-language attribute to override its detection. The language names are case-insensitive, and may be specified using an alias. Spaces within language names must be replaced with hyphens.

An example showing these overrides:

# Reclassify `.pl` files as Prolog
*.pl     linguist-language=Prolog

# Whitespace in language names must be replaced with hyphens
*.glyphs linguist-language=OpenStep-Property-List

# Language names are case-insensitive, and may be specified using an alias.
# All of the following three lines are equivalent:
*.es     linguist-language=js
*.es     linguist-language=JS
*.es     linguist-language=JavaScript

Overriding the category

It is possible to mark files matching a pattern as "Documentation", "Generated", or "Vendored". This can be useful when the automatic detection of these fail, or if you want to reclassify files for some other reason. It is also possible to reclassify files that would be considered either of these, as not being "Documentation", "Generated", or "Vendored".

To achieve this, the linguist-documentation, linguist-generated, and linguist-vendored attributes can be used. All three of these are boolean, you can set them simply by listing the attribute name. You can also set an explicit value by setting them to true or false. Prefixing the attribute with a minus sign is the same as setting it to false.

It's best to illustrate this with a few examples!

# Do not consider Markdown files documentation anymore!
# Note: Both forms here are equivalent.
*.md -linguist-documentation
*.md  linguist-documentation=false

# Consider files in `dist/` generated.
# Both forms here are equivalent.
/dist/**/* linguist-generated
/dist/**/* linguist-generated=true

# Do not categorize `cpplint.py` as vendored.
cpplint.py -linguist-vendored
cpplint.py  linguist-vendored=false

Reclassifying a file will result in Forgejo proceeding with language detection. That may still result in the file not being considered for statistics. Take a look at this example:

*.nib -linguist-generated
*.nib  linguist-language=Markdown

This will classify *.nib files as non-generated, and as Markdown. However, Markdown is considered documentation, which is, by default, excluded from language statistics.

Overriding detection

In cases where a file should be considered for language statistics, regardless of its category, the linguist-detectable attribute can be used. The same attribute can be used to hide a file from the language statistics, without reclassifying it into a category that would otherwise be hidden.

For a repository whose primary contents are documentation in Markdown format, the following override would make Forgejo consider the Markdown files for the language statistics:

*.md linguist-detectable

Similarly, to hide a file from the language statistics:

config/app.js -linguist-detectable

The above will not consider the app's configuration - in JSON, but with a .js extension - for language statistics.