Skip to content

feat(init): interactive fzf worktree picker + fix zsh locale error (#134)#136

Merged
helizaga merged 4 commits intomainfrom
feat/fzf-worktree-picker
Feb 24, 2026
Merged

feat(init): interactive fzf worktree picker + fix zsh locale error (#134)#136
helizaga merged 4 commits intomainfrom
feat/fzf-worktree-picker

Conversation

@karan925
Copy link
Contributor

@karan925 karan925 commented Feb 24, 2026

Summary

  • gtr cd (no args) opens an interactive fzf picker with git log preview and keybindings for editor, AI, delete, copy, and refresh
  • Graceful fallback with usage hint when fzf is not installed
  • Fixes gtr cd fails with locale error for branch names containing hyphen ranges (e.g. fix-cron) #134emulate -L zsh prevents locale errors with hyphenated branch names (e.g. fix-cron, test-app)
  • Fixes pre-existing set -e bug in doctor where detect_provider failure aborted the entire command

Test plan

  • bats tests/ — 282 tests pass (7 new tests for fzf output, fallback messages, --as substitution)
  • Manual: gtr cd no-args fallback in bash and zsh (no fzf installed)
  • Manual: gtr doctor fzf check in repos with and without remotes
  • Manual: zsh function with EXTENDED_GLOB + hyphenated branch names (fix-cron, test-app, update-branch)
  • Manual: gtr help init and gtr help show fzf docs

🤖 Generated with Claude Code

karan925 and others added 2 commits February 24, 2026 01:16
When `gtr cd` is called with no arguments and fzf is installed, an
interactive picker launches showing all worktrees with a git log + status
preview pane. Gracefully falls back to printing the worktree list with a
hint when fzf is not available. Supported in bash, zsh, and fish shells.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@coderabbitai
Copy link

coderabbitai bot commented Feb 24, 2026

Walkthrough

The changes introduce an interactive command palette for the gtr cd command using fzf, enabling users to select worktrees with multiple key bindings (edit, AI, delete, copy, refresh). The feature is implemented across bash, zsh, and fish shells in the init script, with corresponding documentation and diagnostic tooling updates.

Changes

Cohort / File(s) Summary
Documentation & Help
README.md, lib/commands/help.sh
Added descriptions of the interactive gtr cd command palette when fzf is available, including keybindings, preview functionality, and workflow examples. Also documents naming conflicts with GNU coreutils tr and the --as option for aliasing.
Core Implementation
lib/commands/init.sh
Implements interactive worktree selection flow for gtr cd without arguments across bash, zsh, and fish shells. Integrates fzf with git gtr list --porcelain, multiple keybindings, and preview pane showing status and logs. Falls back to existing non-interactive path if fzf unavailable.
Diagnostic Support
lib/commands/doctor.sh
Adds optional fzf availability check that prints version if installed or installation guidance if not, positioned after repository checks.

Sequence Diagram

sequenceDiagram
    participant User
    participant Shell
    participant fzf
    participant GitRepo as Git Repository
    participant TargetDir as Target Worktree

    User->>Shell: gtr cd (no args)
    Shell->>Shell: Check if fzf installed
    alt fzf available
        Shell->>Shell: Generate worktree list via git gtr list
        Shell->>fzf: Launch with list + keybindings + preview
        fzf->>GitRepo: Preview: fetch status & logs
        GitRepo-->>fzf: Return git data
        fzf->>fzf: User selects/performs action
        User->>fzf: Select directory / Edit / AI / Delete / Copy / Refresh
        fzf->>Shell: Return selected directory (first field)
        Shell->>TargetDir: cd to selected worktree
        TargetDir-->>Shell: Navigation complete
        Shell-->>User: Display new directory
    else fzf not available
        Shell->>Shell: Fall back to existing go path resolution
        Shell->>TargetDir: cd via standard path
        TargetDir-->>Shell: Navigation complete
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Hop through the workspaces, let fzf shine,
Gtr cd unveils a palette so fine,
Edit, enhance, delete with a keystroke—
Interactive picking brings joy to each stroke!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add FZF support for handling worktrees' accurately summarizes the main change—adding fzf interactive picker functionality for navigating worktrees in the gtr cd command across documentation, help, init, and doctor commands.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/fzf-worktree-picker

Comment @coderabbitai help to get the list of available commands and usage tips.

@helizaga helizaga marked this pull request as ready for review February 24, 2026 16:59
@helizaga helizaga requested a review from NatoBoram as a code owner February 24, 2026 16:59
…d branch names

Fixes #134 — zsh interprets hyphens in branch names (e.g. fix-cron) as
character ranges under non-C locales, causing "range-endpoints in reverse
collating sequence order" errors. `emulate -L zsh` resets all zsh options
to defaults within the function scope.

Also adds fzf install hint when `gtr cd` is called with no args and fzf
is not available, and deduplicates a README line.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
lib/commands/init.sh (4)

279-302: Same no-fzf fallback concern applies to the fish implementation.

The fish implementation correctly uses fish idioms (type -q fzf, string split, or return 0). The same recommendation about a fallback message when fzf is unavailable and gtr cd is called with no arguments applies here (line 300 will pass no additional args to git gtr go).

Proposed fallback for fish
     if test (count $argv) -eq 1; and type -q fzf
       # ... fzf block ...
+    else if test (count $argv) -eq 1
+      echo "Install fzf for interactive worktree picker: https://github.com/junegunn/fzf" >&2
+      echo "" >&2
+      command git gtr list
+      return 1
     else
       set dir (command git gtr go $argv[2..])
       or return $status
     end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/commands/init.sh` around lines 279 - 302, The fish implementation lacks a
user-friendly fallback when fzf is not installed and the command is invoked with
no arguments: detect the case where type -q fzf is false and (count $argv) -eq 1
(i.e., no path arg provided), then print a clear message to the user (e.g., "fzf
not available; please pass a directory or install fzf") and return 0 instead of
falling through to calling git gtr go with no args; update the block around the
_gtr_selection logic (references: type -q fzf, _gtr_selection, git gtr go) to
handle this early-return fallback.

97-101: ctrl-d delete action: consider adding --yes or documenting TTY behavior.

The ctrl-d binding runs git gtr rm {2} which triggers a confirmation prompt by default. While fzf's execute() does suspend and connect to the terminal (so the prompt works), this may be surprising UX — the user presses ctrl-d inside fzf, fzf suspends, a separate confirmation prompt appears, and then fzf resumes and reloads.

If this is intentional (keeping the safety prompt), it's fine — just noting it as a deliberate design choice. If you'd prefer a smoother flow, you could add --yes and rely on ctrl-d being the explicit confirmation:

-        --bind='ctrl-d:execute(git gtr rm {2})+reload(git gtr list --porcelain)' \
+        --bind='ctrl-d:execute(git gtr rm {2} --yes)+reload(git gtr list --porcelain)' \

This applies to all three shell implementations (bash line 99, zsh line 194, fish line 293).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/commands/init.sh` around lines 97 - 101, The ctrl-d fzf binding currently
runs "git gtr rm {2}" which invokes an interactive confirmation and suspends
fzf; decide whether to keep the safety prompt or make the flow smoother: either
add the non-interactive flag (e.g., pass --yes to the removal command) to the
ctrl-d binding that executes git gtr rm {2} so it will not prompt, or document
the existing behavior in the binding comment; update the binding that contains
--bind='ctrl-d:execute(git gtr rm {2})+reload(git gtr list --porcelain)'
accordingly and apply the same change to the zsh and fish equivalents.

180-201: Same no-fzf fallback concern applies here.

The zsh implementation mirrors the bash block. The same recommendation about adding a user-friendly fallback when fzf is unavailable and no arguments are given applies here (line 200 will pass no args to git gtr go).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/commands/init.sh` around lines 180 - 201, When no arguments are given and
fzf is unavailable the script currently falls through to calling git gtr go with
no args; instead detect that case and present a friendly fallback: if [ "$#" -eq
0 ] && ! command -v fzf >/dev/null 2>&1 then print a short user-facing message
(suggest installing fzf or show how to call the command), or print the output of
git gtr list --porcelain (or a human-readable header plus that list) and exit 0;
modify the branch around the _gtr_selection handling so the variables
_gtr_selection and dir assignment remain unchanged when fzf exists, but when fzf
is missing and $# is 0 do the user-friendly print/list and return rather than
calling git gtr go "$@".

85-106: Solid fzf integration with minor UX improvement opportunity.

The interactive picker is well-implemented: porcelain format is correctly parsed (pathbranchstatus), fzf field references ({1} for path, {2} for branch) are accurate, and the keybindings + preview pane provide good UX.

One minor improvement: when fzf is not installed and the user runs gtr cd with no arguments, the code falls through to git gtr go "$@" (line 105) with no arguments, which exits with a usage error. Consider providing a more helpful fallback:

elif [ "$#" -eq 0 ]; then
  echo "Install fzf for interactive picker: https://github.com/junegunn/fzf" >&2
  command git gtr list
  return 1

This lets users see available worktrees when fzf is unavailable, rather than just seeing an error.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/commands/init.sh` around lines 85 - 106, When fzf is not installed the
else branch falls through to calling git gtr go "$@" which errors when there are
no args; update the else branch to detect if "$#" -eq 0 and in that case print a
short stderr hint about installing fzf (e.g., "Install fzf for interactive
picker: https://github.com/junegunn/fzf"), invoke git gtr list to show available
worktrees, and return 1, otherwise keep the existing fallback behavior of
calling git gtr go "$@" (refer to the current use of "$#" check, git gtr go, and
git gtr list in the snippet).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@README.md`:
- Around line 221-225: Remove the duplicated example of the "gtr cd" interactive
picker so only one entry remains; keep a single "gtr cd" line (and its
follow-ups like "gtr cd my-feature" / "gtr cd 1") and make the comment text
consistent (choose either "Interactive worktree picker (requires fzf)" or
"interactive picker (requires fzf)" and apply it to the remaining entry) to
eliminate redundancy and capitalization inconsistency.

---

Nitpick comments:
In `@lib/commands/init.sh`:
- Around line 279-302: The fish implementation lacks a user-friendly fallback
when fzf is not installed and the command is invoked with no arguments: detect
the case where type -q fzf is false and (count $argv) -eq 1 (i.e., no path arg
provided), then print a clear message to the user (e.g., "fzf not available;
please pass a directory or install fzf") and return 0 instead of falling through
to calling git gtr go with no args; update the block around the _gtr_selection
logic (references: type -q fzf, _gtr_selection, git gtr go) to handle this
early-return fallback.
- Around line 97-101: The ctrl-d fzf binding currently runs "git gtr rm {2}"
which invokes an interactive confirmation and suspends fzf; decide whether to
keep the safety prompt or make the flow smoother: either add the non-interactive
flag (e.g., pass --yes to the removal command) to the ctrl-d binding that
executes git gtr rm {2} so it will not prompt, or document the existing behavior
in the binding comment; update the binding that contains
--bind='ctrl-d:execute(git gtr rm {2})+reload(git gtr list --porcelain)'
accordingly and apply the same change to the zsh and fish equivalents.
- Around line 180-201: When no arguments are given and fzf is unavailable the
script currently falls through to calling git gtr go with no args; instead
detect that case and present a friendly fallback: if [ "$#" -eq 0 ] && ! command
-v fzf >/dev/null 2>&1 then print a short user-facing message (suggest
installing fzf or show how to call the command), or print the output of git gtr
list --porcelain (or a human-readable header plus that list) and exit 0; modify
the branch around the _gtr_selection handling so the variables _gtr_selection
and dir assignment remain unchanged when fzf exists, but when fzf is missing and
$# is 0 do the user-friendly print/list and return rather than calling git gtr
go "$@".
- Around line 85-106: When fzf is not installed the else branch falls through to
calling git gtr go "$@" which errors when there are no args; update the else
branch to detect if "$#" -eq 0 and in that case print a short stderr hint about
installing fzf (e.g., "Install fzf for interactive picker:
https://github.com/junegunn/fzf"), invoke git gtr list to show available
worktrees, and return 1, otherwise keep the existing fallback behavior of
calling git gtr go "$@" (refer to the current use of "$#" check, git gtr go, and
git gtr list in the snippet).

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c74f843 and 40005e9.

📒 Files selected for processing (4)
  • README.md
  • lib/commands/doctor.sh
  • lib/commands/help.sh
  • lib/commands/init.sh

detect_provider returns non-zero in repos without remotes, causing
set -e to abort cmd_doctor before reaching the fzf and summary checks.
@helizaga helizaga changed the title Add FZF support for handling worktrees feat(init): interactive fzf worktree picker + fix zsh locale error (#134) Feb 24, 2026
@helizaga helizaga merged commit daee0c1 into main Feb 24, 2026
4 checks passed
@helizaga helizaga deleted the feat/fzf-worktree-picker branch February 24, 2026 17:12
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.

gtr cd fails with locale error for branch names containing hyphen ranges (e.g. fix-cron)

2 participants