From bfabdbc278bb89b29c7d0a94c5a032ef00bbb110 Mon Sep 17 00:00:00 2001 From: maliv2 <259173856+maliv2@users.noreply.github.com> Date: Wed, 14 Oct 2026 20:53:08 +0300 Subject: [PATCH] [Fix] `nvm use`: do not pile up `PATH` entries in nested sessions `nvm_change_path` prepends the new version (instead of replacing the existing nvm path) when a system bin dir precedes an nvm path, to handle macOS `path_helper` reordering the `PATH` of nested sessions (#1652). However, the check matched a system dir followed by *any* nvm path. Once a stale nvm path sits after the system dirs (e.g. inherited by a nested shell, tmux, or an editor's terminal), the check stays true forever, so every `nvm use` prepends yet another entry and the previously used version is never removed from the `PATH`. Only consider the first nvm path: if it is not preceded by a system bin dir, replace it in place as usual. Fixes #3561 --- nvm.sh | 9 +++++---- test/fast/Unit tests/nvm_change_path | 13 +++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/nvm.sh b/nvm.sh index 990506ed..2d503d7a 100755 --- a/nvm.sh +++ b/nvm.sh @@ -1556,11 +1556,12 @@ nvm_change_path() { && ! nvm_echo "${1-}" | nvm_grep -Eq "${NVM_DIR_RE}/versions/[^/]*/[^/]*${2-}"; then nvm_echo "${3-}${2-}:${1-}" # if the initial path contains BOTH an nvm path (checked for above) and - # that nvm path is preceded by a system binary path, just prepend the - # supplementary path instead of replacing it. + # the first nvm path is preceded by a system binary path, just prepend the + # supplementary path instead of replacing it. Only what precedes the first + # nvm path counts, so that a shadowed nvm path further on does not make + # every change prepend yet another entry. # https://github.com/nvm-sh/nvm/issues/1652#issuecomment-342571223 - elif nvm_echo "${1-}" | nvm_grep -Eq "(^|:)(/usr(/local)?)?${2-}:.*${NVM_DIR_RE}/[^/]*${2-}" \ - || nvm_echo "${1-}" | nvm_grep -Eq "(^|:)(/usr(/local)?)?${2-}:.*${NVM_DIR_RE}/versions/[^/]*/[^/]*${2-}"; then + elif nvm_echo "${1%%"${NVM_DIR}"/*}" | nvm_grep -Eq "(^|:)(/usr(/local)?)?${2-}:"; then nvm_echo "${3-}${2-}:${1-}" # use sed to replace the existing nvm path with the supplementary path. This # preserves the order of the path. diff --git a/test/fast/Unit tests/nvm_change_path b/test/fast/Unit tests/nvm_change_path index b690b6df..4871b6c6 100755 --- a/test/fast/Unit tests/nvm_change_path +++ b/test/fast/Unit tests/nvm_change_path @@ -70,3 +70,16 @@ NEW_PATH=`nvm_change_path "$MAC_OS_NESTED_SESSION_PATH" "/bin" "$NVM_DIR/version NEW_PATH=`nvm_change_path "$MAC_OS_NESTED_SESSION_PATH" "/bin" "$NVM_DIR/v0.1.2"` [ "$NEW_PATH" = "$NVM_DIR/v0.1.2/bin:/usr/bin:/usr/local/bin:$NVM_DIR/versions/node/v4.5.0/bin" ] || die "Not correctly changed: $NEW_PATH " + +# an nvm path that was already prepended ahead of the system paths is replaced, +# rather than piling up another entry on every change +# https://github.com/nvm-sh/nvm/issues/3561 +PREPENDED_NESTED_SESSION_PATH=$NVM_DIR/versions/node/v7.1.0/bin:/usr/bin:/usr/local/bin:$NVM_DIR/versions/node/v4.5.0/bin + +NEW_PATH=`nvm_change_path "$PREPENDED_NESTED_SESSION_PATH" "/bin" "$NVM_DIR/versions/node/v8.0.0"` + +[ "$NEW_PATH" = "$NVM_DIR/versions/node/v8.0.0/bin:/usr/bin:/usr/local/bin:$NVM_DIR/versions/node/v4.5.0/bin" ] || die "Not correctly changed: $NEW_PATH " + +NEW_PATH=`nvm_change_path "$PREPENDED_NESTED_SESSION_PATH" "/bin" "$NVM_DIR/v0.1.2"` + +[ "$NEW_PATH" = "$NVM_DIR/v0.1.2/bin:/usr/bin:/usr/local/bin:$NVM_DIR/versions/node/v4.5.0/bin" ] || die "Not correctly changed: $NEW_PATH "