Branch protection
Arbinel keeps Forgejo’s branch protection and changes three things. The rule form is simpler, with presets and a live preview. A rule can let selected users, teams and repository admins force-push. Organization owners can set rules for all their repositories.
Forgejo’s documentation covers rule matching in only two sentences, so how patterns match branches and which rule takes precedence are explained here as well.
Rule matching
Section titled “Rule matching”A rule’s Protected branch name pattern is either a plain branch name or a glob pattern.
Arbinel treats the pattern as a glob when it contains one of *, ?, [, ], {, } or \.
Otherwise it is a plain name.
| Pattern | Matches | Does not match |
|---|---|---|
main |
main, Main, MAIN |
main2, feature/main |
release/* |
release/1.0 |
release/1.0/hotfix, Release/1.0 |
release/** |
release/1.0, release/1.0/hotfix |
release |
release-* |
release-1.0 |
release-1.0/fix |
{main,develop} |
main, develop |
Main |
v[0-9]* |
v1, v2.0 |
version |
The table follows these rules:
- A plain name matches regardless of case. A glob is case-sensitive.
/separates path segments.*and?match within one segment, and**matches any number of segments.- Patterns use the gobwas/glob syntax, which also supports
[!a-z]and{a,b}. - A pattern that is not a valid glob matches only the branch with exactly that name, and the server logs a warning. The live preview reports the pattern as not valid instead.
Rule order
Section titled “Rule order”Arbinel does not combine rules within a repository. When several rules match a branch, only the first one applies, in this order:
- Plain names come before globs.
- Among rules of the same kind, the oldest rule comes first.
There is no priority field and no way to reorder rules. To make a newer glob take precedence over an older one for some branches, narrow the older pattern. You can also delete the older rule and create it again, so that it becomes the newer rule. The form shows this order under the pattern field, and the live preview lists the branches that an earlier rule already protects.
The organization rules section explains where organization rules fit into this order.
Rule form
Section titled “Rule form”Open Settings > Branches in a repository and select Add new rule, or edit an existing rule. Arbinel replaces Forgejo’s single long form with sections, and each section answers one question:
- Which branches does this rule protect?
- Who can push directly?
- What must a pull request pass before merging?
- Who can merge pull requests?
- Force-push, admins and files
Each collapsed section shows a one-line summary of its settings, such as No direct pushes or Force-push allowlist.
The form saves the same settings as Forgejo’s form, so the repository’s branch_protections API is unchanged.
Arbinel replaces Forgejo’s two stale approval checkboxes with one choice under When new commits change a pull request:
| Choice | Effect |
|---|---|
| Keep earlier approvals | Approvals given before the new commits still count. |
| Stop counting earlier approvals | Earlier approvals stay visible but no longer count towards the required number. |
| Dismiss earlier approvals | Earlier approvals are dismissed, and reviewers must approve again. |
Under Require status checks to pass, the form lists the status checks that the repository reported in the last week. Select one to add it as a pattern. Arbinel escapes glob characters in the check name, so it matches only that check.
Presets
Section titled “Presets”The form for a new rule starts with Start from a preset. A preset fills in the form, and you can change any field before saving.
| Preset | Direct pushes | Approvals | Earlier approvals | Status checks | Other settings |
|---|---|---|---|---|---|
| Pull requests only | Nobody | 0 | Kept | Off | None |
| Reviewed and tested | Nobody | 1 | Dismissed | Required | Blocked on requested changes |
| Strict | Nobody | 2 | Dismissed | Required | Signed commits, up to date with the base branch, blocked on requested changes and on pending official reviews, enforced for repository admins |
All three presets turn off the merge and force-push allowlists.
A preset that requires status checks enters * as the pattern when the field is empty, so every check that the repository reports must pass.
Replace it with the checks you need.
Presets leave out settings that would block every merge:
- A preset leaves status checks off when the repository reported none in the last week.
- Strict leaves signed commits off when the instance has no key to sign merges with. With direct pushes also off, no commit could reach the branch. Commit signing explains how an admin sets up that key.
Live preview
Section titled “Live preview”While you type a pattern, the form shows which existing branches the rule would protect. It also lists branches that the pattern matches but an earlier rule protects instead, with the name of that rule. Each list shows up to 20 branches and the total count.
The preview applies the order from Rule order. It considers only the repository’s own rules, not the organization’s rules.
The rule list on Settings > Branches shows the same count for each saved rule.
Force-push
Section titled “Force-push”Forgejo rejects every force-push to a protected branch. Arbinel adds a choice under Force-push, admins and files:
- Nobody can force-push is the default and matches Forgejo’s behaviour. It applies to repository admins too.
- Only selected users and teams lets the listed users and teams force-push. Repository admins can force-push too, unless Enforce this rule for repository admins is on.
A force-push is still a push, so the user also needs push access under Who can push directly?. Nobody can delete a protected branch.
When Arbinel allows a force-push through this setting, Git prints a note in the push output, for example:
The note ends with (admin override) when a repository admin force-pushed.
The API fields are enable_force_push_allowlist, force_push_allowlist_usernames and force_push_allowlist_teams on the repository’s branch_protections endpoints.
Organization rules
Section titled “Organization rules”Organization owners can set branch protection rules that cover every repository of the organization, including repositories created later. These rules do not apply to repositories owned by a user.
Set up an organization rule
Section titled “Set up an organization rule”- Open the organization’s Settings > Branch protection.
- Select Add new rule.
- Fill in the same form as for a repository rule.
- Under How does this rule apply to repositories?, select Default or Enforced.
- Optionally, select repositories under Repositories this rule skips.
- Save the rule.
The organization form has no live preview. Its presets always leave status checks off, because repositories run different checks. Add the checks that every repository runs yourself.
Allowlists accept only members and teams of the organization. When the rule applies to a repository, Arbinel also leaves out teams without access to that repository. It also leaves out users without write access to the repository, or without read access for the approvals list.
After you save or delete a rule, Arbinel checks the affected open pull requests again, as it does after a repository rule changes.
Default and enforced rules
Section titled “Default and enforced rules”| Mode | Behaviour |
|---|---|
| Default | Protects a branch only when no rule of the repository matches it. Repository admins can replace it. |
| Enforced | Always protects the branch. A repository rule for the same branch can add requirements but cannot remove any. |
Repository admins see the organization’s rules under Rules from the organization on the repository’s Settings > Branches page, with the number of branches that each rule protects. A default rule has a Replace with a repository rule button, which opens a new repository rule filled in from the organization rule.
Precedence
Section titled “Precedence”For a branch of an organization repository, Arbinel looks for a rule in this order:
- The first matching enforced organization rule. If a repository rule also matches, Arbinel combines the two.
- Otherwise, the first matching repository rule.
- Otherwise, the first matching default organization rule.
Within each group, the order from Rule order determines which rule is first. Arbinel uses only one enforced rule and one repository rule, even if more of them match.
When an enforced rule and a repository rule are combined, Arbinel uses the stricter setting:
| Setting | Combined result |
|---|---|
| Required approvals | The higher number. |
| Status checks | Required when either rule requires them, with the patterns of both. |
| Blocks, stale approvals, signed commits, enforcement for admins | On when either rule turns it on. |
| Protected file patterns | The patterns of both rules. |
| Who can push | The organization rule’s choice, unless it lets everyone with write access push. Then the repository rule decides. Pushes are off when either rule turns them off. |
| Who can merge, whose approvals count | The organization rule’s allowlist when it has one, otherwise the repository rule’s. |
| Force-push | Allowed only when both rules allow it, to the organization rule’s list. |
Organization owners and site admins manage the rules through these endpoints.
These endpoints require a token with the organization scope.
| Method | Path | Result |
|---|---|---|
GET |
/api/v1/orgs/{org}/branch_protections |
The organization’s rules, in the order they apply. |
POST |
/api/v1/orgs/{org}/branch_protections |
Creates a rule. Returns 201. |
GET |
/api/v1/orgs/{org}/branch_protections/{name} |
One rule, by its pattern. |
PATCH |
/api/v1/orgs/{org}/branch_protections/{name} |
Changes only the fields you send. |
DELETE |
/api/v1/orgs/{org}/branch_protections/{name} |
Deletes the rule. Returns 204. |
The request body takes the fields of the repository endpoint’s CreateBranchProtectionOption or EditBranchProtectionOption, plus two more:
enforced:truefor an enforced rule,falsefor a default rule.excluded_repos: names of the organization’s repositories the rule skips. Leave it out of aPATCHto keep the current list.
rule_name is required when creating a rule.
A rule name that already exists returns 409.
An unknown user, team or repository name, or a status check pattern that is not a valid glob, returns 422.
The full schema is in the API reference at /api/swagger on your instance.
Differences from Forgejo
Section titled “Differences from Forgejo”- Forgejo shows one long form without presets or a preview.
- Forgejo always rejects a force-push to a protected branch.
- Forgejo has no organization-wide rules.
- Rule matching and ordering within a repository are the same as in Forgejo.