diff --git a/CLAUDE.md b/CLAUDE.md index 09d159b..1a58c30 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -133,6 +133,15 @@ git config --add gtr.copy.exclude "**/.env" ./bin/gtr new test-copy # Expected: Copies .env.example but not .env +# Test .worktreeinclude file +printf '# Test patterns\n**/.env.example\n*.md\n' > .worktreeinclude +echo "TEST=value" > .env.example +./bin/gtr new test-worktreeinclude +# Expected: Copies .env.example and *.md files to worktree +ls "$(./bin/gtr go test-worktreeinclude)/.env.example" +./bin/gtr rm test-worktreeinclude +rm .worktreeinclude .env.example + # Test directory copying with include/exclude patterns git config --add gtr.copy.includeDirs "node_modules" git config --add gtr.copy.excludeDirs "node_modules/.cache" @@ -402,6 +411,7 @@ All config keys use `gtr.*` prefix and are managed via `git config`: - `gtr.ai.default`: Default AI tool (aider, claude, codex, etc.) - `gtr.copy.include`: Multi-valued glob patterns for files to copy - `gtr.copy.exclude`: Multi-valued glob patterns for files to exclude +- `.worktreeinclude`: File in repo root with glob patterns (merged with `gtr.copy.include`) - `gtr.copy.includeDirs`: Multi-valued directory patterns to copy (e.g., "node_modules", ".venv", "vendor") - `gtr.copy.excludeDirs`: Multi-valued directory patterns to exclude when copying (supports globs like "node_modules/.cache", "\*/.cache") - `gtr.hook.postCreate`: Multi-valued commands to run after creating worktree diff --git a/README.md b/README.md index ce8518b..c462c92 100644 --- a/README.md +++ b/README.md @@ -369,6 +369,21 @@ git gtr config add gtr.copy.exclude "**/.env" git gtr config add gtr.copy.exclude "**/secrets.*" ``` +#### Using .worktreeinclude file + +Alternatively, create a `.worktreeinclude` file in your repository root: + +```gitignore +# .worktreeinclude - files to copy to new worktrees +# Comments start with # + +**/.env.example +**/CLAUDE.md +*.config.js +``` + +The file uses `.gitignore`-style syntax (one pattern per line, `#` for comments, empty lines ignored). Patterns from `.worktreeinclude` are merged with `gtr.copy.include` config settings - both sources are used together. + #### Security Best Practices **The key distinction:** Development secrets (test API keys, local DB passwords) are **low risk** on personal machines. Production credentials are **high risk** everywhere. diff --git a/bin/gtr b/bin/gtr index cc3de6f..5bc781f 100755 --- a/bin/gtr +++ b/bin/gtr @@ -240,10 +240,22 @@ cmd_create() { # Copy files based on patterns if [ "$skip_copy" -eq 0 ]; then - local includes excludes + local includes excludes file_includes includes=$(cfg_get_all gtr.copy.include) excludes=$(cfg_get_all gtr.copy.exclude) + # Read .worktreeinclude file if exists + file_includes=$(parse_pattern_file "$repo_root/.worktreeinclude") + + # Merge patterns (newline-separated) + if [ -n "$file_includes" ]; then + if [ -n "$includes" ]; then + includes="$includes"$'\n'"$file_includes" + else + includes="$file_includes" + fi + fi + if [ -n "$includes" ]; then log_step "Copying files..." copy_patterns "$repo_root" "$worktree_path" "$includes" "$excludes" diff --git a/lib/copy.sh b/lib/copy.sh index 35bf626..2d89222 100644 --- a/lib/copy.sh +++ b/lib/copy.sh @@ -1,6 +1,20 @@ #!/usr/bin/env bash # File copying utilities with pattern matching +# Parse .gitignore-style pattern file +# Usage: parse_pattern_file file_path +# Returns: newline-separated patterns (comments and empty lines stripped) +parse_pattern_file() { + local file_path="$1" + + if [ ! -f "$file_path" ]; then + return 0 + fi + + # Read file, strip comments and empty lines + grep -v '^#' "$file_path" 2>/dev/null | grep -v '^[[:space:]]*$' || true +} + # Copy files matching patterns from source to destination # Usage: copy_patterns src_root dst_root includes excludes [preserve_paths] # includes: newline-separated glob patterns to include