detached 66bbda9

docs(readme): point links to the public mirror and drop private infrastructure details (#68)

commit
66bbda9e06b4bf4f5b19fa846fff3ba4f52462ac
author
brice · · 2026-10-18 15:13 UTC
committer
bnema · · 2026-10-18 15:13 UTC
parent
4492065
signature
SSH UnverifiedSHA256:VOCA5lYARHcbKDZ7GhTV45VmcjWnJ6ZQIBazj17LivA The key is unknown
5 files · +16 -19
M .forgejo/workflows/ci.yml +5 -8
@@ -16,8 +16,7 @@ jobs:
1616 runs-on: ubuntu-latest
1717 steps:
1818 - uses: actions/checkout@v6
19- # Job containers reach Forgejo through the Gordon edge on the host loopback,
20- # in plain HTTP on :8088 (see vps-infra homelab/igor/ci-runner).
19+ # Job containers reach the forge over plain HTTP on the host loopback.
2120 - name: Fetch bnema.dev/ermite* modules through the runner's Forgejo route
2221 run: git config --global url."http://git.bnema.dev:8088/".insteadOf "https://git.bnema.dev/"
2322 - uses: actions/setup-go@v5
@@ -40,8 +39,7 @@ jobs:
4039 - name: System packages
4140 run: pacman -Syu --noconfirm --needed git gcc openssh nodejs
4241 - uses: actions/checkout@v6
43- # Job containers reach Forgejo through the Gordon edge on the host loopback,
44- # in plain HTTP on :8088 (see vps-infra homelab/igor/ci-runner).
42+ # Job containers reach the forge over plain HTTP on the host loopback.
4543 - name: Fetch bnema.dev/ermite* modules through the runner's Forgejo route
4644 run: git config --global url."http://git.bnema.dev:8088/".insteadOf "https://git.bnema.dev/"
4745 - uses: actions/setup-go@v5
@@ -86,8 +84,7 @@ jobs:
8684 with:
8785 # buf breaking compares with the base branch.
8886 fetch-depth: 0
89- # Job containers reach Forgejo through the Gordon edge on the host loopback,
90- # in plain HTTP on :8088 (see vps-infra homelab/igor/ci-runner).
87+ # Job containers reach the forge over plain HTTP on the host loopback.
9188 - name: Fetch bnema.dev/ermite* modules through the runner's Forgejo route
9289 run: git config --global url."http://git.bnema.dev:8088/".insteadOf "https://git.bnema.dev/"
9390 - uses: actions/setup-go@v5
@@ -124,8 +121,8 @@ jobs:
124121 # git describe needs the tags for the image version.
125122 fetch-depth: 0
126123 # The build runs in Podman on the runner host. With the host network it resolves
127- # git.bnema.dev through the host's /etc/hosts (127.0.0.1, see vps-infra
128- # homelab/igor/ci-runner) and reaches Forgejo on :8088. Podman's Docker API rejects
124+ # the forge through the host's /etc/hosts (loopback) and reaches it over plain HTTP.
125+ # Podman's Docker API rejects
129126 # the classic builder's --add-host encoding, so host networking is used instead.
130127 # Acceptable because only trusted branches of this repo trigger CI (no fork PRs).
131128 - name: Build the image
@@ -16,8 +16,7 @@ jobs:
16 runs-on: ubuntu-latest16 runs-on: ubuntu-latest
17 steps:17 steps:
18 - uses: actions/checkout@v618 - uses: actions/checkout@v6
19- # Job containers reach Forgejo through the Gordon edge on the host loopback,19+ # Job containers reach the forge over plain HTTP on the host loopback.
20- # in plain HTTP on :8088 (see vps-infra homelab/igor/ci-runner).
21 - name: Fetch bnema.dev/ermite* modules through the runner's Forgejo route20 - name: Fetch bnema.dev/ermite* modules through the runner's Forgejo route
22 run: git config --global url."http://git.bnema.dev:8088/".insteadOf "https://git.bnema.dev/"21 run: git config --global url."http://git.bnema.dev:8088/".insteadOf "https://git.bnema.dev/"
23 - uses: actions/setup-go@v522 - uses: actions/setup-go@v5
@@ -40,8 +39,7 @@ jobs:
40 - name: System packages39 - name: System packages
41 run: pacman -Syu --noconfirm --needed git gcc openssh nodejs40 run: pacman -Syu --noconfirm --needed git gcc openssh nodejs
42 - uses: actions/checkout@v641 - uses: actions/checkout@v6
43- # Job containers reach Forgejo through the Gordon edge on the host loopback,42+ # Job containers reach the forge over plain HTTP on the host loopback.
44- # in plain HTTP on :8088 (see vps-infra homelab/igor/ci-runner).
45 - name: Fetch bnema.dev/ermite* modules through the runner's Forgejo route43 - name: Fetch bnema.dev/ermite* modules through the runner's Forgejo route
46 run: git config --global url."http://git.bnema.dev:8088/".insteadOf "https://git.bnema.dev/"44 run: git config --global url."http://git.bnema.dev:8088/".insteadOf "https://git.bnema.dev/"
47 - uses: actions/setup-go@v545 - uses: actions/setup-go@v5
@@ -86,8 +84,7 @@ jobs:
86 with:84 with:
87 # buf breaking compares with the base branch.85 # buf breaking compares with the base branch.
88 fetch-depth: 086 fetch-depth: 0
89- # Job containers reach Forgejo through the Gordon edge on the host loopback,87+ # Job containers reach the forge over plain HTTP on the host loopback.
90- # in plain HTTP on :8088 (see vps-infra homelab/igor/ci-runner).
91 - name: Fetch bnema.dev/ermite* modules through the runner's Forgejo route88 - name: Fetch bnema.dev/ermite* modules through the runner's Forgejo route
92 run: git config --global url."http://git.bnema.dev:8088/".insteadOf "https://git.bnema.dev/"89 run: git config --global url."http://git.bnema.dev:8088/".insteadOf "https://git.bnema.dev/"
93 - uses: actions/setup-go@v590 - uses: actions/setup-go@v5
@@ -124,8 +121,8 @@ jobs:
124 # git describe needs the tags for the image version.121 # git describe needs the tags for the image version.
125 fetch-depth: 0122 fetch-depth: 0
126 # The build runs in Podman on the runner host. With the host network it resolves123 # The build runs in Podman on the runner host. With the host network it resolves
127- # git.bnema.dev through the host's /etc/hosts (127.0.0.1, see vps-infra124+ # the forge through the host's /etc/hosts (loopback) and reaches it over plain HTTP.
128- # homelab/igor/ci-runner) and reaches Forgejo on :8088. Podman's Docker API rejects125+ # Podman's Docker API rejects
129 # the classic builder's --add-host encoding, so host networking is used instead.126 # the classic builder's --add-host encoding, so host networking is used instead.
130 # Acceptable because only trusted branches of this repo trigger CI (no fork PRs).127 # Acceptable because only trusted branches of this repo trigger CI (no fork PRs).
131 - name: Build the image128 - name: Build the image
M Dockerfile +3 -5
@@ -4,11 +4,9 @@
44 #
55 # docker build --build-arg VERSION="$(git describe --tags --always --dirty)" -t ermite .
66 #
7-# The modules bnema.dev/ermite-* are private and resolve through git.bnema.dev, which is
8-# reachable from the NetBird network only. The build container uses the host's DNS and
9-# routes, so on a NetBird host it needs nothing more. Behind a different route (CI), set
10-# --build-arg GIT_REWRITE_BASE=http://git.bnema.dev:8088/ --network host
11-# to fetch the modules over that URL instead of https://git.bnema.dev/.
7+# The modules bnema.dev/ermite-* resolve through the bnema.dev vanity path.
8+# GIT_REWRITE_BASE optionally rewrites the git host for builds behind a private route:
9+# --build-arg GIT_REWRITE_BASE=<url> --network host
1210 #
1311 # Base images are pinned to an Alpine minor release; bump them on purpose.
1412
@@ -4,11 +4,9 @@
4 #4 #
5 # docker build --build-arg VERSION="$(git describe --tags --always --dirty)" -t ermite .5 # docker build --build-arg VERSION="$(git describe --tags --always --dirty)" -t ermite .
6 #6 #
7-# The modules bnema.dev/ermite-* are private and resolve through git.bnema.dev, which is7+# The modules bnema.dev/ermite-* resolve through the bnema.dev vanity path.
8-# reachable from the NetBird network only. The build container uses the host's DNS and8+# GIT_REWRITE_BASE optionally rewrites the git host for builds behind a private route:
9-# routes, so on a NetBird host it needs nothing more. Behind a different route (CI), set9+# --build-arg GIT_REWRITE_BASE=<url> --network host
10-# --build-arg GIT_REWRITE_BASE=http://git.bnema.dev:8088/ --network host
11-# to fetch the modules over that URL instead of https://git.bnema.dev/.
12 #10 #
13 # Base images are pinned to an Alpine minor release; bump them on purpose.11 # Base images are pinned to an Alpine minor release; bump them on purpose.
14 12
M README.md +6 -4
@@ -1,5 +1,7 @@
11 # ermite
22
3+> Read-only mirror. Development happens at git.bnema.dev; issues and pull requests are closed here.
4+
35 A single-user Git forge in one Go binary. ermite hosts bare repositories, serves clone and push over HTTPS, reviews branches as merge requests, and shows everything in a web interface with live updates.
46
57 Status: early development. `ermite serve` serves Git over HTTP (clone, fetch, push), the API, `GET /-/health`, and the web: repositories, an expandable file tree with a repository-wide fuzzy file finder, files, commits, refs and merge requests. Visitors read public repositories; the owner signs in with a one-time link from the CLI to see private ones and to review and merge.
@@ -21,7 +23,7 @@ ermite serve
2123 | `ERMITE_ADDR` | `:7341` | listen address |
2224 | `ERMITE_TRUSTED_PROXIES` | empty | comma-separated CIDRs |
2325 | `ERMITE_GIT` | `git` | git 2.45 or newer |
24-| `ERMITE_GIT_READER` | `ermite-git` | `ermite-git` reads refs, trees, blobs and history with the [ermite-git](https://git.bnema.dev/bnema/ermite-git) library where it is faster than the `git` binary and falls back to `git` elsewhere and for repositories it does not read; `cli` uses the `git` binary for every read (the escape hatch if a read looks wrong: set it and restart) |
26+| `ERMITE_GIT_READER` | `ermite-git` | `ermite-git` reads refs, trees, blobs and history with the [ermite-git](https://github.com/bnema/ermite-git) library where it is faster than the `git` binary and falls back to `git` elsewhere and for repositories it does not read; `cli` uses the `git` binary for every read (the escape hatch if a read looks wrong: set it and restart) |
2527 | `ERMITE_SOURCE_URL` | `$ERMITE_PUBLIC_URL/ermite` | link to the source (AGPL) |
2628 | `ERMITE_LOG_LEVEL` | `info` | `trace`, `debug`, `info`, `warn`, `error` |
2729 | `ERMITE_LOG_FORMAT` | `json` | `json` or `console` |
@@ -34,7 +36,7 @@ ermite serve
3436 | `ERMITE_CI_ARTIFACT_RETENTION` | `90d` | default and longest retention of an artifact (`retention-days`), at least one day: `Nd` or a Go duration |
3537 | `ERMITE_CI_ARTIFACT_QUOTA` | `10GiB` | space of the artifacts of one repository, uploads in progress included: bytes, or a number with `KiB`, `MiB`, `GiB`, `TiB` |
3638 | `ERMITE_CI_ARTIFACT_MAX` | `5GiB` | size of one artifact, same syntax |
37-| `ERMITE_CI_POLL_TIMEOUT` | `50s` | how long the server holds a runner's `FetchJob` call when no job is queued, from `1s` to `55s`; set it below the response timeout of a reverse proxy in front of ermite (Gordon cuts a response that has no headers after 30 s, so use `25s` behind it) |
39+| `ERMITE_CI_POLL_TIMEOUT` | `50s` | how long the server holds a runner's `FetchJob` call when no job is queued, from `1s` to `55s`; set it below the response timeout of a reverse proxy in front of ermite (a reverse proxy may cut a response that has no headers after 30 s, so use `25s` behind such a proxy) |
3840
3941 `ermite version` prints the version (and the server's when a server URL is configured, see Remote CLI).
4042
@@ -122,7 +124,7 @@ A merge request proposes a branch for its target (the default branch unless set)
122124
123125 ermite runs the `.github/workflows/*.yml` workflows of a repository on `push` (a branch or a tag, and the merge of a merge request), on `pull_request` and `pull_request_target` (the merge requests, below), `workflow_dispatch`, `schedule`, `workflow_run`, `create` and `delete` (below) and shows each job as a check on the commit, the branch list and the merge request. CI is on once a runner is registered; there is no switch. Before that a push makes no run and no check.
124126
125-Runs execute on [ermite-runner](https://git.bnema.dev/bnema/ermite-runner) hosts, which call ermite over its API. Create a token for the runner host with `ermite token create <label> --preset runner` (the `runner:register` scope, which also gives access to the code and the secrets of every repository: give it only to runners you operate), then register the runner with it. `ermite runner list` shows the runners and whether they are online; `ermite runner remove <id>` stops one. A job goes to a runner that has every label of its `runs-on`; a job no runner takes within 24 hours fails.
127+Runs execute on [ermite-runner](https://github.com/bnema/ermite-runner) hosts, which call ermite over its API. Create a token for the runner host with `ermite token create <label> --preset runner` (the `runner:register` scope, which also gives access to the code and the secrets of every repository: give it only to runners you operate), then register the runner with it. `ermite runner list` shows the runners and whether they are online; `ermite runner remove <id>` stops one. A job goes to a runner that has every label of its `runs-on`; a job no runner takes within 24 hours fails.
126128
127129 Every job gets a **repository token** (`github.token`, `ermitegh_…`) when a runner takes it: it reads the repository of the run, even a private one, over Git and the REST subset below, writes nothing, and ends with the job (completion, cancel, lost runner) or five minutes after the job's deadline. It is not a stored token: `ermite token list` never shows it and no scope manages it.
128130
@@ -185,7 +187,7 @@ docker run -d -p 127.0.0.1:7341:7341 -v ermite-data:/data \
185187 -e ERMITE_PUBLIC_URL=http://localhost:7341 -e ERMITE_ADMIN_TOKEN="$token" ermite
186188 ```
187189
188-The image is alpine with git, runs as uid 10001 and keeps its data in the `/data` volume. Logs are JSON by default. The build fetches `bnema.dev/ermite-*` from `git.bnema.dev`, so the host must reach it (NetBird); the build container uses the host's DNS and routes. Behind another route, pass `--build-arg GIT_REWRITE_BASE=http://git.bnema.dev:8088/` with `--network host`, as the CI job does.
190+The image is alpine with git, runs as uid 10001 and keeps its data in the `/data` volume. Logs are JSON by default. The build fetches the `bnema.dev/ermite-*` modules through their `bnema.dev` vanity paths. Behind a private route, `--build-arg GIT_REWRITE_BASE=<url>` rewrites the git host used for those modules.
189191
190192 ## Develop with compose
191193
@@ -1,5 +1,7 @@
1 # ermite1 # ermite
2 2
3+> Read-only mirror. Development happens at git.bnema.dev; issues and pull requests are closed here.
4+
3 A single-user Git forge in one Go binary. ermite hosts bare repositories, serves clone and push over HTTPS, reviews branches as merge requests, and shows everything in a web interface with live updates.5 A single-user Git forge in one Go binary. ermite hosts bare repositories, serves clone and push over HTTPS, reviews branches as merge requests, and shows everything in a web interface with live updates.
4 6
5 Status: early development. `ermite serve` serves Git over HTTP (clone, fetch, push), the API, `GET /-/health`, and the web: repositories, an expandable file tree with a repository-wide fuzzy file finder, files, commits, refs and merge requests. Visitors read public repositories; the owner signs in with a one-time link from the CLI to see private ones and to review and merge.7 Status: early development. `ermite serve` serves Git over HTTP (clone, fetch, push), the API, `GET /-/health`, and the web: repositories, an expandable file tree with a repository-wide fuzzy file finder, files, commits, refs and merge requests. Visitors read public repositories; the owner signs in with a one-time link from the CLI to see private ones and to review and merge.
@@ -21,7 +23,7 @@ ermite serve
21 | `ERMITE_ADDR` | `:7341` | listen address |23 | `ERMITE_ADDR` | `:7341` | listen address |
22 | `ERMITE_TRUSTED_PROXIES` | empty | comma-separated CIDRs |24 | `ERMITE_TRUSTED_PROXIES` | empty | comma-separated CIDRs |
23 | `ERMITE_GIT` | `git` | git 2.45 or newer |25 | `ERMITE_GIT` | `git` | git 2.45 or newer |
24-| `ERMITE_GIT_READER` | `ermite-git` | `ermite-git` reads refs, trees, blobs and history with the [ermite-git](https://git.bnema.dev/bnema/ermite-git) library where it is faster than the `git` binary and falls back to `git` elsewhere and for repositories it does not read; `cli` uses the `git` binary for every read (the escape hatch if a read looks wrong: set it and restart) |26+| `ERMITE_GIT_READER` | `ermite-git` | `ermite-git` reads refs, trees, blobs and history with the [ermite-git](https://github.com/bnema/ermite-git) library where it is faster than the `git` binary and falls back to `git` elsewhere and for repositories it does not read; `cli` uses the `git` binary for every read (the escape hatch if a read looks wrong: set it and restart) |
25 | `ERMITE_SOURCE_URL` | `$ERMITE_PUBLIC_URL/ermite` | link to the source (AGPL) |27 | `ERMITE_SOURCE_URL` | `$ERMITE_PUBLIC_URL/ermite` | link to the source (AGPL) |
26 | `ERMITE_LOG_LEVEL` | `info` | `trace`, `debug`, `info`, `warn`, `error` |28 | `ERMITE_LOG_LEVEL` | `info` | `trace`, `debug`, `info`, `warn`, `error` |
27 | `ERMITE_LOG_FORMAT` | `json` | `json` or `console` |29 | `ERMITE_LOG_FORMAT` | `json` | `json` or `console` |
@@ -34,7 +36,7 @@ ermite serve
34 | `ERMITE_CI_ARTIFACT_RETENTION` | `90d` | default and longest retention of an artifact (`retention-days`), at least one day: `Nd` or a Go duration |36 | `ERMITE_CI_ARTIFACT_RETENTION` | `90d` | default and longest retention of an artifact (`retention-days`), at least one day: `Nd` or a Go duration |
35 | `ERMITE_CI_ARTIFACT_QUOTA` | `10GiB` | space of the artifacts of one repository, uploads in progress included: bytes, or a number with `KiB`, `MiB`, `GiB`, `TiB` |37 | `ERMITE_CI_ARTIFACT_QUOTA` | `10GiB` | space of the artifacts of one repository, uploads in progress included: bytes, or a number with `KiB`, `MiB`, `GiB`, `TiB` |
36 | `ERMITE_CI_ARTIFACT_MAX` | `5GiB` | size of one artifact, same syntax |38 | `ERMITE_CI_ARTIFACT_MAX` | `5GiB` | size of one artifact, same syntax |
37-| `ERMITE_CI_POLL_TIMEOUT` | `50s` | how long the server holds a runner's `FetchJob` call when no job is queued, from `1s` to `55s`; set it below the response timeout of a reverse proxy in front of ermite (Gordon cuts a response that has no headers after 30 s, so use `25s` behind it) |39+| `ERMITE_CI_POLL_TIMEOUT` | `50s` | how long the server holds a runner's `FetchJob` call when no job is queued, from `1s` to `55s`; set it below the response timeout of a reverse proxy in front of ermite (a reverse proxy may cut a response that has no headers after 30 s, so use `25s` behind such a proxy) |
38 40
39 `ermite version` prints the version (and the server's when a server URL is configured, see Remote CLI).41 `ermite version` prints the version (and the server's when a server URL is configured, see Remote CLI).
40 42
@@ -122,7 +124,7 @@ A merge request proposes a branch for its target (the default branch unless set)
122 124
123 ermite runs the `.github/workflows/*.yml` workflows of a repository on `push` (a branch or a tag, and the merge of a merge request), on `pull_request` and `pull_request_target` (the merge requests, below), `workflow_dispatch`, `schedule`, `workflow_run`, `create` and `delete` (below) and shows each job as a check on the commit, the branch list and the merge request. CI is on once a runner is registered; there is no switch. Before that a push makes no run and no check.125 ermite runs the `.github/workflows/*.yml` workflows of a repository on `push` (a branch or a tag, and the merge of a merge request), on `pull_request` and `pull_request_target` (the merge requests, below), `workflow_dispatch`, `schedule`, `workflow_run`, `create` and `delete` (below) and shows each job as a check on the commit, the branch list and the merge request. CI is on once a runner is registered; there is no switch. Before that a push makes no run and no check.
124 126
125-Runs execute on [ermite-runner](https://git.bnema.dev/bnema/ermite-runner) hosts, which call ermite over its API. Create a token for the runner host with `ermite token create <label> --preset runner` (the `runner:register` scope, which also gives access to the code and the secrets of every repository: give it only to runners you operate), then register the runner with it. `ermite runner list` shows the runners and whether they are online; `ermite runner remove <id>` stops one. A job goes to a runner that has every label of its `runs-on`; a job no runner takes within 24 hours fails.127+Runs execute on [ermite-runner](https://github.com/bnema/ermite-runner) hosts, which call ermite over its API. Create a token for the runner host with `ermite token create <label> --preset runner` (the `runner:register` scope, which also gives access to the code and the secrets of every repository: give it only to runners you operate), then register the runner with it. `ermite runner list` shows the runners and whether they are online; `ermite runner remove <id>` stops one. A job goes to a runner that has every label of its `runs-on`; a job no runner takes within 24 hours fails.
126 128
127 Every job gets a **repository token** (`github.token`, `ermitegh_…`) when a runner takes it: it reads the repository of the run, even a private one, over Git and the REST subset below, writes nothing, and ends with the job (completion, cancel, lost runner) or five minutes after the job's deadline. It is not a stored token: `ermite token list` never shows it and no scope manages it.129 Every job gets a **repository token** (`github.token`, `ermitegh_…`) when a runner takes it: it reads the repository of the run, even a private one, over Git and the REST subset below, writes nothing, and ends with the job (completion, cancel, lost runner) or five minutes after the job's deadline. It is not a stored token: `ermite token list` never shows it and no scope manages it.
128 130
@@ -185,7 +187,7 @@ docker run -d -p 127.0.0.1:7341:7341 -v ermite-data:/data \
185 -e ERMITE_PUBLIC_URL=http://localhost:7341 -e ERMITE_ADMIN_TOKEN="$token" ermite187 -e ERMITE_PUBLIC_URL=http://localhost:7341 -e ERMITE_ADMIN_TOKEN="$token" ermite
186 ```188 ```
187 189
188-The image is alpine with git, runs as uid 10001 and keeps its data in the `/data` volume. Logs are JSON by default. The build fetches `bnema.dev/ermite-*` from `git.bnema.dev`, so the host must reach it (NetBird); the build container uses the host's DNS and routes. Behind another route, pass `--build-arg GIT_REWRITE_BASE=http://git.bnema.dev:8088/` with `--network host`, as the CI job does.190+The image is alpine with git, runs as uid 10001 and keeps its data in the `/data` volume. Logs are JSON by default. The build fetches the `bnema.dev/ermite-*` modules through their `bnema.dev` vanity paths. Behind a private route, `--build-arg GIT_REWRITE_BASE=<url>` rewrites the git host used for those modules.
189 191
190 ## Develop with compose192 ## Develop with compose
191 193
M compose.yaml +1 -1
@@ -1,6 +1,6 @@
11 # Development server with hot reload: `docker compose up`, then http://localhost:7341.
22 # The module is built on its own (no go.work), like CI. Private modules bnema.dev/ermite-*
3-# are fetched from git.bnema.dev, which the container reaches through the host's DNS and routes.
3+# resolve through the bnema.dev vanity path, using the host's DNS and routes.
44 services:
55 ermite:
66 build:
@@ -1,6 +1,6 @@
1 # Development server with hot reload: `docker compose up`, then http://localhost:7341.1 # Development server with hot reload: `docker compose up`, then http://localhost:7341.
2 # The module is built on its own (no go.work), like CI. Private modules bnema.dev/ermite-*2 # The module is built on its own (no go.work), like CI. Private modules bnema.dev/ermite-*
3-# are fetched from git.bnema.dev, which the container reaches through the host's DNS and routes.3+# resolve through the bnema.dev vanity path, using the host's DNS and routes.
4 services:4 services:
5 ermite:5 ermite:
6 build:6 build:
M go.sum +1 -1 generated file: collapsed

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 3

Tags 43

↑↓ moveenter openesc close