Skip to content

shellenv: emit zsh fpath in nested/child shells#21884

Open
sumanthratna wants to merge 10 commits intoHomebrew:mainfrom
sumanthratna:shellenv-fpath
Open

shellenv: emit zsh fpath in nested/child shells#21884
sumanthratna wants to merge 10 commits intoHomebrew:mainfrom
sumanthratna:shellenv-fpath

Conversation

@sumanthratna
Copy link
Copy Markdown

The early-return idempotency check skipped all output when PATH already contained Homebrew's bin/sbin. Unlike PATH, zsh's fpath is a shell-local array not inherited by child processes, so completions broke in tmux/zellij panes and nested zsh shells.

Move shell detection before the early return and always emit the fpath line for zsh.

Fixes #21879


  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same change?
  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests (excluding integration tests) for your changes? Here's an example.
  • Have you successfully run brew lgtm (style, typechecking and tests) with your changes locally?
    • yes; brew lgtm complains about unrelated typechecking config
==> brew style --changed --fix
Library/Homebrew/test/cmd/shellenv_spec.rb:1:1: C: Sorbet/StrictSigil: Sorbet sigil should be at least strict got false.
# typed: false
^^^^^^^^^^^^^^
Library/Homebrew/test/cmd/shellenv_spec.rb:1:1: C: Sorbet/TrueSigil: Sorbet sigil should be at least true got false.
# typed: false
^^^^^^^^^^^^^^

  • AI was used to generate or assist with generating this PR. Please specify below how you used AI to help you, and what steps you have taken to manually verify the changes.
    • Claude Code (Opus 4.6 (1M context) with high effort) was used to read the issue, explore the relevant source code (shellenv.sh, shellenv_spec.rb, bin/brew), design the fix, and implement the changes.
    • The changes were manually verified by:
      1. Smoke-testing brew shellenv zsh with PATH set to trigger the early return — confirmed it now emits the fpath[1,0]= line (previously produced zero output)
      2. Smoke-testing brew shellenv bash with the same PATH — confirmed it still produces no output on early return (no regression)
      3. Running brew style, brew typecheck, and brew tests --only=cmd/shellenv — all pass

The early-return idempotency check skipped all output when PATH
already contained Homebrew's bin/sbin. Unlike PATH, zsh's fpath is
a shell-local array not inherited by child processes, so completions
broke in tmux/zellij panes and nested zsh shells.

Move shell detection before the early return and always emit the
fpath line for zsh.

Fixes Homebrew#21879
Copilot AI review requested due to automatic review settings April 1, 2026 18:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes brew shellenv for zsh in nested/child shells by ensuring the zsh fpath initialization is still emitted even when the PATH idempotency/early-return condition is met (so zsh completions work in tmux/zellij panes and nested zsh sessions).

Changes:

  • Move shell detection ahead of the PATH-based early return in shellenv.sh.
  • When early return triggers, still emit the fpath[1,0]=... line for zsh.
  • Add an integration spec asserting fpath output for brew shellenv zsh even when PATH already contains the Homebrew prefix.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
Library/Homebrew/cmd/shellenv.sh Reorders early-return logic and ensures zsh fpath is emitted in the idempotent PATH case.
Library/Homebrew/test/cmd/shellenv_spec.rb Adds an integration test covering the zsh fpath output when PATH already includes Homebrew.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

The unconditional fpath[1,0]= caused duplicate entries when
brew shellenv zsh was evaluated from both .zprofile and .zshrc
in the same login shell. Use zsh's ${fpath[(Ie)...]} exact-match
lookup so the directory is only prepended when not already present.
Deduplicate Homebrew's zsh site-functions entry while always moving it
to the front of fpath. This keeps repeated `brew shellenv zsh` evals
returning success and preserves Homebrew's completion precedence.

Add a regression test for the pre-existing non-first fpath case.
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.

brew shellenv idempotency check skips fpath setup in child/nested zsh shells

2 participants