feat(shell_alias): add shell_alias support for cross-shell aliases#7316
feat(shell_alias): add shell_alias support for cross-shell aliases#7316
Conversation
Adds [shell_alias] configuration to define shell aliases that work across bash, zsh, and fish. Aliases update dynamically when entering/leaving directories, similar to environment variables. Also deprecates [alias] in favor of [tool_alias] for tool version aliases, providing clearer separation between shell aliases and tool version aliases. Changes: - Add set_alias/unset_alias methods to Shell trait with implementations for bash, zsh, and fish - Add shell_alias and tool_alias fields to mise.toml config parsing - Add deprecation warning when [alias] is used (recommends [tool_alias]) - Track aliases in HookEnvSession for dynamic updates - Add e2e tests for shell_alias and tool_alias features Example configuration: ```toml [shell_alias] ll = "ls -la" myTool = "path/to/my_tool.sh --default-option" [tool_alias.node.versions] lts = "22.0.0" ``` Closes #3551 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces cross-shell alias support via [shell_alias] configuration and deprecates [alias] in favor of [tool_alias] for better semantic clarity. Shell aliases are dynamically managed through the hook-env system as users navigate directories, similar to environment variables.
- Added
[shell_alias]section for defining shell aliases that work across bash, zsh, and fish - Renamed
[alias]to[tool_alias]for tool version aliases with backward compatibility - Integrated alias management into the hook-env workflow with tracking and diff-based updates
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/shell/mod.rs | Added set_alias and unset_alias trait methods with default implementations |
| src/shell/bash.rs | Implemented bash alias commands using alias and unalias |
| src/shell/zsh.rs | Delegated zsh alias handling to bash implementation |
| src/shell/fish.rs | Implemented fish alias commands using alias and functions -e |
| src/config/config_file/mise_toml.rs | Added shell_alias and tool_alias fields with deprecation warning for [alias] |
| src/config/config_file/mod.rs | Added shell_aliases() trait method to ConfigFile |
| src/config/mod.rs | Added shell_aliases field and load_shell_aliases function |
| src/hook_env.rs | Added aliases tracking to HookEnvSession and build_alias_commands function |
| src/cli/hook_env.rs | Integrated alias output into hook-env command execution |
| e2e/cli/test_tool_alias | Added e2e tests for tool_alias functionality |
| e2e/cli/test_shell_alias | Added e2e tests for shell_alias functionality |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| fn set_alias(&self, name: &str, cmd: &str) -> String { | ||
| // Default implementation returns empty string (unsupported) | ||
| let _ = (name, cmd); |
There was a problem hiding this comment.
The parameter silencing pattern let _ = (name, cmd); is unconventional. Use the standard _ prefix for unused parameters instead: change the function signature to fn set_alias(&self, _name: &str, _cmd: &str) and remove line 84.
| fn set_alias(&self, name: &str, cmd: &str) -> String { | |
| // Default implementation returns empty string (unsupported) | |
| let _ = (name, cmd); | |
| fn set_alias(&self, _name: &str, _cmd: &str) -> String { | |
| // Default implementation returns empty string (unsupported) |
| fn unset_alias(&self, name: &str) -> String { | ||
| // Default implementation returns empty string (unsupported) | ||
| let _ = name; |
There was a problem hiding this comment.
The parameter silencing pattern let _ = name; is unconventional. Use the standard _ prefix for unused parameters instead: change the function signature to fn unset_alias(&self, _name: &str) and remove line 91.
| fn unset_alias(&self, name: &str) -> String { | |
| // Default implementation returns empty string (unsupported) | |
| let _ = name; | |
| fn unset_alias(&self, _name: &str) -> String { | |
| // Default implementation returns empty string (unsupported) |
| } | ||
|
|
||
| fn unset_alias(&self, name: &str) -> String { | ||
| let name = shell_escape::unix::escape(name.into()); |
There was a problem hiding this comment.
The error suppression pattern 2>/dev/null || true masks all errors. Consider handling the case where the alias doesn't exist more explicitly, or document why this pattern is necessary for robustness.
| let name = shell_escape::unix::escape(name.into()); | |
| let name = shell_escape::unix::escape(name.into()); | |
| // Suppress errors if the alias does not exist. This is intentional and safe, | |
| // as 'unalias' only errors if the alias is missing, which is not a problem here. |
- Add new docs/shell-aliases.md page documenting the shell_alias feature - Update docs/configuration.md to add shell_alias section and rename alias to tool_alias - Update docs/dev-tools/aliases.md to use tool_alias with deprecation notice - Update sidebar to add Shell Aliases under Environments section - Rename "Aliases" to "Tool Aliases" in sidebar for clarity 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
| } | ||
|
|
||
| output | ||
| } |
There was a problem hiding this comment.
Bug: Aliases not set when switching between shell types
When switching from a shell that doesn't support aliases (nushell, elvish, etc.) to one that does (bash, zsh, fish) while inheriting __MISE_SESSION, aliases won't be set. The session stores which aliases were in the config regardless of whether they were actually set in the shell. The build_alias_commands function compares PREV_SESSION.aliases with new_aliases - if they're equal, no commands are generated. However, the previous shell may have returned empty strings from set_alias. Since HookEnvSession doesn't track the shell type, there's no way to detect this shell change and force re-setting aliases.
Additional Locations (1)
There was a problem hiding this comment.
Bug: Shell aliases not cleaned up during deactivation
When mise deactivate is called, the build_deactivation_script function clears environment variables via clear_old_env but does not clear shell aliases. The PREV_SESSION.aliases contains all aliases mise has set, but these are never unset during deactivation. This causes aliases like ll='ls -la' to persist in the shell after deactivation, which is inconsistent with environment variable cleanup behavior. Users would have dangling aliases after running mise deactivate.
src/shell/mod.rs#L117-L126
Lines 117 to 126 in a42c00c
src/hook_env.rs#L335-L356
Lines 335 to 356 in a42c00c
Shell aliases were not being cleaned up when `mise deactivate` was called. The `clear_old_env` function cleared environment variables but not aliases from `PREV_SESSION.aliases`, causing dangling aliases to persist in the shell. This fix adds alias clearing to `clear_old_env` so that all aliases are properly unset during deactivation, matching the behavior of environment variable cleanup. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.12.7 x -- echo |
20.2 ± 0.3 | 19.6 | 22.4 | 1.00 |
mise x -- echo |
20.3 ± 0.8 | 19.1 | 22.5 | 1.01 ± 0.04 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.12.7 env |
20.3 ± 0.7 | 19.3 | 29.1 | 1.04 ± 0.06 |
mise env |
19.5 ± 0.9 | 18.5 | 28.4 | 1.00 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.12.7 hook-env |
19.8 ± 0.6 | 19.3 | 30.3 | 1.02 ± 0.04 |
mise hook-env |
19.4 ± 0.5 | 18.6 | 23.2 | 1.00 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.12.7 ls |
17.0 ± 0.4 | 16.1 | 18.0 | 1.00 |
mise ls |
17.0 ± 0.4 | 16.3 | 18.7 | 1.00 ± 0.03 |
xtasks/test/perf
| Command | mise-2025.12.7 | mise | Variance |
|---|---|---|---|
| install (cached) | 107ms | 108ms | +0% |
| ls (cached) | 65ms | 65ms | +0% |
| bin-paths (cached) | 71ms | 71ms | +0% |
| task-ls (cached) | 436ms | -80% |
The previous fix for alias clearing during deactivation incorrectly cleared aliases on every hook-env run by adding the clear logic to `clear_old_env()`. This function is called both during deactivation AND on every hook-env invocation, causing unchanged aliases to be cleared unnecessarily. This fix separates alias clearing into its own `clear_aliases()` function that is only called from `build_deactivation_script()`, ensuring aliases are properly maintained during normal hook-env runs while still being cleaned up during deactivation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The load_shell_aliases function was iterating over config_files.values() without calling .rev(), causing parent and global config files to override child directory configs. This is backwards from the documented behavior which states "A child directory can override a parent's alias." This fix adds .rev() to iterate in reverse order (global -> local) so that child directories properly take precedence, matching the pattern used by load_env. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
### 🚀 Features - **(conda)** add dependency resolution for conda packages by @jdx in [#7280](#7280) - **(go)** add created_at support to ls-remote --json by @jdx in [#7305](#7305) - **(hook-env)** add hook_env.cache_ttl and hook_env.chpwd_only settings for NFS optimization by @jdx in [#7312](#7312) - **(hooks)** add MISE_TOOL_NAME and MISE_TOOL_VERSION to preinstall/postinstall hooks by @jdx in [#7311](#7311) - **(shell_alias)** add shell_alias support for cross-shell aliases by @jdx in [#7316](#7316) - **(tool)** add security field to mise tool --json by @jdx in [#7303](#7303) - add --before flag for date-based version filtering by @jdx in [#7298](#7298) ### 🐛 Bug Fixes - **(aqua)** support cosign v3 bundle verification by @jdx in [#7314](#7314) - **(config)** use correct config_root in tera context for hooks by @jdx in [#7309](#7309) - **(nu)** fix nushell deactivation script on Windows by @fu050409 in [#7213](#7213) - **(python)** apply uv_venv_create_args in auto-venv code path by @jdx in [#7310](#7310) - **(shell)** escape exe path in activation scripts for paths with spaces by @jdx in [#7315](#7315) - **(task)** parallelize exec_env loading to fix parallel task execution by @jdx in [#7313](#7313) - track downloads for python and java by @jdx in [#7304](#7304) - include full tool ID in download track by @jdx in [#7320](#7320) ### 📚 Documentation - Switch `postinstall` code to be shell-agnostic by @thejcannon in [#7317](#7317) ### 🧪 Testing - **(e2e)** disable debug mode by default for windows-e2e by @jdx in [#7318](#7318) ### New Contributors - @fu050409 made their first contribution in [#7213](#7213)
Summary
Adds
[shell_alias]configuration to define shell aliases that work across bash, zsh, and fish. Aliases update dynamically when entering/leaving directories, similar to environment variables.[shell_alias]section to mise.toml for defining shell aliases[alias]in favor of[tool_alias]for tool version aliases (clearer naming)Example configuration:
Closes #3551
Changes
src/shell/mod.rs: Addedset_alias/unset_aliasmethods to Shell traitsrc/shell/bash.rs: Bash implementation for alias commandssrc/shell/zsh.rs: Zsh implementation (delegates to Bash)src/shell/fish.rs: Fish implementation usingalias/functions -esrc/config/config_file/mise_toml.rs: Addedshell_aliasandtool_aliasfields with deprecation warning for[alias]src/config/config_file/mod.rs: Addedshell_aliases()to ConfigFile traitsrc/config/mod.rs: Addedshell_aliasesloading to Configsrc/hook_env.rs: Added alias tracking in session andbuild_alias_commands()functionsrc/cli/hook_env.rs: Integrated alias output into hook-env commandTest plan
mise run lint-fix- passesmise run test:e2e test_shell_alias test_tool_alias- all passcargo test --all-features- 377 tests pass🤖 Generated with Claude Code
Note
Adds cross-shell dynamic shell aliases via
[shell_alias]and renames[alias]to[tool_alias], with hook-env integration, config loading, docs, and tests.hook_env::build_alias_commandsand tracks aliases inHookEnvSession(src/cli/hook_env.rs,src/hook_env.rs).hook_env::clear_aliases).[shell_alias]; load intoConfig.shell_aliaseswith sources (src/config/config_file/mise_toml.rs,src/config/mod.rs).[tool_alias]; merge with legacy[alias](deprecated) with precedence and warning.Shelltrait withset_alias/unset_alias; implement forbash,zsh,fish(src/shell/*).[tool_alias]and[shell_alias](docs/*).test_shell_alias(set/update/unset behavior) andtest_tool_alias(fallback, precedence).Written by Cursor Bugbot for commit 210b215. This will update automatically on new commits. Configure here.