fj has no git tag commands and branch support is read-only (list-only), forcing fj api/raw git for ref mutation #121

Open
opened 2026-06-11 00:47:52 +00:00 by stephen · 1 comment
Owner

Observation

fj has no git tag commands at all, and its branch support is read-only. A team scripting releases or branch cleanup against fj must drop to fj api or raw git for every mutation, which is the raw-API fallback the tool exists to remove.

fj repo (src/cli/repo.rs:256-277) exposes branches and nothing else for refs:

$ fj repo --help
  branches     List branches
  topics       Manage repo topics (tags)      # GitHub "topics", NOT git tags
  ...

branches is list-only (src/cli/repo.rs:571, handler just renders a table); there is no branch create, delete, or rename. The API layer confirms the ceiling: the only ref helper in src/api/ is list_branches (src/api/repo_core.rs:246). There is no create_branch, delete_branch, list_tags, create_tag, or delete_tag anywhere:

$ grep -rnE 'fn (create_branch|delete_branch|list_tags|create_tag|delete_tag)' src/api/
(no matches)

Note fj repo topics is unrelated: in Forgejo "topics" are the discovery keywords on a repo, not git tags.

Forgejo serves all of this already: GET/POST/DELETE /repos/{owner}/{repo}/branches, and GET /repos/{owner}/{repo}/tags, GET .../tags/{tag}, POST .../tags, DELETE .../tags/{tag}. So the gap is entirely at the CLI/api-helper layer.

The read-but-not-write shape mirrors the PR-label gap tracked in rasterstate/fj#110: fj repo branches lists refs the CLI then gives you no way to mutate.

Why it matters

Branch and tag mutation is routine scripted-forge work, and it is the one class of forge operation where fj currently has zero coverage:

  • Release cutting: a CI job that tags a release commit (POST .../tags with a target SHA) has to either shell out to git tag && git push (needs a writable checkout and push credentials) or call fj api by hand. fj release create creates an annotated release but a lightweight fj tag create v1.2.3 <sha> has no equivalent.
  • Branch hygiene: "delete every merged feature/* branch" is a common post-merge cleanup. Today it is fj repo branches --json | jq ... | xargs -I{} fj api -X DELETE /repos/o/r/branches/{}, defeating the point of having a CLI.
  • Listing tags for changelog/diff tooling: fj tag list to feed git log <prev>..<this> is a basic building block that simply isn't there; you must fj api /repos/o/r/tags.

fj already covers the heavier, less-frequent ref operations (branch protection via fj protect, releases via fj release), which makes the absence of the lightweight, high-frequency tag/branch verbs more surprising, not less.

Possible directions (sketches)

  • (sketch) fj tag list / fj tag view <tag> / fj tag create <tag> [--target <sha>] [-m <msg>] / fj tag delete <tag> -y, backed by new thin src/api/ helpers over the /repos/{o}/{r}/tags endpoints. Mirror the existing fj milestone / fj label CRUD shape (list/view/create/delete with --json and a typed-confirmation delete).
  • (sketch) Extend fj repo with branch-create <name> [--from <ref>] and branch-delete <name> -y (or a fj branch group), backed by create_branch/delete_branch helpers over /repos/{o}/{r}/branches. The existing list_branches (src/api/repo_core.rs:246) is the read half already.
  • (sketch) Whichever lands, give tag list / branch list --json from the start so they compose into changelog and cleanup pipelines without re-scraping tables (consistent with the --json direction in rasterstate/fj#109).
## Observation `fj` has no git tag commands at all, and its branch support is read-only. A team scripting releases or branch cleanup against `fj` must drop to `fj api` or raw git for every mutation, which is the raw-API fallback the tool exists to remove. `fj repo` (`src/cli/repo.rs:256-277`) exposes `branches` and nothing else for refs: ``` $ fj repo --help branches List branches topics Manage repo topics (tags) # GitHub "topics", NOT git tags ... ``` `branches` is list-only (`src/cli/repo.rs:571`, handler just renders a table); there is no branch create, delete, or rename. The API layer confirms the ceiling: the only ref helper in `src/api/` is `list_branches` (`src/api/repo_core.rs:246`). There is no `create_branch`, `delete_branch`, `list_tags`, `create_tag`, or `delete_tag` anywhere: ``` $ grep -rnE 'fn (create_branch|delete_branch|list_tags|create_tag|delete_tag)' src/api/ (no matches) ``` Note `fj repo topics` is unrelated: in Forgejo "topics" are the discovery keywords on a repo, not git tags. Forgejo serves all of this already: `GET/POST/DELETE /repos/{owner}/{repo}/branches`, and `GET /repos/{owner}/{repo}/tags`, `GET .../tags/{tag}`, `POST .../tags`, `DELETE .../tags/{tag}`. So the gap is entirely at the CLI/api-helper layer. The read-but-not-write shape mirrors the PR-label gap tracked in `rasterstate/fj#110`: `fj repo branches` *lists* refs the CLI then gives you no way to mutate. ## Why it matters Branch and tag mutation is routine scripted-forge work, and it is the one class of forge operation where `fj` currently has zero coverage: - *Release cutting*: a CI job that tags a release commit (`POST .../tags` with a target SHA) has to either shell out to `git tag && git push` (needs a writable checkout and push credentials) or call `fj api` by hand. `fj release create` creates an annotated release but a lightweight `fj tag create v1.2.3 <sha>` has no equivalent. - *Branch hygiene*: "delete every merged `feature/*` branch" is a common post-merge cleanup. Today it is `fj repo branches --json | jq ... | xargs -I{} fj api -X DELETE /repos/o/r/branches/{}`, defeating the point of having a CLI. - *Listing tags for changelog/diff tooling*: `fj tag list` to feed `git log <prev>..<this>` is a basic building block that simply isn't there; you must `fj api /repos/o/r/tags`. `fj` already covers the heavier, less-frequent ref operations (branch protection via `fj protect`, releases via `fj release`), which makes the absence of the lightweight, high-frequency tag/branch verbs more surprising, not less. ## Possible directions (sketches) - *(sketch)* `fj tag list` / `fj tag view <tag>` / `fj tag create <tag> [--target <sha>] [-m <msg>]` / `fj tag delete <tag> -y`, backed by new thin `src/api/` helpers over the `/repos/{o}/{r}/tags` endpoints. Mirror the existing `fj milestone` / `fj label` CRUD shape (list/view/create/delete with `--json` and a typed-confirmation delete). - *(sketch)* Extend `fj repo` with `branch-create <name> [--from <ref>]` and `branch-delete <name> -y` (or a `fj branch` group), backed by `create_branch`/`delete_branch` helpers over `/repos/{o}/{r}/branches`. The existing `list_branches` (`src/api/repo_core.rs:246`) is the read half already. - *(sketch)* Whichever lands, give `tag list` / `branch` list `--json` from the start so they compose into changelog and cleanup pipelines without re-scraping tables (consistent with the `--json` direction in `rasterstate/fj#109`).
Author
Owner

Converted to backlog item rasterstate/fj#132 (p2, size L).

Converted to backlog item rasterstate/fj#132 (p2, size L).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
rasterstate/fj#121
No description provided.