fix(activate): preserve ordering of paths appended after mise activate#7919
fix(activate): preserve ordering of paths appended after mise activate#7919
Conversation
Paths added to PATH after `eval "$(mise activate)"` in shell rc files were being moved to the front of PATH instead of staying at the end. The bug was in build_path_operations(): all PATH entries not in __MISE_ORIG_PATH and not mise-managed were collected into `pre` and placed at the beginning. Now they are split into `pre` (before original PATH entries) and `post_user` (after), preserving their intended position. Fixes #7694 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes a bug where paths appended to $PATH after mise activate in shell RC files were incorrectly moved to the front of PATH instead of maintaining their intended position at the end.
Changes:
- Modified PATH reconstruction logic to distinguish between user additions before (pre) and after (post_user) the original PATH entries
- Updated PATH ordering to preserve the position of paths added after activation:
pre → user_paths → tool_paths → original PATH → post_user - Added regression test to verify appended paths maintain their position
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/cli/hook_env.rs | Splits user PATH additions into pre/post_user to preserve ordering relative to original PATH |
| e2e/config/test_path_post_activate_append | Regression test verifying appended paths stay at the end of PATH |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary of ChangesHello @jdx, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses a critical issue where Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request correctly fixes an issue with $PATH ordering after mise activate. Paths appended after activation are now preserved at the end of $PATH instead of being moved to the front. The logic to split user-added paths into pre and post_user collections is sound, and the new regression test effectively validates the fix. My feedback includes a minor refactoring for code clarity in hook_env.rs and a suggestion to make the new test more robust.
| SYSTEM_POS=$(echo "$PATH" | tr ':' '\n' | grep -n "system/bin" | head -1 | cut -d: -f1) | ||
| APPENDED_POS=$(echo "$PATH" | tr ':' '\n' | grep -n "appended/bin" | head -1 | cut -d: -f1) |
There was a problem hiding this comment.
The grep command could be made more robust by matching the full path with -F (fixed string) instead of a substring. This prevents potential false positives if another directory in PATH contains system/bin or appended/bin.
SYSTEM_POS=$(echo "$PATH" | tr ':' '\n' | grep -nF "$HOME/system/bin" | head -1 | cut -d: -f1)
APPENDED_POS=$(echo "$PATH" | tr ':' '\n' | grep -nF "$HOME/appended/bin" | head -1 | cut -d: -f1)
| let user_additions_set: HashSet<_> = pre.iter().chain(post_user.iter()).collect(); | ||
| let user_additions_canonical: HashSet<PathBuf> = pre | ||
| .iter() | ||
| .chain(post_user.iter()) | ||
| .filter_map(|p| p.canonicalize().ok()) | ||
| .collect(); |
There was a problem hiding this comment.
To avoid creating the pre.iter().chain(post_user.iter()) iterator twice, you could store it in a variable and clone it for creating user_additions_set. This is a minor optimization for cleaner code.
| let user_additions_set: HashSet<_> = pre.iter().chain(post_user.iter()).collect(); | |
| let user_additions_canonical: HashSet<PathBuf> = pre | |
| .iter() | |
| .chain(post_user.iter()) | |
| .filter_map(|p| p.canonicalize().ok()) | |
| .collect(); | |
| let user_additions_iter = pre.iter().chain(post_user.iter()); | |
| let user_additions_set: HashSet<_> = user_additions_iter.clone().collect(); | |
| let user_additions_canonical: HashSet<PathBuf> = user_additions_iter | |
| .filter_map(|p| p.canonicalize().ok()) | |
| .collect(); |
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.12 x -- echo |
20.0 ± 0.3 | 19.4 | 22.3 | 1.00 |
mise x -- echo |
20.3 ± 0.7 | 19.5 | 29.4 | 1.02 ± 0.04 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.12 env |
19.4 ± 0.4 | 18.8 | 24.2 | 1.00 |
mise env |
20.3 ± 1.0 | 19.0 | 31.3 | 1.04 ± 0.06 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.12 hook-env |
20.5 ± 0.6 | 19.6 | 22.9 | 1.00 ± 0.03 |
mise hook-env |
20.4 ± 0.4 | 19.7 | 22.0 | 1.00 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.12 ls |
18.0 ± 0.3 | 17.4 | 19.4 | 1.00 |
mise ls |
18.1 ± 0.3 | 17.4 | 19.8 | 1.01 ± 0.02 |
xtasks/test/perf
| Command | mise-2026.1.12 | mise | Variance |
|---|---|---|---|
| install (cached) | 111ms | 112ms | +0% |
| ls (cached) | 70ms | 70ms | +0% |
| bin-paths (cached) | 74ms | 74ms | +0% |
| task-ls (cached) | 542ms | 539ms | +0% |
### 🚀 Features - **(edit)** add interactive config editor (`mise edit`) by @jdx in [#7930](#7930) - **(lockfile)** graduate lockfiles from experimental by @jdx in [#7929](#7929) - **(task)** add support for usage values in task confirm dialog by @roele in [#7924](#7924) - **(task)** improve source freshness checking with edge case handling by @jdx in [#7932](#7932) ### 🐛 Bug Fixes - **(activate)** preserve ordering of paths appended after mise activate by @jdx in [#7919](#7919) - **(install)** sort failed installations for deterministic error output by @jdx in [#7936](#7936) - **(lockfile)** preserve URL and prefer sha256 when merging platform info by @jdx in [#7923](#7923) - **(lockfile)** add atomic writes and cache invalidation by @jdx in [#7927](#7927) - **(templates)** use sha256 for hash filter instead of blake3 by @jdx in [#7925](#7925) - **(upgrade)** respect tracked configs when pruning old versions by @jdx in [#7926](#7926) ### 🚜 Refactor - **(progress)** migrate from indicatif to clx by @jdx in [#7928](#7928) ### 📚 Documentation - improve clarity on uvx and pipx dependencies by @ygormutti in [#7878](#7878) ### ⚡ Performance - **(install)** use Kahn's algorithm for dependency scheduling by @jdx in [#7933](#7933) - use Aho-Corasick for efficient redaction by @jdx in [#7931](#7931) ### 🧪 Testing - remove flaky test_http_version_list test by @jdx in [#7934](#7934) ### Chore - use github backend instead of ubi in mise.lock by @jdx in [#7922](#7922) ### New Contributors - @ygormutti made their first contribution in [#7878](#7878)
## Summary - `hook-env` always restored `__MISE_ORIG_PATH` order when reconstructing PATH, discarding any reordering done after activation - This broke scenarios where `~/.zlogin` (runs after `~/.zshrc`) moves a PATH entry to the front for priority - Now collects orig paths in their current order to preserve post-activation reordering, while still appending any missing orig paths as a safety net Fixes #8188 Fixes #8168 Builds on the earlier fix in #7919 (commit 9e021af) which handled paths *appended* after activation but didn't handle *reordering* of existing orig paths. ## Test plan - [x] Added `e2e/env/test_path_reorder_after_activate` regression test - [x] Verified test **fails** without the fix (mytool/bin pushed to position 5) and **passes** with it (stays at position 1) - [x] Existing `test_path_post_activate_append` still passes - [x] Existing `test_path_interleaved_regression` still passes - [x] All 477 unit tests pass - [x] All linting passes 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches PATH-building logic in `hook-env`, which affects shell environments broadly; bugs could reorder/omit PATH entries and break command resolution across shells. > > **Overview** > Fixes `hook-env` PATH reconstruction so it preserves the *current ordering* of entries that were present in `__MISE_ORIG_PATH`, instead of always restoring the original captured order; it still appends any missing original entries as a safety net. > > Adds an E2E regression test (`e2e/env/test_path_reorder_after_activate`) that simulates post-activation PATH reordering and asserts `hook-env` does not undo it. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8eed0ce. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
jdx#7919) ## Summary - Paths added to `$PATH` after `eval "$(mise activate)"` in shell rc files were being moved to the front of PATH instead of staying at the end - Split user additions into `pre` (before original PATH entries) and `post_user` (after) to preserve their intended position - Final PATH order: `pre → user_paths → tool_paths → original PATH → post_user` Fixes jdx#7694 ## Test plan - [x] Added `e2e/config/test_path_post_activate_append` regression test - [x] Existing `test_env_path_ordering` still passes - [x] Full e2e test suite passes - [x] All 435 unit tests pass - [x] Linting passes 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes `hook-env` PATH reconstruction logic, which can affect command/tool resolution across shells and projects; risk is mitigated by an added e2e regression test but could still impact edge-case PATH layouts. > > **Overview** > Fixes a regression where PATH entries appended *after* `mise activate` could be moved to the front when `mise hook-env` rebuilt PATH. > > `hook-env` now splits post-activation user additions into shell *prepends* (`pre`) vs shell *appends* (`post_user`) and reconstructs PATH as `pre → user_paths → tool_paths → original PATH → post_user`, while de-duping against both pre/appended user additions. > > Adds an e2e regression test (`e2e/config/test_path_post_activate_append`) to ensure appended paths remain after the original PATH and do not change command priority. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 5cf7c06. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
### 🚀 Features - **(edit)** add interactive config editor (`mise edit`) by @jdx in [jdx#7930](jdx#7930) - **(lockfile)** graduate lockfiles from experimental by @jdx in [jdx#7929](jdx#7929) - **(task)** add support for usage values in task confirm dialog by @roele in [jdx#7924](jdx#7924) - **(task)** improve source freshness checking with edge case handling by @jdx in [jdx#7932](jdx#7932) ### 🐛 Bug Fixes - **(activate)** preserve ordering of paths appended after mise activate by @jdx in [jdx#7919](jdx#7919) - **(install)** sort failed installations for deterministic error output by @jdx in [jdx#7936](jdx#7936) - **(lockfile)** preserve URL and prefer sha256 when merging platform info by @jdx in [jdx#7923](jdx#7923) - **(lockfile)** add atomic writes and cache invalidation by @jdx in [jdx#7927](jdx#7927) - **(templates)** use sha256 for hash filter instead of blake3 by @jdx in [jdx#7925](jdx#7925) - **(upgrade)** respect tracked configs when pruning old versions by @jdx in [jdx#7926](jdx#7926) ### 🚜 Refactor - **(progress)** migrate from indicatif to clx by @jdx in [jdx#7928](jdx#7928) ### 📚 Documentation - improve clarity on uvx and pipx dependencies by @ygormutti in [jdx#7878](jdx#7878) ### ⚡ Performance - **(install)** use Kahn's algorithm for dependency scheduling by @jdx in [jdx#7933](jdx#7933) - use Aho-Corasick for efficient redaction by @jdx in [jdx#7931](jdx#7931) ### 🧪 Testing - remove flaky test_http_version_list test by @jdx in [jdx#7934](jdx#7934) ### Chore - use github backend instead of ubi in mise.lock by @jdx in [jdx#7922](jdx#7922) ### New Contributors - @ygormutti made their first contribution in [jdx#7878](jdx#7878)
## Summary - `hook-env` always restored `__MISE_ORIG_PATH` order when reconstructing PATH, discarding any reordering done after activation - This broke scenarios where `~/.zlogin` (runs after `~/.zshrc`) moves a PATH entry to the front for priority - Now collects orig paths in their current order to preserve post-activation reordering, while still appending any missing orig paths as a safety net Fixes jdx#8188 Fixes jdx#8168 Builds on the earlier fix in jdx#7919 (commit 9e021af) which handled paths *appended* after activation but didn't handle *reordering* of existing orig paths. ## Test plan - [x] Added `e2e/env/test_path_reorder_after_activate` regression test - [x] Verified test **fails** without the fix (mytool/bin pushed to position 5) and **passes** with it (stays at position 1) - [x] Existing `test_path_post_activate_append` still passes - [x] Existing `test_path_interleaved_regression` still passes - [x] All 477 unit tests pass - [x] All linting passes 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches PATH-building logic in `hook-env`, which affects shell environments broadly; bugs could reorder/omit PATH entries and break command resolution across shells. > > **Overview** > Fixes `hook-env` PATH reconstruction so it preserves the *current ordering* of entries that were present in `__MISE_ORIG_PATH`, instead of always restoring the original captured order; it still appends any missing original entries as a safety net. > > Adds an E2E regression test (`e2e/env/test_path_reorder_after_activate`) that simulates post-activation PATH reordering and asserts `hook-env` does not undo it. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8eed0ce. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
$PATHaftereval "$(mise activate)"in shell rc files were being moved to the front of PATH instead of staying at the endpre(before original PATH entries) andpost_user(after) to preserve their intended positionpre → user_paths → tool_paths → original PATH → post_userFixes #7694
Test plan
e2e/config/test_path_post_activate_appendregression testtest_env_path_orderingstill passes🤖 Generated with Claude Code
Note
Medium Risk
Changes
hook-envPATH reconstruction logic, which can affect command/tool resolution across shells and projects; risk is mitigated by an added e2e regression test but could still impact edge-case PATH layouts.Overview
Fixes a regression where PATH entries appended after
mise activatecould be moved to the front whenmise hook-envrebuilt PATH.hook-envnow splits post-activation user additions into shell prepends (pre) vs shell appends (post_user) and reconstructs PATH aspre → user_paths → tool_paths → original PATH → post_user, while de-duping against both pre/appended user additions.Adds an e2e regression test (
e2e/config/test_path_post_activate_append) to ensure appended paths remain after the original PATH and do not change command priority.Written by Cursor Bugbot for commit 5cf7c06. This will update automatically on new commits. Configure here.