The #113 sweep rested on CLAUDE.md's premise that rtk either filters or passes through unchanged, so prefixing is always safe. Measured against rtk 0.42.4, that premise is false for several of the commands the sweep prefixed, and two skills were left giving wrong answers silently. Why: - `rtk git worktree list --porcelain -z` discards both flags and renders its own format. The `locked`/`lock_reason` fields git-worktrees Step 2 must emit are absent entirely, and paths under $HOME are abbreviated to `~/`. - `rtk git branch --list <name>` prints a phantom `* ` line even when nothing matches, so git-branches' stated ambiguity test — "output from both means the name is ambiguous" — reported every name as ambiguous. `tag --list` is a clean passthrough, so only one half broke. - `rtk git diff --name-only`/`--name-status` append a `Changes:` trailer to output documented as "one per line"; `--word-diff` emits none of the `[-removed-] {+added+}` markers its table describes; `rtk git log -L` truncates each line at ~72 chars, on the one command whose purpose is showing line content. - `rtk git stash pop` prints only `FAILED: git stash pop`, swallowing the conflict diagnostic and retained-entry message the surrounding prose tells the agent to rely on. Implementation notes: - Eleven sites reverted to bare `git`, each carrying its reason inline so the next sweep does not undo it. `mergetool` and `rebase -i` are reverted on clause 3's interactive limb only: the TTY defect does not reproduce — rtk filters exactly twelve subcommands and execs the rest — and ADR-0023 records that measurement rather than a convenient one. - ADR-0023 states the rule repo-wide with a third clause: a command whose output the skill parses, or which is interactive, stays bare. `plugins/git/README.md` is reduced to a pointer; its claim that gitea skills "contain no git/rtk mentions at all" was false, and its citation of `hard-rules.md` pointed at a file containing no occurrence of "rtk". - Eight gitea sites swept, all verified byte-identical passthroughs first. - `scripts/check-rtk-prefix.sh` gates clause 1. Run against main's pre-sweep corpus it reports 99 findings including every gitea site, so it would have caught the drift #113 was filed about. Impact: the gate covers clause 1 only, in shell-tagged fences and the opening span of Run cells. Clause 2 is not gateable — "Run `git switch`" and "`git switch` refuses" are the same tokens — and prose bullets are invisible to it. Both limits are recorded in gates.md rather than left implied. Refs: #113 ADR: 0023 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP
109 lines
4.5 KiB
Markdown
109 lines
4.5 KiB
Markdown
---
|
|
topic: branches
|
|
source_keys:
|
|
- gitea-mcp-repo
|
|
- gitea-mcp-slim-go
|
|
---
|
|
|
|
# Branch operations
|
|
|
|
Call signatures below were verified live against the deployed `gitea-mcp` server via `ToolSearch`,
|
|
not copied from research docs — this is deliberate: research docs are generated from source code at
|
|
a point in time and can drift from the server actually deployed. **Last verified against gitea-mcp
|
|
v1.7.0**, as reported by `get_gitea_mcp_server_version`. Re-verify against the live schema if the
|
|
deployed version differs or these tools behave differently than documented here.
|
|
|
|
## `list_branches`
|
|
|
|
**Parameters:**
|
|
- `owner` (string, required)
|
|
- `repo` (string, required)
|
|
- `page` (number, optional, default: `1`)
|
|
- `per_page` (number, optional, default: `30`)
|
|
|
|
**Call:**
|
|
```text
|
|
list_branches owner: <owner> repo: <repo>
|
|
```
|
|
|
|
**Response:** one object per branch: `name`, `protected` (bool), `commit_sha` (present when the
|
|
underlying commit data is available).
|
|
|
|
Paginate if you need the full list (see Gotchas in SKILL.md) — iterate `page` until the returned
|
|
count is less than `per_page`.
|
|
|
|
## `create_branch`
|
|
|
|
**Parameters:**
|
|
- `owner` (string, required)
|
|
- `repo` (string, required)
|
|
- `branch` (string, required) — new branch name
|
|
- `old_branch` (string, optional) — source branch; if omitted, defaults to the repo's default
|
|
branch server-side (not necessarily your current local checkout)
|
|
|
|
**Call:**
|
|
```text
|
|
create_branch owner: <owner> repo: <repo> branch: <new-name> old_branch: <source-branch>
|
|
```
|
|
|
|
Default dispatch: if the user gives a base ("branch off of X", "from X"), pass it as `old_branch`.
|
|
If they don't specify a base and you're mid-task on a local branch, pass your current branch
|
|
(`rtk git branch --show-current`) as `old_branch` so the new branch forks from where you're actually
|
|
working, rather than silently falling back to the repo default. If neither applies (e.g. a fresh
|
|
top-level request with no working branch context), omit `old_branch` and let it default server-side.
|
|
|
|
A branch name collision returns `409 Conflict`.
|
|
|
|
## `rename_branch`
|
|
|
|
**Parameters:**
|
|
- `owner` (string, required)
|
|
- `repo` (string, required)
|
|
- `branch` (string, required) — the branch's current name
|
|
- `new_name` (string, required) — the name to move it to
|
|
|
|
**Call:**
|
|
```text
|
|
rename_branch owner: <owner> repo: <repo> branch: <current-name> new_name: <new-name>
|
|
```
|
|
|
|
A rename moves the ref server-side; it is not a delete-plus-create, and no commit history is
|
|
rewritten. What it does to things *pointing at* the old name — open pull requests using it as head or
|
|
base, a branch protection rule matching it, CI config, and tracking branches on every other clone —
|
|
is **not confirmed** by this skill's sources: the deployed tool describes itself only as "Rename an
|
|
existing branch in a repository". Treat a rename of a branch with open PRs or a protection rule as a
|
|
change needing verification afterward (`list_branches`, plus `gitea-prs` for the PR side), and
|
|
confirm with the user first, exactly as for `delete_branch` below. A collision with an existing
|
|
branch name is expected to return `409 Conflict` by analogy with `create_branch`, not separately
|
|
confirmed.
|
|
|
|
## `delete_branch`
|
|
|
|
**Parameters:**
|
|
- `owner` (string, required)
|
|
- `repo` (string, required)
|
|
- `branch` (string, required)
|
|
|
|
**Call:**
|
|
```text
|
|
delete_branch owner: <owner> repo: <repo> branch: <name>
|
|
```
|
|
|
|
Before calling this, see the `delete_branch` Gotcha in SKILL.md. If the target branch's name isn't
|
|
obviously a scratch/feature branch, call `list_branches` first and check `protected` on the
|
|
matching entry — name-matching `main`/`master` alone isn't authoritative, since a repo can protect
|
|
a differently-named default branch. Confirm explicitly with the user before deleting anything
|
|
protected, every time, regardless of how the request is phrased.
|
|
|
|
## Token scope
|
|
|
|
`list_branches`, `create_branch` and `delete_branch` all require `write:repository`. Gitea
|
|
gates reads behind write scope for repo-scoped operations, so `list_branches` needs the same scope
|
|
as the write operations, not `write:issue` alone. An earlier version of this doc claimed
|
|
`write:issue` alone was sufficient for `list_branches`, based on empirical testing under a token
|
|
that held both `write:issue` and `write:repository` simultaneously — that test didn't isolate the
|
|
variable, so it couldn't actually establish `write:issue` alone as sufficient.
|
|
|
|
`rename_branch` is a write on the same repo-scoped surface and is inferred to need `write:repository`
|
|
too — inferred by analogy, not separately confirmed.
|