Skip to content

feat: allow unambiguous command shorthands - #649

Merged
jpgrayson merged 4 commits into
stacked-git:masterfrom
dtor:allow-shorthands
Oct 10, 2026
Merged

jpgrayson merged 4 commits into
stacked-git:masterfrom
dtor:allow-shorthands

Conversation

@dtor

@dtor dtor commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

Allow invoking StGit commands, aliases, and subcommands using any unambiguous prefix (for example, stg del for stg delete, stg ser for stg series, or stg em s for stg email send), matching StGit 1.x behavior.

Enable infer_subcommands(true) on the base clap Command so clap accepts unambiguous prefixes for top-level and nested subcommands. Because the initial bootstrap CLI parser uses
allow_external_subcommands(true) to avoid constructing the full command graph up front, also resolve subcommand prefixes across built-in commands, help, and configured aliases:

  • Exact matches on built-in commands, help, or aliases always take precedence over prefix matches.
  • Non-exact prefixes are checked against built-in commands, help, and aliases together so that a prefix shared between a built-in command and an alias (such as res for reset and resolved) is rejected as ambiguous.

Allow invoking StGit commands, aliases, and subcommands using any
unambiguous prefix (for example, `stg del` for `stg delete`, `stg ser`
for `stg series`, or `stg em s` for `stg email send`), matching StGit
1.x behavior.

Enable `infer_subcommands(true)` on the base clap Command so clap
accepts unambiguous prefixes for top-level and nested subcommands.
Because the initial bootstrap CLI parser uses
`allow_external_subcommands(true)` to avoid constructing the full
command graph up front, also resolve subcommand prefixes across
built-in commands, `help`, and configured aliases:

- Exact matches on built-in commands, `help`, or aliases always take
  precedence over prefix matches.
- Non-exact prefixes are checked against built-in commands, `help`,
  and aliases together so that a prefix shared between a built-in
  command and an alias (such as `res` for `reset` and `resolved`) is
  rejected as ambiguous.

Signed-off-by: Dmitry Torokhov <dtor@google.com>
Whether a prefix is unambiguous depends on the set of commands and
aliases, so defining an alias or upgrading StGit can silently break
an abbreviation that previously worked, and the result can differ
between repositories with different local aliases. Users who accept
that tradeoff can enable stgit.infer-commands; everyone else keeps
the exact-match behavior of StGit 2.x.

The config is only read on the fast path when the matched command
has nested subcommands, so plain command dispatch stays cheap.
An alias stored in config that relies on a command prefix breaks as
soon as another command or alias sharing that prefix appears, far
from where the alias was defined. Requiring the exact command name
keeps configured aliases stable regardless of stgit.infer-commands.

Nested subcommands are still inferred when enabled since they may
come from the user's arguments rather than the alias definition.
The flag-style subcommands of stg branch looked like long options, so
stg branch --l listed branches even though real long options are
never abbreviated. Clap's subcommand inference is a global setting
that cannot be enabled for the top-level command alone, so an
inferred top-level name is now spelled out in argv before clap sees
it. Inference is then only enabled for commands whose nested
subcommands do not start with a hyphen.

Spelling out an inferred "help" the same way means the full-help
fallback never needs inference.
@jpgrayson

Copy link
Copy Markdown
Collaborator

Thanks for this PR, @dtor. And sorry for the delayed response.

Dropping command prefixes in 2.0 was a deliberate choice (see #240 and #462). The main reason is that whether a prefix is unambiguous depends on which commands and aliases exist. Defining an alias, or upgrading StGit, can quietly break an abbreviation someone relies on, and the same prefix can behave differently between repos that define different aliases.

So I don't want to merge this as-is. I would accept prefix support with the following changes, which I've already implemented and tested on top of your commit:

  1. Opt-in. Prefix inference is off by default and enabled with a new stgit.infer-commands config option, documented in stg(1). With it off, behavior is unchanged from 2.x, including nested subcommands (stg email f is rejected).

  2. No prefixes in alias definitions. stgit.alias.ls = ser is rejected even when inference is enabled. A prefix stored in config would break when an unrelated command or alias that shares the prefix is added.

  3. No long-option abbreviation. Because infer_subcommands() is a global clap setting, stg branch --l was accepted as stg branch --list. To users those look like long options, and StGit never abbreviates long options. With my patch, an inferred top-level command name is replaced with the full name in argv before clap parses it, and clap's inference is only enabled for nested subcommands that aren't spelled like options. stg bra --list still works; stg branch --l is rejected. This also means the help fallback never infers, which closes a path where clap could resolve an alias prefix that dispatch had rejected and hit the expect_err() panic in full_app_help().

Does this work for your use case? If you're good with it, I'll push these commits to this PR.

@dtor

dtor commented Oct 10, 2026

Copy link
Copy Markdown
Contributor Author

Yes, thatworks for me. Frankly, I have muscle memory for "stg ref", "stg res", and "stg del" and that is pretty much it.

Thanks!

@jpgrayson

Copy link
Copy Markdown
Collaborator

Thanks, @dtor. One heads-up: stg res will still be rejected as ambiguous with stgit.infer-commands enabled, because the built-in resolved alias also starts with res.

You can use an explicit alias though:

git config --global stgit.alias.res reset

I'll push the commits to this PR.

@jpgrayson
jpgrayson merged commit 21c879e into stacked-git:master Oct 10, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants