Skip to content

feat: enhance config command with list action and improved scope handling#68

Merged
helizaga merged 1 commit intocoderabbitai:mainfrom
vampik33:main
Jan 6, 2026
Merged

feat: enhance config command with list action and improved scope handling#68
helizaga merged 1 commit intocoderabbitai:mainfrom
vampik33:main

Conversation

@vampik33
Copy link
Contributor

@vampik33 vampik33 commented Dec 29, 2025

feat: enhance config command with list action and improved scope handling

  • Add git gtr config list action to display all gtr.* configuration with source origins (local/.gtrconfig/global/system)
  • Add --local and --system flags to complement existing --global flag
  • Implement cfg_list() function with proper multi-value support and origin tracking
  • Improve argument validation with warnings for unexpected extra arguments
  • Add cfg_map_to_file_key() for automatic .gtrconfig key mapping
  • Update all shell completions (bash/zsh/fish) with new list action and scope flags
  • Restrict --system flag to read operations only (write requires root)
  • Change default scope to "auto" for merged config views, resolves to "local" for writes
  • Add comprehensive inline documentation for config precedence and behavior

Pull Request

Description

This PR significantly enhances the git gtr config command with improved configuration management capabilities. The key improvements include:

  • New list action: Display all gtr.* configuration with clear source origin labels (local/.gtrconfig/global/system)
  • Enhanced scope control: Added --local and --system flags to complement the existing --global flag
  • Smart scope resolution: Automatically merges config from all sources with "auto" scope (default), while write operations intelligently resolve to "local"
  • Better validation: Warns users about unexpected extra arguments instead of silently ignoring them
  • Automatic key mapping: New cfg_map_to_file_key() function automatically maps between gtr.* keys and .gtrconfig file keys
  • Complete shell integration: Updated all three shell completions (bash/zsh/fish) with new actions and scope-aware completions

Motivation

Users previously had no easy way to:

  1. View all their gtr configuration at once
  2. Understand where each config value was coming from (local vs global vs .gtrconfig)
  3. Use --local or --system scopes explicitly (only --global was supported)
  4. Know when they provided incorrect arguments to config commands

This PR addresses these UX gaps and provides a foundation for better configuration debugging and team collaboration (via .gtrconfig visibility).

Fixes # (issue)

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring (no functional changes)
  • Other (please describe):

Testing

Manual Testing Checklist

Tested on:

  • macOS
  • Linux (specify distro: CachyOs)
  • Windows (Git Bash)

Core functionality tested:

  • git gtr config list - List all config with origins
  • git gtr config list --local - List local config only
  • git gtr config list --global - List global config only
  • git gtr config list --system - List system config only
  • git gtr config get <key> - Get merged value
  • git gtr config get <key> --local - Get local value
  • git gtr config get <key> --global - Get global value
  • git gtr config set <key> <value> - Set local value (default)
  • git gtr config set <key> <value> --global - Set global value
  • git gtr config set <key> <value> --system - Should error with helpful message
  • git gtr config add <key> <value> - Add multi-value
  • git gtr config unset <key> - Remove config
  • Shell completions work correctly (tab completion for actions and flags)
  • Backward compatibility: existing git gtr config commands still work

Test Steps

Test 1: List all configuration

# Set up some test config
git gtr config set gtr.editor.default cursor
git gtr config set gtr.ai.default claude --global
echo -e "[defaults]\n  editor = vscode" > .gtrconfig

# List all config (should show merged view with origins)
git gtr config list
# Expected: Shows gtr.editor.default from local, global, and .gtrconfig with labels

Test 2: Scoped operations

# Get merged value (auto scope)
git gtr config get gtr.editor.default
# Expected: Shows "cursor" (local takes precedence)

# Get only global value
git gtr config get gtr.editor.default --global
# Expected: Shows "claude" or nothing if not set globally

# List only local config
git gtr config list --local
# Expected: Shows only locally set values

Test 3: Validation warnings

# Provide extra unexpected arguments
git gtr config list some extra args
# Expected: Warning about ignoring extra arguments

# Unset with value (which doesn't make sense)
git gtr config unset gtr.editor.default cursor
# Expected: Warning about ignoring the value argument

Test 4: System scope restrictions

# Try to write to system config
git gtr config set gtr.editor.default vim --system
# Expected: Clear error message about --system not supported for writes

Test 5: Shell completions

# Test bash completion
git gtr config <TAB>
# Expected: Shows "list get set add unset --local --global --system"

# After typing action
git gtr config get <TAB>
# Expected: Shows config keys and scope flags

Expected behavior:
- list action displays formatted output with source origins
- Scope flags work correctly for filtering
- Write operations default to local scope
- System scope is read-only
- Warnings appear for unexpected arguments
- Shell completions suggest appropriate options

Actual behavior:
[To be filled during testing]

## Breaking Changes

- This PR introduces breaking changes

Note: This PR is backward compatible. The default behavior without scope flags remains unchanged. The new list action and additional scope flags are purely additive features.

## Checklist

Before submitting this PR, please check:

