Skip to content

Conversation

@him0
Copy link
Contributor

@him0 him0 commented Nov 25, 2025

Description

Add support for reading glob patterns from a .worktreeinclude file in the repository root.

This implementation follows Claude Code's .worktreeinclude approach, allowing users to commit file copy patterns to the repository instead of requiring each developer to configure gtr.copy.include manually.

Reference: https://code.claude.com/docs/en/desktop

Motivation

Currently, file copy patterns must be configured per-developer using git gtr config add gtr.copy.include. This means:

  • Each developer must manually set up patterns
  • Patterns cannot be shared via the repository

With .worktreeinclude, teams can define standard patterns in the repository, similar to how .gitignore works.

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: _____)
  • Windows (Git Bash)

Core functionality tested:

  • git gtr new <branch> - Create worktree
  • git gtr go <branch> - Navigate to worktree
  • git gtr editor <branch> - Open in editor (if applicable)
  • git gtr ai <branch> - Start AI tool (if applicable)
  • git gtr rm <branch> - Remove worktree
  • git gtr list - List worktrees
  • git gtr config - Configuration commands (if applicable)
  • Other commands affected by this change: _____

Test Steps

  1. Create .worktreeinclude file:
    # Test patterns
    .env.example
    *.md
    
  2. Create a test file: echo "TEST=value" > .env.example
  3. Run ./bin/gtr new test-worktreeinclude
  4. Verify files are copied: ls "$(./bin/gtr go test-worktreeinclude)/.env.example"
  5. Clean up: ./bin/gtr rm test-worktreeinclude && rm .worktreeinclude .env.example

Expected behavior: Files matching patterns in .worktreeinclude are copied to the new worktree.

Actual behavior: Files are copied as expected. Patterns from .worktreeinclude are merged with gtr.copy.include config.

Breaking Changes

  • This PR introduces breaking changes
  • I have discussed this in an issue first
  • Migration guide is included in documentation

Checklist

Before submitting this PR, please check:

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

Additional Context

