docs(readme): document merge requests, web sign-in and the signing key
- commit
- 7586fbd9d4ca4dbd6ce176002db9321591d12729
- author
- brice · · 2026-10-10 19:36 UTC
- parent
- 41cf2ec
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +18 -2
M README.md +18 -2
| @@ -1,8 +1,8 @@ | |||
| 1 | 1 | # ermite | |
| 2 | 2 | ||
| 3 | - | A single-user Git forge in one Go binary. ermite hosts bare repositories, serves clone and push over HTTPS, and shows them in a read-only web interface. | |
| 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. | |
| 4 | 4 | ||
| 5 | - | Status: early development. `ermite serve` serves Git over HTTP (clone, fetch, push), answers `GET /-/health`, and serves the read-only web: the home list, the summary of a repository (README, clone URL, facts, recent commits) and its refs. Tree, file, commit and live pages are still to come. | |
| 5 | + | Status: early development. `ermite serve` serves Git over HTTP (clone, fetch, push), the API, `GET /-/health`, and the web: repositories, tree, 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. | |
| 6 | 6 | ||
| 7 | 7 | ## Run | |
| 8 | 8 | ||
| @@ -24,6 +24,8 @@ ermite serve | |||
| 24 | 24 | | `ERMITE_SOURCE_URL` | `$ERMITE_PUBLIC_URL/ermite` | link to the source (AGPL) | | |
| 25 | 25 | | `ERMITE_LOG_LEVEL` | `info` | `trace`, `debug`, `info`, `warn`, `error` | | |
| 26 | 26 | | `ERMITE_LOG_FORMAT` | `json` | `json` or `console` | | |
| 27 | + | | `ERMITE_COMMITTER_NAME` | `ermite` | committer of squash merges | | |
| 28 | + | | `ERMITE_COMMITTER_EMAIL` | `ermite@<public host>` | committer email of squash merges | | |
| 27 | 29 | ||
| 28 | 30 | `ermite version` prints the version (and the server's when `ERMITE_URL` is set). | |
| 29 | 31 | ||
| @@ -36,6 +38,12 @@ export ERMITE_URL=https://git.example.com ERMITE_TOKEN=ermite_... | |||
| 36 | 38 | ermite repo list | show <name> | create <name> [--description …] [--visibility public] | edit <name> [--description …] [--visibility …] [--default-branch …] | delete <name> [--yes] | |
| 37 | 39 | ermite token create <label> [--preset cli|agent|ci] [--scope repo:read …] [--repo name …] [--expires 30d] # prints the secret once | |
| 38 | 40 | ermite token list | revoke <id> | |
| 41 | + | ermite mr create <repo> --source <branch> --title … | list <repo> | show <repo> <n> [--diff] | |
| 42 | + | ermite mr comment <repo> <n> -m … [--path … --line … --side old|new] | resolve <repo> <n> <comment> | |
| 43 | + | ermite mr merge <repo> <n> --head <id> [--squash] | close <repo> <n> | |
| 44 | + | ermite web login # prints a one-time sign-in link (60 s) | |
| 45 | + | ermite web logout --all # signs every browser out | |
| 46 | + | ermite signing-key show # public key and allowed_signers line of squash commits | |
| 39 | 47 | ermite version # client and server, warns about missing server features | |
| 40 | 48 | ermite watch [repo] [--json] # follows events, reconnects and resumes | |
| 41 | 49 | ``` | |
| @@ -51,6 +59,14 @@ git push http://u:<token>@git.example.com/<repo>.git main | |||
| 51 | 59 | ||
| 52 | 60 | Use the admin token (`ERMITE_ADMIN_TOKEN`) or a stored token as the password; the username is ignored. Store it in a Git credential helper rather than in the URL. Pushing to a new name creates a private repository. Repository names are lowercase, `[a-z0-9._-]`. TLS is terminated by your proxy; list its network in `ERMITE_TRUSTED_PROXIES` so that failed-login limits see the real client address (`X-Forwarded-For`). | |
| 53 | 61 | ||
| 62 | + | ## Merge requests | |
| 63 | + | ||
| 64 | + | A merge request proposes a branch for its target (the default branch unless set). The merge is refused when the branch moved since the reviewed head (`--head`) or when the target is not an ancestor of it. Fast-forward moves the target; squash writes one commit signed by the server's SSH key (`ermite signing-key show` prints the `allowed_signers` line for `git verify-commit`). `ermite repo edit --merge-modes` limits the modes per repository. Tokens need `mr:write` to open and comment, and `mr:merge` to merge. | |
| 65 | + | ||
| 66 | + | ## Web sign-in | |
| 67 | + | ||
| 68 | + | `ermite web login`, run with the admin token or a token with every scope, prints a link that works once within 60 seconds. Opening it and confirming sets a session cookie for 12 hours (never longer than the token that asked for the link). It needs `https` in `ERMITE_PUBLIC_URL` (except on localhost). Browser writes require the session and an `Origin` equal to `ERMITE_PUBLIC_URL`. `ermite web logout --all`, or revoking a token with every scope, ends every session. | |
| 69 | + | ||
| 54 | 70 | The server keeps its runtime files in `$ERMITE_DATA_DIR/run/` (the hook socket and scripts that git calls on each push); the hook socket path must stay under about 100 bytes. | |
| 55 | 71 | ||
| 56 | 72 | ## Run with Docker | |
| @@ -1,8 +1,8 @@ | |||||
| 1 | # ermite | 1 | # ermite | ||
| 2 | 2 | ||||
| 3 | - | A single-user Git forge in one Go binary. ermite hosts bare repositories, serves clone and push over HTTPS, and shows them in a read-only web interface. | 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. |
| 4 | 4 | ||||
| 5 | - | Status: early development. `ermite serve` serves Git over HTTP (clone, fetch, push), answers `GET /-/health`, and serves the read-only web: the home list, the summary of a repository (README, clone URL, facts, recent commits) and its refs. Tree, file, commit and live pages are still to come. | 5 | + | Status: early development. `ermite serve` serves Git over HTTP (clone, fetch, push), the API, `GET /-/health`, and the web: repositories, tree, 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. |
| 6 | 6 | ||||
| 7 | ## Run | 7 | ## Run | ||
| 8 | 8 | ||||
| @@ -24,6 +24,8 @@ ermite serve | |||||
| 24 | | `ERMITE_SOURCE_URL` | `$ERMITE_PUBLIC_URL/ermite` | link to the source (AGPL) | | 24 | | `ERMITE_SOURCE_URL` | `$ERMITE_PUBLIC_URL/ermite` | link to the source (AGPL) | | ||
| 25 | | `ERMITE_LOG_LEVEL` | `info` | `trace`, `debug`, `info`, `warn`, `error` | | 25 | | `ERMITE_LOG_LEVEL` | `info` | `trace`, `debug`, `info`, `warn`, `error` | | ||
| 26 | | `ERMITE_LOG_FORMAT` | `json` | `json` or `console` | | 26 | | `ERMITE_LOG_FORMAT` | `json` | `json` or `console` | | ||
| 27 | + | | `ERMITE_COMMITTER_NAME` | `ermite` | committer of squash merges | | |||
| 28 | + | | `ERMITE_COMMITTER_EMAIL` | `ermite@<public host>` | committer email of squash merges | | |||
| 27 | 29 | ||||
| 28 | `ermite version` prints the version (and the server's when `ERMITE_URL` is set). | 30 | `ermite version` prints the version (and the server's when `ERMITE_URL` is set). | ||
| 29 | 31 | ||||
| @@ -36,6 +38,12 @@ export ERMITE_URL=https://git.example.com ERMITE_TOKEN=ermite_... | |||||
| 36 | ermite repo list | show <name> | create <name> [--description …] [--visibility public] | edit <name> [--description …] [--visibility …] [--default-branch …] | delete <name> [--yes] | 38 | ermite repo list | show <name> | create <name> [--description …] [--visibility public] | edit <name> [--description …] [--visibility …] [--default-branch …] | delete <name> [--yes] | ||
| 37 | ermite token create <label> [--preset cli|agent|ci] [--scope repo:read …] [--repo name …] [--expires 30d] # prints the secret once | 39 | ermite token create <label> [--preset cli|agent|ci] [--scope repo:read …] [--repo name …] [--expires 30d] # prints the secret once | ||
| 38 | ermite token list | revoke <id> | 40 | ermite token list | revoke <id> | ||
| 41 | + | ermite mr create <repo> --source <branch> --title … | list <repo> | show <repo> <n> [--diff] | |||
| 42 | + | ermite mr comment <repo> <n> -m … [--path … --line … --side old|new] | resolve <repo> <n> <comment> | |||
| 43 | + | ermite mr merge <repo> <n> --head <id> [--squash] | close <repo> <n> | |||
| 44 | + | ermite web login # prints a one-time sign-in link (60 s) | |||
| 45 | + | ermite web logout --all # signs every browser out | |||
| 46 | + | ermite signing-key show # public key and allowed_signers line of squash commits | |||
| 39 | ermite version # client and server, warns about missing server features | 47 | ermite version # client and server, warns about missing server features | ||
| 40 | ermite watch [repo] [--json] # follows events, reconnects and resumes | 48 | ermite watch [repo] [--json] # follows events, reconnects and resumes | ||
| 41 | ``` | 49 | ``` | ||
| @@ -51,6 +59,14 @@ git push http://u:<token>@git.example.com/<repo>.git main | |||||
| 51 | 59 | ||||
| 52 | Use the admin token (`ERMITE_ADMIN_TOKEN`) or a stored token as the password; the username is ignored. Store it in a Git credential helper rather than in the URL. Pushing to a new name creates a private repository. Repository names are lowercase, `[a-z0-9._-]`. TLS is terminated by your proxy; list its network in `ERMITE_TRUSTED_PROXIES` so that failed-login limits see the real client address (`X-Forwarded-For`). | 60 | Use the admin token (`ERMITE_ADMIN_TOKEN`) or a stored token as the password; the username is ignored. Store it in a Git credential helper rather than in the URL. Pushing to a new name creates a private repository. Repository names are lowercase, `[a-z0-9._-]`. TLS is terminated by your proxy; list its network in `ERMITE_TRUSTED_PROXIES` so that failed-login limits see the real client address (`X-Forwarded-For`). | ||
| 53 | 61 | ||||
| 62 | + | ## Merge requests | |||
| 63 | + | ||||
| 64 | + | A merge request proposes a branch for its target (the default branch unless set). The merge is refused when the branch moved since the reviewed head (`--head`) or when the target is not an ancestor of it. Fast-forward moves the target; squash writes one commit signed by the server's SSH key (`ermite signing-key show` prints the `allowed_signers` line for `git verify-commit`). `ermite repo edit --merge-modes` limits the modes per repository. Tokens need `mr:write` to open and comment, and `mr:merge` to merge. | |||
| 65 | + | ||||
| 66 | + | ## Web sign-in | |||
| 67 | + | ||||
| 68 | + | `ermite web login`, run with the admin token or a token with every scope, prints a link that works once within 60 seconds. Opening it and confirming sets a session cookie for 12 hours (never longer than the token that asked for the link). It needs `https` in `ERMITE_PUBLIC_URL` (except on localhost). Browser writes require the session and an `Origin` equal to `ERMITE_PUBLIC_URL`. `ermite web logout --all`, or revoking a token with every scope, ends every session. | |||
| 69 | + | ||||
| 54 | The server keeps its runtime files in `$ERMITE_DATA_DIR/run/` (the hook socket and scripts that git calls on each push); the hook socket path must stay under about 100 bytes. | 70 | The server keeps its runtime files in `$ERMITE_DATA_DIR/run/` (the hook socket and scripts that git calls on each push); the hook socket path must stay under about 100 bytes. | ||
| 55 | 71 | ||||
| 56 | ## Run with Docker | 72 | ## Run with Docker | ||