- [x] I have read [CONTRIBUTING.md](../CONTRIBUTING.md)
- [x] My code follows the project's style guidelines
- [x] I have performed manual testing on at least one platform
- [x] I have updated documentation (README.md, CLAUDE.md, etc.) if needed
- [x] My changes work on multiple platforms (or I've noted platform-specific behavior)
- [x] I have added/updated shell completions (if adding new commands or flags)
- [x] I have tested with both `git gtr` (production) and `./bin/gtr` (development)
- [x] No new external dependencies are introduced (Bash + git only)
- [x] All existing functionality still works

## Additional Context

Implementation Highlights

cfg_list() function (lib/config.sh):
- Merges config from all sources (local + .gtrconfig + global + system)
- Deduplicates values while preserving all entries for multi-valued keys
- Uses Unit Separator (\x1f) as delimiter to safely handle any value content
- Supports both scoped queries (--local, --global, --system) and merged auto mode
- Maps .gtrconfig keys to gtr.* format for consistent display

cfg_map_to_file_key() function (lib/config.sh):
- Bidirectional mapping between gtr.* keys and .gtrconfig keys
- Enables automatic integration with .gtrconfig file without manual key specification
- Used by cfg_get_all() for transparent .gtrconfig support

Argument parsing improvements (cmd_config() in bin/gtr):
- Flexible argument order (flags can appear anywhere)
- Tracks and warns about unexpected extra arguments
- Default action intelligently chosen: list if no args, get if key provided
- Resolves "auto" scope to "local" for write operations (for clear user feedback)

Shell Completion Updates

All three shell completion systems updated:
- Bash (completions/gtr.bash): Dynamic action detection with scope-aware flag completion
- Zsh (completions/_git-gtr): Argument scanning for flexible flag positioning
- Fish (completions/gtr.fish): Helper functions to detect read vs write operations for scope filtering

Files Changed

- bin/gtr: Enhanced cmd_config() with list action, scope handling, and validation
- lib/config.sh: Added cfg_list() and cfg_map_to_file_key() functions
- completions/gtr.bash: Updated completions with new action and scope flags
- completions/_git-gtr: Updated Zsh completions
- completions/gtr.fish: Updated Fish completions with helper functions

---

## License Acknowledgment

By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache License 2.0](../LICENSE.txt).


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
* Added `config list` action to view all configuration values
* Added `--local`, `--global`, and `--system` scope flags for granular scope control
* Enhanced shell completions with improved suggestions for configuration keys

* **Bug Fixes**
* Prevented using `--system` scope with write operations; users are guided to use `--local` or `--global` instead
* Improved config command validation and error messaging

<sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

@vampik33 vampik33 requested a review from NatoBoram as a code owner December 29, 2025 07:27
@coderabbitai
Copy link

coderabbitai bot commented Dec 29, 2025

Walkthrough

This pull request extends the gtr config command with granular scope control (--local, --global, --system), introduces a new list action to enumerate configurations, and changes the default behavior from get to list when no action is provided. The changes include scope resolution for write operations, validation guards, and corresponding completion updates across all shell environments.

Changes

Cohort / File(s) Summary
Config Command Core
bin/gtr
Enhanced cmd_config function: default scope changed to "auto"; added --local/--system flag support alongside --global; new "list" action with cfg_list integration; scope resolution for write operations (auto → local); guard rejecting --system with write ops; refined usage/error messaging; extra argument handling with warnings per action.
Config Library
lib/config.sh
Added cfg_map_to_file_key to map gtr.\* keys to .gtrconfig equivalents; updated cfg_get_all with auto-mapping; introduced new cfg_list function with multi-source merging (local, .gtrconfig, global, system), origin labeling, and deduplication for multi-valued keys.
Bash Completion
completions/gtr.bash
Replaced fixed positional parsing with dynamic action detection across all config arguments; conditional scope handling: read operations (list/get) allow all scopes; write operations (set/add/unset) restrict to --local/--global; per-action flag and key completion logic.
Zsh Completion
completions/_git-gtr
Similar dynamic action scanning for flexible flag positioning; nested branching for per-action completion; explicit scope flags for read vs. write operations; inline documentation of action detection and scope handling.
Fish Completion
completions/git-gtr.fish
Added "list" action alongside existing actions; introduced helper functions __fish_git_gtr_config_is_read and __fish_git_gtr_config_is_write for action classification; scope flag restrictions (--system limited to read operations); expanded config key suggestions with descriptions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Config scopes now bloom so bright,
With local, global, system in sight,
List them all or get what's there,
Fish and bash complete with care—
New defaults hop, the paths align! 🌱

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main enhancement—adding a list action and improving scope handling for the config command, which aligns with the core changes across all modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

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: 0

🧹 Nitpick comments (3)
lib/config.sh (2)

300-315: Duplicated key mapping logic.

This reverse mapping (.gtrconfig keys → gtr.* keys) duplicates the logic in cfg_map_to_file_key() (lines 83-100). Consider extracting a bidirectional mapping helper or using cfg_map_to_file_key with a reverse lookup to maintain a single source of truth.


317-317: Process substitution < <(...) requires Bash 4.0+.

Process substitution is not available in Bash 3.2 (macOS default). If strict 3.2 compatibility is required, consider using a here-string with command substitution instead:

🔎 Alternative for Bash 3.2 compatibility
-        done < <(git config -f "$config_file" --get-regexp '.' 2>/dev/null || true)
+        local file_entries
+        file_entries=$(git config -f "$config_file" --get-regexp '.' 2>/dev/null || true)
+        done <<< "$file_entries"