Implementation Details

  1. lib/copy.sh: Added parse_pattern_file() function that reads a file and strips comments (#) and empty lines, returning newline-separated patterns.

  2. bin/gtr: Modified cmd_create() to read .worktreeinclude and merge its patterns with gtr.copy.include config.

File Format

The .worktreeinclude file uses .gitignore-style syntax:

  • One pattern per line
  • Lines starting with # are comments
  • Empty lines are ignored
# .worktreeinclude - files to copy to new worktrees
**/.env.example
**/CLAUDE.md
*.config.js

License Acknowledgment

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache License 2.0.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Support for a .worktreeinclude file to add file-copy patterns; patterns are merged with existing include settings and honored only when copying is enabled.
  • Documentation

    • Added usage guide and examples describing .worktreeinclude syntax (one pattern per line, supports # comments, ignores blank lines) and merge behavior.
  • Tests

    • Added a test workflow demonstrating creation and use of a .worktreeinclude file.

✏️ Tip: You can customize this high-level summary in your review settings.

@him0 him0 requested a review from NatoBoram as a code owner November 25, 2025 06:13
@coderabbitai
Copy link

coderabbitai bot commented Nov 25, 2025

📝 Walkthrough

Walkthrough

Adds support for a repository-root .worktreeinclude pattern file: patterns (one per line, # comments and blank lines ignored) are parsed by a new helper and, when copying is enabled, merged with existing gtr.copy.include patterns. Documentation and examples were added; no public APIs changed.

Changes

Cohort / File(s) Summary
Documentation
CLAUDE.md, README.md
Added docs and user examples describing the .worktreeinclude file, its syntax (one pattern per line, # comments, ignore empty lines) and that its patterns are merged with gtr.copy.include.
Library
lib/copy.sh
Added parse_pattern_file(file_path) which returns success when file missing, otherwise outputs newline-separated patterns after removing comment lines and blanks.
Main binary
bin/gtr
When skip_copy is 0, reads repo_root/.worktreeinclude via parse_pattern_file, stores file_includes, and concatenates those patterns with existing gtr.copy.include (newline-separated) for use during file copying.

Sequence Diagram

sequenceDiagram
    autonumber
    participant GTR as bin/gtr
    participant PARSE as lib/copy.sh:parse_pattern_file()
    participant FILE as repo_root/.worktreeinclude
    participant MERGE as Merge Logic

    GTR->>PARSE: call parse_pattern_file(repo_root/.worktreeinclude)
    PARSE->>FILE: attempt to read file
    alt file exists
        PARSE->>PARSE: remove lines starting with '#' and blank lines
        PARSE-->>GTR: return newline-separated patterns
    else file missing
        PARSE-->>GTR: return empty / success
    end

    GTR->>MERGE: provide file_includes + gtr.copy.include (if skip_copy=0)
    MERGE->>MERGE: concatenate newline-separated lists
    MERGE-->>GTR: merged includes used for copying
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Inspect parse_pattern_file for edge cases: trailing whitespace, CRLF handling, encoding.
  • Verify bin/gtr integration: correct skip_copy conditional, ordering of merged patterns, and whether duplicates should be deduplicated.
  • Confirm documentation examples accurately reflect runtime behavior.

Poem

🐰 I nibble lines and skip the hashes,
I drop the blanks and tidy stashes,
I hop the lists and stitch them tight,
So copy finds the files just right,
A tiny hop — a tidy night! 🥕

Pre-merge checks and finishing touches

✅ 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 clearly and concisely describes the main feature being added: support for .worktreeinclude file pattern reading.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

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 126641f and c3afa06.

📒 Files selected for processing (1)
  • README.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • README.md

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)
CLAUDE.md (1)

136-143: Replace echo -e with printf for better portability.

The echo -e flag is not POSIX-compliant and behaves differently across shells. Use printf for reliable newline handling.

Apply this diff:

 # Test .worktreeinclude file
-echo -e "# Test patterns\n**/.env.example\n*.md" > .worktreeinclude
+printf "# Test patterns\n**/.env.example\n*.md\n" > .worktreeinclude
 echo "TEST=value" > .env.example
 ./bin/gtr new test-worktreeinclude
README.md (2)

375-382: Add language specifier to fenced code block.

The fenced code block should specify a language for syntax highlighting and clarity. Since this represents the content of a .worktreeinclude file (gitignore-style), use gitignore or text.

Apply this diff:

 Alternatively, create a `.worktreeinclude` file in your repository root:
 
-```
+```gitignore
 # .worktreeinclude - files to copy to new worktrees
 # Comments start with #

Based on static analysis hints.


371-384: Consider documenting that .worktreeinclude should be committed to the repository.

The documentation describes the feature well, but it might be helpful to explicitly mention that the .worktreeinclude file should be committed to version control so the patterns are shared across the team (similar to .gitignore). This aligns with the PR motivation of enabling pattern sharing instead of per-developer configuration.

📜 Review details

Configuration used: CodeRabbit UI

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 758a684 and 6a1fdc8.

📒 Files selected for processing (4)
  • CLAUDE.md (2 hunks)
  • README.md (1 hunks)
  • bin/gtr (1 hunks)
  • lib/copy.sh (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
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/copy.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)
Use snake_case naming for functions
Use snake_case for local variables and UPPER_CASE for constants/environment variables
Use 2-space indentation (no tabs) in Bash scripts
Always quote variables and paths in Bash scripts
Check return codes and use || exit 1 or || return 1 for error handling

Files:

  • lib/copy.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/copy.sh
{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/copy.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

Update GTR_VERSION constant at line 8 when releasing a new version

Files:

  • bin/gtr
🪛 markdownlint-cli2 (0.18.1)
README.md

375-375: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (3)
CLAUDE.md (1)

414-414: LGTM!

Documentation accurately describes the new .worktreeinclude configuration key and its relationship to gtr.copy.include.

bin/gtr (1)

247-257: LGTM! Clean integration of .worktreeinclude support.

The implementation correctly:

  • Reads patterns from the repo root .worktreeinclude file using parse_pattern_file
  • Handles the case where the file doesn't exist (graceful fallback)
  • Merges patterns with existing gtr.copy.include configuration
  • Preserves existing behavior when only one source is present
  • Only activates when copying is enabled (skip_copy=0)

The patterns will go through the same security validation in copy_patterns as configured patterns.

lib/copy.sh (1)

4-16: LGTM! Robust pattern file parsing with proper error handling.

The function correctly:

  • Returns gracefully (exit 0) when the file doesn't exist, making .worktreeinclude optional
  • Strips comment lines (starting with #) and blank lines using POSIX-compliant grep
  • Handles all edge cases (empty file, only comments, only blanks) through the || true guard
  • Follows coding guidelines: local variables, proper quoting, and compatible with set -e

The implementation aligns with .gitignore-style syntax as documented.

CLAUDE.md Outdated
# Expected: Copies .env.example but not .env

# Test .worktreeinclude file
echo -e "# Test patterns\n**/.env.example\n*.md" > .worktreeinclude
Copy link
Collaborator

Choose a reason for hiding this comment

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

echo -e → printf for POSIX compatibility

@helizaga
Copy link
Collaborator

LGTM just fix nitpick

him0 and others added 2 commits November 30, 2025 14:54
Add support for reading glob patterns from a `.worktreeinclude` file
in the repository root, similar to Claude Code's implementation.

This feature allows users to commit file copy patterns to the repository
instead of requiring each developer to configure `gtr.copy.include` manually.

Features:
- `.gitignore`-style syntax (# for comments, empty lines ignored)
- Patterns are merged with `gtr.copy.include` config (both sources used)
- File is optional - missing file is silently ignored

Implementation:
- Add `parse_pattern_file()` function in lib/copy.sh
- Read and merge patterns in cmd_create() in bin/gtr

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Replace echo -e with printf in the .worktreeinclude test example
to ensure compatibility with POSIX shells that don't support the
-e flag.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@him0 him0 force-pushed the feat/worktreeinclude-file branch from 1a0664e to 126641f Compare November 30, 2025 05:54
@him0 him0 requested a review from helizaga November 30, 2025 05:54
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

📜 Review details

Configuration used: CodeRabbit UI

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 6a1fdc8 and 126641f.

📒 Files selected for processing (4)
  • CLAUDE.md (2 hunks)
  • README.md (1 hunks)
  • bin/gtr (1 hunks)
  • lib/copy.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • CLAUDE.md
  • lib/copy.sh
🧰 Additional context used
📓 Path-based instructions (2)
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 GTR_VERSION constant at line 8 when releasing a new version

Files:

  • bin/gtr
{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:

  • bin/gtr
🪛 markdownlint-cli2 (0.18.1)
README.md

376-376: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (2)
bin/gtr (2)

243-243: LGTM - Variable declaration is clear.

Adding file_includes to the local variable declaration properly scopes it for the pattern merging logic.


247-257: Verify error handling for missing or inaccessible .worktreeinclude file.

The merge logic correctly concatenates patterns with newline separation. However, the parse_pattern_file call is not guarded against errors. If the file is inaccessible (e.g., permission denied), the script will exit due to set -e. Per coding guidelines, non-critical commands should be guarded with || true. Verify that parse_pattern_file handles all error cases gracefully (returns empty string for missing/inaccessible files) or add error handling. Additionally, ensure $file_includes is quoted to handle spaces in file paths: includes="$includes"$'\n'"$file_includes"includes="$includes"$'\n'"$file_includes".

Add gitignore language specifier to the .worktreeinclude example
code block for proper syntax highlighting.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
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