gitee-cli-rs 0.2.2

A gh-like command-line client for Gitee
Documentation

gitee

A gh-like command-line client for Gitee. Manage pull requests, issues, releases, gists, and more from your terminal.

Quick start

1 — Install (pick one):

cargo install gitee-cli-rs      # build from crates.io
cargo binstall gitee-cli-rs     # pre-built binary (no compile)
brew install kipyin/tap/gitee   # macOS via Homebrew

Or grab a binary from GitHub Releases.

2 — Log in with a Gitee personal access token:

gitee auth login

3 — Use it. Run inside any git clone (or add --repo owner/name):

gitee pr list        # pull requests
gitee issue list     # issues
gitee status         # your open issues across repos
gitee release list   # releases
gitee repo view      # repo info

That's it. Everything below is detail.

Scripting gitee-cli? See docs/scripting.md for exit codes, --preview, idempotent mutating verbs, and CI/agent patterns.

Install

Method Command Notes
crates.io cargo install gitee-cli-rs builds from source
cargo-binstall cargo binstall gitee-cli-rs same binary, no compile
Homebrew (macOS) brew install kipyin/tap/gitee arm64 + x86_64
Direct download Releases gitee-<target>-v<ver>.tar.xz
From source cargo install --path . after git clone

The crates.io package is gitee-cli-rs, but the installed command is gitee.

Shell completions (bash/zsh/fish/powershell/elvish):

gitee completions zsh > "${fpath[1]}/_gitee"

Configure

The CLI needs a Gitee personal access token. Create one at https://gitee.com/profile/personal_access_tokens (default scopes are fine for reading; check pull_requests, issues, and projects for write actions).

gitee auth login                  # prompts for the token, validates it, stores it

For CI / scripts, use an environment variable instead:

export GITEE_TOKEN=your_token

Token lookup order: $GITEE_TOKEN → OS keyring → ~/.config/gitee/<host>/… (per-user token files after login; legacy ~/.config/gitee/<host>.token is migrated).

Useful commands:

gitee auth status                 # where am I logged in / who's active?
gitee auth token                  # print the active token (for piping)
gitee auth switch --user alice    # pick among saved accounts on this host
gitee auth setup-git              # use gitee as git credential helper
gitee auth logout                 # forget the stored token
gitee config set editor nvim      # defaults: host / remote / editor
gitee alias set co pr checkout    # expand `gitee co 42` → `gitee pr checkout 42`

Everyday commands

Run from inside a repo, or point anywhere with --repo owner/name.

# pull requests
gitee pr list
gitee pr status                      # created / assigned / awaiting my test
gitee pr view 42
gitee pr view 42 --web               # open in browser
gitee pr diff 42
gitee pr checkout 42                 # fetch into local branch pr-42
gitee pr create --title "Fix" --head my-branch
gitee pr create --draft --title "WIP"    # draft PR (mark ready later)
gitee pr create                      # interactive title/body on a TTY
gitee pr create --fill               # title/body from commits
gitee pr edit 42 --title "Retitle" --label bug
gitee pr ready 42                    # draft → ready for review
gitee pr ready 42 --undo             # ready → draft again
gitee pr comment create 42 -m "LGTM"
gitee pr approve 42                  # 审查通过
gitee pr test 42                     # 测试通过 (Gitee-specific)
gitee pr merge 42 --squash

# issues
gitee issue list
gitee issue status                   # created / assigned to me
gitee issue view I88
gitee issue view I88 --web
gitee issue create --title "Bug" --body "steps…"
gitee issue create                   # interactive title/body on a TTY
gitee issue edit I88 --label bug --milestone v1.0
gitee issue edit I88 --state progressing   # open|progressing|closed (API write set)
gitee issue comment create I88 -m "looking into it"
gitee issue close I88

# cross-repo dashboard / browser
gitee status                         # assigned / created open issues
gitee browse                         # open the resolved repo in a browser

# search
gitee search repos gitee --language Rust
gitee search issues login --state open
gitee search users kip