However, per coding guidelines, 4.0+ features are allowed where appropriate, so this may be acceptable.

completions/gtr.fish (1)

74-93: Potential false positive in read/write predicates.

The predicates scan the entire command line for action keywords. A branch name like feature-list or add-feature could trigger false positives. Consider checking that the keyword appears after config in the command sequence.

🔎 Suggested improvement
function __fish_git_gtr_config_is_read
  set -l cmd (commandline -opc)
  set -l found_config 0
  for i in $cmd
    if test $found_config -eq 1
      if test "$i" = "list" -o "$i" = "get"
        return 0
      end
    end
    if test "$i" = "config"
      set found_config 1
    end
  end
  return 1
end
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 03ff84a and 685bc6c.

📒 Files selected for processing (7)
  • .serena/.gitignore
  • .serena/project.yml
  • bin/gtr
  • completions/_git-gtr
  • completions/gtr.bash
  • completions/gtr.fish
  • lib/config.sh
🧰 Additional context used
📓 Path-based instructions (13)
lib/**/*.sh

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

lib/**/*.sh: Core libraries (lib/core.sh, lib/config.sh, lib/ui.sh, lib/copy.sh, lib/hooks.sh, lib/platform.sh) must be sourced at startup and implement specific functionality
Maintain backwards compatibility with Git <2.22 by using fallback rev-parse --abbrev-ref HEAD instead of branch --show-current

lib/**/*.sh: Maintain backwards compatibility with existing configs in shell scripts
Quote all paths to support spaces in directory names
Use log_error / log_info from lib/ui.sh for user messages
Implement Git version fallbacks (e.g., Git 2.22+ --show-current vs older rev-parse); check lib/core.sh:97-100 for example
Add new config keys with gtr.<name> prefix to avoid collisions
For performance-sensitive loops (e.g., directory scans), prefer built-ins (find, grep) with minimal subshells
For any new Git command, add fallback for older versions or guard with detection

Files:

  • lib/config.sh
**/*.sh

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.sh: Always quote paths to handle spaces and special characters; avoid unguarded globbing
Keep set -e active in shell scripts; ensure non-critical failures are guarded with command || true

**/*.sh: Use shebang #!/usr/bin/env bash (not /bin/bash or /bin/sh) for all shell scripts
Use snake_case naming for all functions and local variables in Bash scripts
Use UPPER_CASE naming for constants and environment variables in Bash scripts
Use 2-space indentation (no tabs) in all Bash scripts
Always quote variables and paths in Bash scripts (e.g., use "$var" not $var)
Check return codes and use || exit 1 or || return 1 for error handling in Bash scripts
Use local keyword for function-scoped variables in Bash scripts
Maintain POSIX-compatible Bash patterns targeting Bash 3.2+ compatibility
Git worktree operations must work cross-platform on macOS, Linux, and Windows Git Bash
All code must only use git and basic POSIX shell utilities - no external dependencies
Use set -e for error handling in Bash scripts where appropriate

Files:

  • lib/config.sh
lib/config.sh

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

For multi-value git config keys, use git config --add to merge and deduplicate values rather than overwriting the entire list

Configuration keys must use the gtr.* prefix when stored in git config

Files:

  • lib/config.sh