# releases
gitee release list
gitee release view v1.0.0
gitee release view v1.0.0 --web
gitee release create --tag v1.0.0 --notes "changelog…"
gitee release upload v1.0.0 dist/*.tar.xz
gitee release download v1.0.0 --dir ./dist
gitee release edit v1.0.0 --notes "updated notes"

# repositories
gitee repo view oschina/git
gitee repo view --web
gitee repo list
gitee repo clone oschina/git
gitee repo fork
gitee repo create my-tool --private
gitee repo edit --description ""
gitee repo rename new-slug
gitee repo star                      # also: unstar / watch / unwatch

# labels / milestones
gitee label list
gitee label create bug --color ff0000
gitee milestone list
gitee milestone create --title v1.0 --due-on 2026-12-31

# org / access / hooks
gitee org list
gitee ssh-key list
gitee ssh-key add ~/.ssh/id_ed25519.pub --title laptop
gitee collaborator list
gitee collaborator add alice --permission push
gitee webhook list
gitee webhook create --url https://example.com/hook --events push_events

# gists
gitee gist list
gitee gist create notes.md --desc "scratch"
gitee gist view <id> --raw

# config / aliases / extensions
gitee config list
gitee alias list
gitee extension list                 # gitee-* binaries on PATH + managed dir
gitee extension install owner/my-ext # clone + (optionally) build, into managed dir
gitee extension create demo         # scaffold a new extension in cwd
gitee extension remove demo         # delete an installed extension
gitee extension upgrade [name]      # git pull + rebuild (all if no name)
# unknown commands also exec `gitee-<name>` from PATH (gh-style)

# raw API escape hatch
gitee api user
gitee api repos/oschina/git/releases --paginate

Handy global flags:

gitee pr list --json number,title          # JSON field projection
gitee pr list --json --jq '.[].title'      # jq after projection
gitee --debug pr list                      # HTTP trace on stderr
gitee --repo owner/name pr list            # target a repo without cd'ing
gitee --remote gitee pr status             # resolve via a non-origin remote
gitee --host git.example.com ...           # self-hosted Gitee

Command reference

Subcommand Description
list List PRs (--state, --author, --limit)
status Open PRs relevant to you: created, assigned, awaiting your test (--limit)
view <n> Show pull request details (--web opens in browser; --merged exits 0/1 for merge state); --json includes a files array with per-file path / additions / deletions / changes
diff <n> Show pull request diff
checkout <n> Fetch and check out a pull request locally
commits <n> List commits on a pull request
create Open a PR (--title / --fill, or interactive on a TTY; --body, --head, --base, --assignee, --tester, --label, --milestone, --close-issue, --draft)
edit <n> Edit metadata (--title, --body, --assignee, --tester, --label, --milestone)
ready <n> Mark a draft PR ready for review (--undo converts back to draft) — idempotent
merge <n> Merge (--squash, --rebase, --no-close-issue) — idempotent: already-merged exits 0
comment create <n> Add a comment (-m/--body; optional --path / --position / --commit-id for diff-line comments; --position is Gitee's diff line index)
comment list <n> List comments (`--type diff
comment edit <id> Edit by id, or latest via --last + PR number (-m/--body or $EDITOR)
comment delete <id> Delete by id, or latest via --last + PR number (--yes skips confirm; 404 is idempotent)
label add|remove|list <n> Non-destructive label membership on a PR
assignee add|remove|list <n> Non-destructive reviewer (审查人) membership
tester add|remove|list <n> Non-destructive tester (测试人) membership
approve <n> Approve / 审查通过 (--force)
test <n> Mark tested / 测试通过 (--force) — Gitee-specific
close <n> / reopen <n> Change state
link <n> <issue> Link a pull request to an issue
Subcommand Description
list List issues (--state, --assignee, --limit)
status Open issues relevant to you: created, assigned (--limit)
view <n> Show issue details (--web; Gitee issue idents are strings, e.g. I88)
create Create (--title or interactive on a TTY; --body, --assignee, --labels, --milestone, --security-hole)
edit <n> Edit metadata (--title, --body, --assignee, --label, --milestone, --security-hole, --state open|progressing|closed)
close <n> / reopen <n> Change state — idempotent: already-closed/open exits 0 (open/closed shortcuts; prefer edit --state progressing for in-progress)
link <n> <pr> Link an issue to a pull request
comment create <n> Add a comment (-m/--body) — closed issues often reject new comments on Gitee (reopen → comment → re-close)
comment list <n> List comments (--limit)
comment edit <id> Edit by id, or latest via --last + issue ident (-m/--body or $EDITOR)
comment delete <id> Delete by id, or latest via --last + issue ident (--yes skips confirm; 404 is idempotent)
label add|remove|list <n> Non-destructive label membership on an issue
Flag Description
--limit Cap each section (default 30)

Shows open issues assigned to you and created by you across all repos. PR sections are omitted — Gitee v5 has no user-level pulls endpoint.

Subcommand Description
repos <query> Search repositories (--owner, --language, --fork, --sort, --order, --limit)
issues <query> Search issues (--state, --author, --assignee, --label, --language, --sort, --order, --limit; scoped with global --repo)
users <query> Search users (--sort, --order, --limit)
Subcommand Description
list List releases (--limit)
view <tag> Show release details (--web opens in browser)
create Create (--tag required; --name, --notes, --target, --prerelease)
upload <tag> <files…> Attach files to an existing release
download <tag> Download assets (--dir, --pattern)
edit <tag> Edit (--name, --notes, --prerelease)
delete <tag> Delete (--yes to skip confirmation) — deleting a missing release exits 4
Subcommand Description
view [repo] Show repository details (--web opens in browser)
list [owner] List repos (yours, or a user/org's public repos) (--limit)
clone <spec> [dir] Clone via git (--ssh)
fork Fork the resolved repository (--add-remote <name>)
create <name> Create under your account or --org (--private, --description, --homepage, --gitignore, --license)
edit Edit settings (--description, --homepage, --private/--public, --default-branch)
rename <path> Rename the URL slug
star / unstar Star or unstar the resolved repository
watch / unwatch Watch or unwatch the resolved repository
delete Delete (--yes to skip confirmation)
Subcommand Description
list List labels (--limit)
create <name> Create (--color required, hex without #) — idempotent: same name + same color exits 0; same name + different color exits 1 with gitee label edit <name> --color <c> hint
edit <name> Edit (--name, --color)
delete <name> Delete (--yes to skip confirmation) — deleting a missing label exits 4
Subcommand Description
list List milestones (--state, --limit)
view <n> Show milestone details
create Create (--title and --due-on YYYY-MM-DD required; --description, --state)
edit <n> Edit (--title, --due-on, --description, --state)
Subcommand Description
list List your gists (--limit)
view <id> Show a gist (--raw prints file contents)
create <files…> Create (--desc, --public, --filename when reading - from stdin)
edit <id> <file> Replace one file's contents
delete <id> Delete (--yes to skip confirmation)

Like gh api. Pass an endpoint path, optional -X method, -F/-f fields, -H headers, --input, and --paginate for array paging.

gitee api user
gitee api /repos/oschina/git/issues -X POST -F title=Bug -F body=steps
gitee api repos/oschina/git/releases --paginate

Issue state changes are a common footgun: use PATCH /repos/{owner}/issues/{number} with a JSON body {"repo":"<name>","title":"<current title>","state":"progressing"} (title must be echoed or Gitee blanks it). The /repos/{owner}/{repo}/issues/{number} path with form -f state=… often returns 404 {"message":"project or enterprise"}. Prefer gitee issue edit <n> --state … when you can.

Writable issue state values (Gitee v5, verified live): only open, progressing, and closed. Sending rejected returns 400 {"messages":["state does not have a valid value"]} — that limit is on the official API, not a CLI mapping bug. closed always maps to the board label 已完成; there is no API close-reason for 拒绝 / wontfix. Express non-completion with a repo label (e.g. wontfix) plus a comment. Older CLI builds accepted --state rejected and simply forwarded the 400.

Subcommand Description
login Store a token (--token, --force to skip validation)
status Show login status, active user, and token source
token Print the active token
logout Forget the stored token for the current host
switch --user <name> Switch the active saved account for this host
setup-git Configure git to use gitee as credential helper for this host
git-credential Git credential-helper protocol (get / store / erase; usually invoked by git)

Opens the resolved repository in your default browser. Prefer view --web when you already know the PR / issue / release / repo target.

Subcommand Description
list List organizations for the authenticated user (--limit)
Subcommand Description
list List your SSH public keys (--limit)
add <pubkey-file> Upload a public key (--title)
delete <id> Delete a key (--yes to skip confirmation)
Subcommand Description
list List collaborators on the resolved repo (--limit)
add <username> Add a collaborator (--permission pull|push|admin, default push)
remove <username> Remove a collaborator (--yes to skip confirmation)
Subcommand Description
list List webhooks (--limit)
create Create (--url required; --events push_events/tag_push_events/issues_events/merge_requests_events/note_events; --password)
delete <id> Delete (--yes to skip confirmation)
Subcommand Description
list Show configured keys
get <key> Read one key (host, remote, editor)
set <key> <value> Write one key

Stored in ~/.config/gitee/config.json. CLI flags still win over these defaults.

Subcommand Description
list Show aliases
set <name> <expansion…> Define an alias (shell-quote multi-word expansions)
delete <name> Remove an alias

Example: gitee alias set co pr checkoutgitee co 42 expands to gitee pr checkout 42.

Subcommand Description
list List gitee-* executables discovered on PATH and in the managed dir
install <owner/repo> [--build cargo|npm] [-y] Clone the repo into the managed dir and (optionally) build it
create <name> [--cargo] Scaffold a new extension project in the current directory
remove <name> [-y] Delete an installed extension from the managed dir
upgrade [name] git pull (and rebuild, if needed) one or all installed extensions

Unknown top-level commands also exec gitee-<name> from PATH (same model as gh).

Extensions

Installed extensions live in a managed dir (no shell PATH mutation):

  • Linux/macOS: ~/.local/share/gitee/extensions/<name>/
  • Windows: %LOCALAPPDATA%\gitee\extensions\<name>\

The CLI's extension resolver scans this managed dir before PATH, so an installed extension shadows a same-named binary elsewhere. The directory layout is <name>/gitee-<name> — the entry point must be a gitee-<name> executable at the repo root (no build step) unless --build cargo or --build npm is given.

Trust model. gitee extension install downloads and runs arbitrary code. Before cloning it prints the repo URL and last commit short SHA and asks for confirmation (--yes skips). There is no signature verification — install only from repos you trust.

Build systems.

  • --build cargo: runs cargo build --release, copies the resulting binary (named after the crate, or gitee-<name>) to the extension dir root.
  • --build npm: runs npm install and npm run build (if a build script exists); the gitee-<name> script at the repo root is the entry point.
  • Default (no --build): the repo must already contain a gitee-<name> executable at the root.

Environment contract (forwarded to every extension child process):

  • GITEE_TOKEN — the active personal access token (or your own $GITEE_TOKEN).
  • GITEE_HOST — the active Gitee host (e.g. gitee.com), unless already exported.
  • All trailing argv, forwarded verbatim.

Global flags

Flag Description
--repo <owner/name> Target repository (default: resolved from git remote)
--remote <name> Git remote to resolve the repo from (default: origin)
--host <host> Gitee host (default: gitee.com)
--json [fields] JSON output; --json number,title projects fields
--jq <expr> jq expression on --json output (requires --json)
--debug Log HTTP requests/responses to stderr
--preview Print what would happen and exit 0 (no HTTP call); mutating verbs only

Exit codes

gitee exits with a stable, documented code so scripts can switch on $? instead of parsing stderr. See docs/scripting.md for the full table and patterns.

Code Meaning
0 success (including idempotent no-ops)
1 generic failure
2 usage error (missing flag, bad arg, non-TTY prompt attempted)
3 auth error (no token / invalid / expired)
4 not found (repo / issue / PR / release)
5 rate limited (HTTP 429)
6 network error (host unreachable)

When --json is set, errors print to stderr as {"code":"not_found","message":"…","exit_code":4} — see docs/scripting.md.

Repository resolution

Most commands operate on a repository resolved two ways:

  1. --repo owner/name, or
  2. from the current directory's git remote (--remote, default origin).

So either cd into a clone, or pass --repo / --remote explicitly.

Compared to gh (与 gh 的差异)

Gitee OpenAPI v5 does not expose everything GitHub CLI can reach. These are not planned (no public API / no Gitee equivalent):

  • gh workflow / gh run / gh pr checks / secrets / variables — Gitee Go has no public v5 REST API; PR 门禁 is only available via third-party apps
  • issue transfer / pin / lock / delete — no Gitee API
  • repo archive — no Gitee API
  • codespaces / projects / attestations / discussions — no Gitee equivalent

Also omitted after swagger verification: repo sync, pr update-branch.

Shipped gh-parity items that used to be gaps: issue|pr comment list/edit/delete (plus --last), pr commits, and pr view --merged.

An MCP server is intentionally not built into this CLI — Gitee already ships an official one (mcp-gitee, Go). For AI agent runtimes that prefer native MCP integration, use the official server. For shell-out / CI patterns, see Scripting gitee-cli for agents below.

Gitee-specific (Gitee 特色)

Features beyond GitHub CLI parity:

Feature Status Notes
pr test shipped 测试通过 gate; pairs with pr approve (审查通过)
issue --security-hole shipped mark an issue as a security hole on create/edit
milestone shipped full list/view/create/edit; Gitee requires --due-on on create
pr assignees and testers shipped dual review/test roles on create/edit/status; plus non-destructive assignee/tester {add,remove,list}
issue|pr label {add,remove,list} shipped non-destructive label membership (distinct from repo-level gitee label)
pr comment create --path/--position/--commit-id shipped positional/diff-line comments; position is Gitee's diff line index
pr commits / pr view --merged shipped commit list + scriptable merge check
repo star / watch shipped star / unstar / watch / unwatch
webhook shipped list / create / delete repository hooks

Scripting gitee-cli for agents

AI agents and CI scripts can drive this CLI directly — no MCP required.

  • Native MCP integration (for agent runtimes like Claude Code, Cursor, opencode): use Gitee's official mcp-gitee (Go). We do not ship our own MCP server; the official one is active and covers the read/write surface.
  • Shell-out patterns (for agents that exec commands, and for CI): every verb supports --json + --jq for structured output, stable exit codes (0–6), structured JSON errors on stderr in --json mode, idempotent mutating verbs (already-closed / already-merged is exit 0), and --preview to dry-run a mutation. See docs/scripting.md for the PR→issue closure loop, batch operations, CI status gates, and error handling by exit code.
  • Extensions as agent tools: a MCP server can also be installed as a gitee extension via gitee extension install <owner/repo> --build cargo (see Extensions above) if a Rust implementation you trust ever emerges.

License

MIT — see Cargo.toml.