**/*.{bash,fish,sh}

📄 CodeRabbit inference engine (.github/instructions/sh.instructions.md)

**/*.{bash,fish,sh}: Bash 3.2+ compatible (macOS default), but 4.0+ features allowed where appropriate
Always quote variables: use "$var" not $var
Use function-scoped variables: local var="value"
Check return codes; functions return 1 on failure
Use snake_case for functions and variables, UPPER_CASE for constants
Prefer [ ] over [[ ]] for POSIX portability; use [[ only when needed
Always quote glob inputs; disable unintended globbing with set -f temporarily if required
Avoid associative arrays in shell scripts; use simple string/loop constructs for Bash 3.2+ compatibility
Avoid readarray and process substitution unsupported in older Bash
Debug with bash -x ./bin/gtr <cmd> or wrap suspicious blocks with set -x / set +x
Check function presence with declare -f create_worktree or declare -f resolve_target
Use stderr for variable inspection: echo "DEBUG var=$var" >&2 to keep stdout clean for command substitution
Keep dependencies minimal: only use git, sed, awk, find, grep; avoid jq/curl unless justified
Check availability of external commands before use when adding new tools
Use "${var}" for variable expansion; for line loops use while IFS= read -r line; do ... done to preserve spaces
Sanitize branch names via sanitize_branch_name function; do NOT duplicate logic elsewhere
Everything is sourced at startup with set -e enabled; functions call each other directly; no subshells except for hooks and AI tools

Files:

  • lib/config.sh
  • completions/gtr.bash
  • completions/gtr.fish
{bin/gtr,lib/**/*.sh,adapters/**/*.sh}

📄 CodeRabbit inference engine (.github/instructions/testing.instructions.md)

{bin/gtr,lib/**/*.sh,adapters/**/*.sh}: All commands must exit 0 (except intentional failures) and produce expected side-effects
No unquoted path errors; spaces must be handled in file paths
Hooks must run only once per creation/removal event

Files:

  • lib/config.sh
  • bin/gtr
lib/*.sh

📄 CodeRabbit inference engine (CLAUDE.md)

Library functions in lib/*.sh should maintain backwards compatibility with existing configurations

Files:

  • lib/config.sh
bin/gtr

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

bin/gtr: Dispatch commands through cmd_* functions in bin/gtr (case block lines 36‑77)
Update GTR_VERSION on line 8 of bin/gtr when releasing; this affects gtr version / --version output

Global set -e in bin/gtr: guard non-critical commands with || true

list --porcelain output must remain stable for scripting purposes

Update version number in bin/gtr (line 8, GTR_VERSION constant) when releasing a new version

Files:

  • bin/gtr
completions/*

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Shell completion files must be updated for bash, zsh, and fish when commands or adapters are added

Files:

  • completions/gtr.bash
  • completions/gtr.fish
  • completions/_git-gtr
completions/{gtr.bash,_git-gtr,gtr.fish}

📄 CodeRabbit inference engine (.github/instructions/completions.instructions.md)

completions/{gtr.bash,_git-gtr,gtr.fish}: Always update all three completion files (gtr.bash, _git-gtr, gtr.fish) when adding new commands, flags, editors, or AI adapters
Implement command completion in all three completion files to support top-level commands (new, rm, editor, ai, list, etc.) with appropriate tab-completion
Implement flag completion in all three completion files to support command-specific flags (e.g., --from, --force, --editor) with appropriate tab-completion
Implement adapter name completion in all three completion files, listing available editor names (cursor, vscode, zed) and AI tool names (aider, claude, codex) for --editor and --ai flags

Files:

  • completions/gtr.bash
  • completions/gtr.fish
  • completions/_git-gtr
completions/gtr.bash

📄 CodeRabbit inference engine (.github/instructions/completions.instructions.md)

completions/gtr.bash: In completions/gtr.bash, implement command completion using COMPREPLY array and compgen filtering for the current word ($cur)
In completions/gtr.bash, support dynamic branch completion using 'git branch --format='%(refname:short)' and include special ID '1' for main repo

Files:

  • completions/gtr.bash
completions/*.{bash,fish}

📄 CodeRabbit inference engine (CLAUDE.md)

Update shell completion files (completions/gtr.bash, completions/_git-gtr, completions/gtr.fish) when adding new commands or flags

Files:

  • completions/gtr.bash
  • completions/gtr.fish
completions/gtr.fish

📄 CodeRabbit inference engine (.github/instructions/completions.instructions.md)

completions/gtr.fish: In completions/gtr.fish, use custom predicates (__fish_git_gtr_needs_command, __fish_git_gtr_using_command) to handle git subcommand context and detect 'git gtr' usage
In completions/gtr.fish, support dynamic branch completion using 'git branch --format='%(refname:short)' and include special ID '1' for main repo

Files:

  • completions/gtr.fish
completions/_git-gtr

📄 CodeRabbit inference engine (.github/instructions/completions.instructions.md)

completions/_git-gtr: In completions/_git-gtr, use Zsh completion framework with _arguments and _describe/_values for sophisticated completion logic with descriptions and grouping
In completions/_git-gtr, support dynamic branch completion using 'git branch --format='%(refname:short)' and include special ID '1' for main repo

Files:

  • completions/_git-gtr
🪛 Shellcheck (0.11.0)
completions/gtr.bash

[warning] 79-79: Prefer mapfile or read -a to split command output (or quote to avoid splitting).

(SC2207)


[warning] 86-86: Prefer mapfile or read -a to split command output (or quote to avoid splitting).

(SC2207)


[warning] 88-88: Prefer mapfile or read -a to split command output (or quote to avoid splitting).

(SC2207)


[warning] 94-94: Prefer mapfile or read -a to split command output (or quote to avoid splitting).

(SC2207)


[warning] 96-96: Prefer mapfile or read -a to split command output (or quote to avoid splitting).

(SC2207)

🔇 Additional comments (11)
.serena/.gitignore (1)

1-1: LGTM!

Standard gitignore entry for the Serena cache directory.

.serena/project.yml (1)

1-84: LGTM!

Standard Serena project configuration with appropriate settings for a bash-based project.

completions/gtr.bash (1)

68-100: LGTM - Dynamic action detection is a good improvement.

The flexible flag positioning and scope-aware completions align well with the new config command semantics. The SC2207 shellcheck warnings about COMPREPLY=($(compgen ...)) are expected in bash completion scripts—this pattern is idiomatic and the word splitting is intentional here.

One minor observation: the config key lists on lines 88-89 and 96-97 are duplicated. Consider extracting to a variable if the list grows, but this is acceptable for now.

completions/_git-gtr (1)

111-146: LGTM - Consistent with bash completion logic.

The flexible action detection and scope-aware argument handling properly mirrors the bash completion implementation, ensuring a consistent user experience across shells.

lib/config.sh (2)

113-116: Good use of [[ ]] for glob pattern matching.

The [[ "$key" == gtr.* ]] correctly uses double brackets for glob matching. Single brackets [ ] would not work here.


247-268: The trap ... RETURN construct is supported in Bash 3.2 (available since Bash 3.0), so no compatibility issue exists. The helper function pattern with cleanup is well-structured and the Unit Separator delimiter is a clever choice to avoid collisions with config values.

Likely an incorrect or invalid review comment.

completions/gtr.fish (1)

95-114: LGTM - Scope and key completions are well-structured.

The scope flags are correctly restricted (--system only for read operations), and the config key list with descriptions provides good UX. The keys are consistent with the bash and zsh completion files.

bin/gtr (4)

1053-1069: LGTM - Scope resolution and validation logic is well-designed.

The auto → local resolution for write operations and the explicit rejection of --system for writes are appropriate. This provides sensible defaults while preventing accidental system-level modifications that require elevated privileges.


1044-1051: LGTM - Smart default action selection.

Defaulting to list when no action/key is provided and get when a key is provided creates an intuitive UX that matches common CLI patterns.


1119-1126: LGTM - List action implementation.

The warning for unexpected arguments and delegation to cfg_list with proper scope handling is clean.


1282-1292: LGTM - Help text accurately reflects the new command syntax.

The updated usage examples clearly show the scope options and the distinction between read and write operations.

@helizaga
Copy link
Collaborator

helizaga commented Jan 5, 2026

lgtm. rebase to main

…ling

- Add `git gtr config list` action to display all gtr.* configuration with source origins (local/.gtrconfig/global/system)
- Add --local and --system flags to complement existing --global flag
- Implement cfg_list() function with proper multi-value support and origin tracking
- Improve argument validation with warnings for unexpected extra arguments
- Add cfg_map_to_file_key() for automatic .gtrconfig key mapping
- Update all shell completions (bash/zsh/fish) with new list action and scope flags
- Restrict --system flag to read operations only (write requires root)
- Change default scope to "auto" for merged config views, resolves to "local" for writes
- Add comprehensive inline documentation for config precedence and behavior

Co-authored-by: Vladislav Dobromyslov <vladik.dobrik@gmail.com>
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

Fix all issues with AI Agents 🤖
In @lib/config.sh:
- Line 317: Replace the process substitution used in the loop terminator "done <
<(git config -f \"$config_file\" --get-regexp '.' 2>/dev/null || true)" with the
file's existing Bash 3.2-compatible variable assignment pattern: capture the
output of the git command into a temporary variable (like the pattern used
around line 321), then feed that variable into the while/read loop (e.g., via a
here-string or printf piping); update the loop to read from that variable
instead of using < <(...), ensuring stderr is still redirected to /dev/null and
behavior remains identical.
🧹 Nitpick comments (1)
lib/config.sh (1)

300-316: Refactor to use cfg_map_to_file_key for consistency.

This case statement duplicates the inverse mapping logic of cfg_map_to_file_key. Consider creating an inverse function (e.g., cfg_map_from_file_key) to reduce duplication and ensure consistency.

🔎 Proposed refactor

Create an inverse mapping function and use it here:

+# Map a .gtrconfig key to its gtr.* equivalent (inverse of cfg_map_to_file_key)
+cfg_map_from_file_key() {
+  local fkey="$1"
+  case "$fkey" in
+    copy.include)     echo "gtr.copy.include" ;;
+    copy.exclude)     echo "gtr.copy.exclude" ;;
+    copy.includeDirs) echo "gtr.copy.includeDirs" ;;
+    copy.excludeDirs) echo "gtr.copy.excludeDirs" ;;
+    hooks.postCreate) echo "gtr.hook.postCreate" ;;
+    hooks.preRemove)  echo "gtr.hook.preRemove" ;;
+    hooks.postRemove) echo "gtr.hook.postRemove" ;;
+    defaults.editor)  echo "gtr.editor.default" ;;
+    defaults.ai)      echo "gtr.ai.default" ;;
+    defaults.branch)  echo "gtr.defaultBranch" ;;
+    worktrees.dir)    echo "gtr.worktrees.dir" ;;
+    worktrees.prefix) echo "gtr.worktrees.prefix" ;;
+    gtr.*)            echo "$fkey" ;;
+    *)                echo "" ;;
+  esac
+}

Then replace lines 300-316 with:

-          # Map .gtrconfig keys to gtr.* format
-          case "$fkey" in
-            copy.include)     mapped_key="gtr.copy.include" ;;
-            copy.exclude)     mapped_key="gtr.copy.exclude" ;;
-            copy.includeDirs) mapped_key="gtr.copy.includeDirs" ;;
-            copy.excludeDirs) mapped_key="gtr.copy.excludeDirs" ;;
-            hooks.postCreate) mapped_key="gtr.hook.postCreate" ;;
-            hooks.preRemove)  mapped_key="gtr.hook.preRemove" ;;
-            hooks.postRemove) mapped_key="gtr.hook.postRemove" ;;
-            defaults.editor)  mapped_key="gtr.editor.default" ;;
-            defaults.ai)      mapped_key="gtr.ai.default" ;;
-            defaults.branch)  mapped_key="gtr.defaultBranch" ;;
-            worktrees.dir)    mapped_key="gtr.worktrees.dir" ;;
-            worktrees.prefix) mapped_key="gtr.worktrees.prefix" ;;
-            gtr.*)            mapped_key="$fkey" ;;
-            *)                continue ;;  # Skip unmapped keys
-          esac
+          # Map .gtrconfig keys to gtr.* format
+          mapped_key=$(cfg_map_from_file_key "$fkey")
+          [ -z "$mapped_key" ] && continue  # Skip unmapped keys
           _cfg_list_add_entry ".gtrconfig" "$mapped_key" "$fvalue"
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 685bc6c and a62b731.

📒 Files selected for processing (5)
  • bin/gtr
  • completions/_git-gtr
  • completions/git-gtr.fish
  • completions/gtr.bash
  • lib/config.sh
🧰 Additional context used
📓 Path-based instructions (12)
lib/**/*.sh

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

lib/**/*.sh: Core libraries (lib/core.sh, lib/config.sh, lib/ui.sh, lib/copy.sh, lib/hooks.sh, lib/platform.sh) must be sourced at startup and implement specific functionality
Maintain backwards compatibility with Git <2.22 by using fallback rev-parse --abbrev-ref HEAD instead of branch --show-current

lib/**/*.sh: Maintain backwards compatibility with existing configs in shell scripts
Quote all paths to support spaces in directory names
Use log_error / log_info from lib/ui.sh for user messages
Implement Git version fallbacks (e.g., Git 2.22+ --show-current vs older rev-parse); check lib/core.sh:97-100 for example
Add new config keys with gtr.<name> prefix to avoid collisions
For performance-sensitive loops (e.g., directory scans), prefer built-ins (find, grep) with minimal subshells
For any new Git command, add fallback for older versions or guard with detection

lib/**/*.sh: Maintain backwards compatibility with existing configurations when modifying core functionality in lib/*.sh files
Follow POSIX-compatible Bash patterns targeting Bash 3.2+ when modifying core functionality in lib/*.sh files
Provide clear error messages via log_error and log_info from lib/ui.sh when modifying core functionality

Files:

  • lib/config.sh
**/*.sh

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.sh: Always quote paths to handle spaces and special characters; avoid unguarded globbing
Keep set -e active in shell scripts; ensure non-critical failures are guarded with command || true

**/*.sh: Use shebang #!/usr/bin/env bash (not /bin/bash or /bin/sh) for Bash scripts
Use snake_case naming for functions in Bash scripts
Use snake_case for local variables and UPPER_CASE for constants/environment variables in Bash scripts
Use 2-space indentation (no tabs) in Bash scripts
Always quote variables and paths in Bash scripts to prevent word splitting and globbing issues
Check return codes and use || exit 1 or || return 1 for error handling in Bash scripts
Use set -e for error handling in Bash scripts
Use local keyword for function-scoped variables in Bash scripts

Files:

  • lib/config.sh
lib/config.sh

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

For multi-value git config keys, use git config --add to merge and deduplicate values rather than overwriting the entire list

Files:

  • lib/config.sh
**/*.{bash,fish,sh}

📄 CodeRabbit inference engine (.github/instructions/sh.instructions.md)

**/*.{bash,fish,sh}: Bash 3.2+ compatible (macOS default), but 4.0+ features allowed where appropriate
Always quote variables: use "$var" not $var
Use function-scoped variables: local var="value"
Check return codes; functions return 1 on failure
Use snake_case for functions and variables, UPPER_CASE for constants
Prefer [ ] over [[ ]] for POSIX portability; use [[ only when needed
Always quote glob inputs; disable unintended globbing with set -f temporarily if required
Avoid associative arrays in shell scripts; use simple string/loop constructs for Bash 3.2+ compatibility
Avoid readarray and process substitution unsupported in older Bash
Debug with bash -x ./bin/gtr <cmd> or wrap suspicious blocks with set -x / set +x
Check function presence with declare -f create_worktree or declare -f resolve_target
Use stderr for variable inspection: echo "DEBUG var=$var" >&2 to keep stdout clean for command substitution
Keep dependencies minimal: only use git, sed, awk, find, grep; avoid jq/curl unless justified
Check availability of external commands before use when adding new tools
Use "${var}" for variable expansion; for line loops use while IFS= read -r line; do ... done to preserve spaces
Sanitize branch names via sanitize_branch_name function; do NOT duplicate logic elsewhere
Everything is sourced at startup with set -e enabled; functions call each other directly; no subshells except for hooks and AI tools

Files:

  • lib/config.sh
  • completions/git-gtr.fish
  • completions/gtr.bash
{bin/gtr,lib/**/*.sh,adapters/**/*.sh}

📄 CodeRabbit inference engine (.github/instructions/testing.instructions.md)

{bin/gtr,lib/**/*.sh,adapters/**/*.sh}: All commands must exit 0 (except intentional failures) and produce expected side-effects
No unquoted path errors; spaces must be handled in file paths
Hooks must run only once per creation/removal event

Files:

  • lib/config.sh
  • bin/gtr
bin/gtr

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

bin/gtr: Dispatch commands through cmd_* functions in bin/gtr (case block lines 36‑77)
Update GTR_VERSION on line 8 of bin/gtr when releasing; this affects gtr version / --version output

Global set -e in bin/gtr: guard non-critical commands with || true

list --porcelain output must remain stable for scripting purposes

bin/gtr: Update bin/gtr version constant (GTR_VERSION) when releasing a new version
Update help text in bin/gtr by searching for 'Available editors:' in cmd_help function and load_editor_adapter function when adding a new editor adapter
Update help text in bin/gtr by searching for 'Available AI tools:' in cmd_help function and load_ai_adapter function when adding a new AI tool adapter

Files:

  • bin/gtr
completions/*

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Shell completion files must be updated for bash, zsh, and fish when commands or adapters are added

Files:

  • completions/_git-gtr
  • completions/git-gtr.fish
  • completions/gtr.bash
completions/{gtr.bash,_git-gtr,gtr.fish}

📄 CodeRabbit inference engine (.github/instructions/completions.instructions.md)

completions/{gtr.bash,_git-gtr,gtr.fish}: Always update all three completion files (gtr.bash, _git-gtr, gtr.fish) when adding new commands, flags, editors, or AI adapters
Implement command completion in all three completion files to support top-level commands (new, rm, editor, ai, list, etc.) with appropriate tab-completion
Implement flag completion in all three completion files to support command-specific flags (e.g., --from, --force, --editor) with appropriate tab-completion
Implement adapter name completion in all three completion files, listing available editor names (cursor, vscode, zed) and AI tool names (aider, claude, codex) for --editor and --ai flags

Files:

  • completions/_git-gtr
  • completions/gtr.bash
completions/_git-gtr

📄 CodeRabbit inference engine (.github/instructions/completions.instructions.md)

completions/_git-gtr: In completions/_git-gtr, use Zsh completion framework with _arguments and _describe/_values for sophisticated completion logic with descriptions and grouping
In completions/_git-gtr, support dynamic branch completion using 'git branch --format='%(refname:short)' and include special ID '1' for main repo

Update shell completion files when adding new commands or flags: completions/gtr.bash, completions/_git-gtr, and completions/git-gtr.fish

Files:

  • completions/_git-gtr
completions/{gtr.bash,_git-gtr,git-gtr.fish}

📄 CodeRabbit inference engine (CLAUDE.md)

completions/{gtr.bash,_git-gtr,git-gtr.fish}: Update completion files (bash, zsh, fish) to include new editor adapter names when adding a new editor adapter
Update completion files (bash, zsh, fish) to include new AI tool names when adding a new AI tool adapter

Files:

  • completions/_git-gtr
  • completions/git-gtr.fish
  • completions/gtr.bash
completions/git-gtr.fish

📄 CodeRabbit inference engine (CLAUDE.md)

Update shell completion files when adding new commands or flags: completions/gtr.bash, completions/_git-gtr, and completions/git-gtr.fish

Files:

  • completions/git-gtr.fish
completions/gtr.bash

📄 CodeRabbit inference engine (.github/instructions/completions.instructions.md)

completions/gtr.bash: In completions/gtr.bash, implement command completion using COMPREPLY array and compgen filtering for the current word ($cur)
In completions/gtr.bash, support dynamic branch completion using 'git branch --format='%(refname:short)' and include special ID '1' for main repo

Update shell completion files when adding new commands or flags: completions/gtr.bash, completions/_git-gtr, and completions/git-gtr.fish

Files:

  • completions/gtr.bash
🧠 Learnings (1)
📚 Learning: 2025-12-29T18:46:36.983Z
Learnt from: helizaga
Repo: coderabbitai/git-worktree-runner PR: 64
File: bin/gtr:746-750
Timestamp: 2025-12-29T18:46:36.983Z
Learning: When error messages reference missing CLI tools (such as gh for GitHub CLI), use platform-agnostic installation guidance by directing users to the official website (e.g., https://cli.github.com/) instead of platform-specific package managers (brew, apt, choco) to ensure the guidance works across all operating systems. Apply this messaging to the bin/gtr script where applicable.

Applied to files:

  • bin/gtr
🧬 Code graph analysis (1)
lib/config.sh (1)
lib/ui.sh (1)
  • log_warn (8-10)
🪛 Shellcheck (0.11.0)
completions/gtr.bash

[warning] 79-79: Prefer mapfile or read -a to split command output (or quote to avoid splitting).

(SC2207)


[warning] 86-86: Prefer mapfile or read -a to split command output (or quote to avoid splitting).

(SC2207)


[warning] 88-88: Prefer mapfile or read -a to split command output (or quote to avoid splitting).

(SC2207)


[warning] 94-94: Prefer mapfile or read -a to split command output (or quote to avoid splitting).

(SC2207)


[warning] 96-96: Prefer mapfile or read -a to split command output (or quote to avoid splitting).

(SC2207)

🔇 Additional comments (9)
lib/config.sh (2)

83-100: LGTM! Function correctly maps gtr. keys to .gtrconfig equivalents.*

The mapping logic is clear and comprehensive.


217-394: Excellent implementation of multi-source config listing with origin tracking.

The use of Unit Separator ($'\x1f') as a delimiter is a smart choice to avoid conflicts with config values. The deduplication logic correctly preserves priority order (local > .gtrconfig > global > system).

completions/gtr.bash (1)

67-101: LGTM! Dynamic action detection correctly handles flexible flag positioning.

The loop-based action detection (lines 71-75) is a good approach that allows flags to appear in any position. The per-action completion logic properly restricts --system to read operations only.

Note on static analysis warnings (SC2207): The ShellCheck warnings about preferring mapfile or read -a are false positives. Using compgen to populate COMPREPLY is the standard and correct pattern for bash-completion. The warnings can be safely ignored in this context.

completions/_git-gtr (1)

78-147: LGTM! Zsh completion correctly mirrors bash completion logic.

The dynamic action detection (lines 111-122) correctly scans arguments with proper Zsh offset handling. The per-action completion appropriately restricts --system to read operations.

completions/git-gtr.fish (1)

71-114: LGTM! Fish completion cleanly implements read/write operation detection.

The helper functions __fish_git_gtr_config_is_read and __fish_git_gtr_config_is_write (lines 73-93) provide a clean abstraction for conditional completion. The restriction of --system to read operations (line 100) is correctly implemented.

bin/gtr (4)

1138-1171: LGTM! Flexible argument parsing correctly handles flags in any position.

The parsing logic properly distinguishes between actions, keys, values, and scope flags. The extra_args accumulation (line 1166) uses correct parameter expansion to handle spacing.


1173-1198: LGTM! Default action selection and scope resolution logic is sound.

The defaults are sensible:

  • Default to list when no arguments are provided
  • Default to get when a key is provided
  • Resolve auto scope to local for write operations
  • Properly reject --system for writes with clear error messaging

1200-1262: LGTM! Per-action handling is comprehensive and user-friendly.

Each action properly:

  • Validates required arguments
  • Warns about unexpected extra arguments
  • Uses resolved_scope for operations and logging (ensuring messages reflect actual behavior)
  • Provides clear error messages with usage examples

The new list action correctly delegates to cfg_list for proper formatting.


1411-1422: LGTM! Help text accurately documents the enhanced config command.

The documentation clearly explains:

  • The new list action as the default
  • Scope behavior for read vs write operations
  • Usage examples for each action

*) continue ;; # Skip unmapped keys
esac
_cfg_list_add_entry ".gtrconfig" "$mapped_key" "$fvalue"
done < <(git config -f "$config_file" --get-regexp '.' 2>/dev/null || true)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the actual code in lib/config.sh around line 317
cat -n lib/config.sh | sed -n '310,325p'

Repository: coderabbitai/git-worktree-runner

Length of output: 954


🏁 Script executed:

# Check if there are other similar process substitution patterns in the codebase
rg '<\s*<\(' --type sh lib/ bin/

Repository: coderabbitai/git-worktree-runner

Length of output: 173


🏁 Script executed:

# Let's also check Bash documentation for version support
# Test both syntaxes with Bash to understand version requirements
python3 << 'PYTHON_EOF'
import subprocess
import sys

# Test process substitution
print("=== Testing Process Substitution ===")
result_ps = subprocess.run(
    ['bash', '-c', 'echo "test" | (while read line; do echo "$line"; done < <(echo "test2"))'],
    capture_output=True,
    text=True
)
print(f"Process substitution exit code: {result_ps.returncode}")
if result_ps.returncode == 0:
    print("Process substitution: WORKS")
else:
    print(f"Process substitution: FAILS - {result_ps.stderr}")

# Test here-string
print("\n=== Testing Here-string ===")
result_hs = subprocess.run(
    ['bash', '-c', 'var="test"; while read line; do echo "$line"; done <<< "$var"'],
    capture_output=True,
    text=True
)
print(f"Here-string exit code: {result_hs.returncode}")
if result_hs.returncode == 0:
    print("Here-string: WORKS")
else:
    print(f"Here-string: FAILS - {result_hs.stderr}")

# Check Bash version
result_version = subprocess.run(
    ['bash', '--version'],
    capture_output=True,
    text=True
)
print(f"\nBash version: {result_version.stdout.split()[2]}")
PYTHON_EOF

Repository: coderabbitai/git-worktree-runner

Length of output: 162


🏁 Script executed:

# Search for Bash version compatibility notes in git history or documentation
rg 'Bash\s+3\.2|process\s+substitution|readarray' --type sh lib/ bin/ -A 2 -B 2

Repository: coderabbitai/git-worktree-runner

Length of output: 722


🏁 Script executed:

# Check the shebang and how scripts are executed
head -1 lib/config.sh lib/core.sh bin/gtr

Repository: coderabbitai/git-worktree-runner

Length of output: 195


Replace process substitution with variable assignment for Bash 3.2 compatibility.

Process substitution < <(...) requires Bash 4.0+. Use the variable assignment pattern already implemented elsewhere in this file (see line 321):

Suggested fix
       # 2. .gtrconfig file (team defaults)
       if [ -n "$config_file" ] && [ -f "$config_file" ]; then
+        local gtrconfig_entries
+        gtrconfig_entries=$(git config -f "$config_file" --get-regexp '.' 2>/dev/null || true)
         while IFS= read -r line; do
           [ -z "$line" ] && continue
           local fkey fvalue mapped_key
@@ -315,7 +316,7 @@
             *)                continue ;;  # Skip unmapped keys
           esac
           _cfg_list_add_entry ".gtrconfig" "$mapped_key" "$fvalue"
-        done < <(git config -f "$config_file" --get-regexp '.' 2>/dev/null || true)
+        done <<< "$gtrconfig_entries"
       fi

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @lib/config.sh around line 317, Replace the process substitution used in the
loop terminator "done < <(git config -f \"$config_file\" --get-regexp '.'
2>/dev/null || true)" with the file's existing Bash 3.2-compatible variable
assignment pattern: capture the output of the git command into a temporary
variable (like the pattern used around line 321), then feed that variable into
the while/read loop (e.g., via a here-string or printf piping); update the loop
to read from that variable instead of using < <(...), ensuring stderr is still
redirected to /dev/null and behavior remains identical.

@helizaga helizaga merged commit 9c3bf73 into coderabbitai:main Jan 6, 2026
1 check passed
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.

2 participants