Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions lib/commands/copy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,19 @@ cmd_copy() {
src_path="$_ctx_worktree_path"

# Get patterns (flag > config + .worktreeinclude)
local excludes
local excludes dir_includes="" dir_excludes=""
if [ -z "$patterns" ]; then
merge_copy_patterns "$repo_root"

patterns="$_ctx_copy_includes" excludes="$_ctx_copy_excludes"
dir_includes=$(cfg_get_all gtr.copy.includeDirs copy.includeDirs)
dir_excludes=$(cfg_get_all gtr.copy.excludeDirs copy.excludeDirs)
else
excludes=$(cfg_get_all gtr.copy.exclude copy.exclude)
fi

if [ -z "$patterns" ]; then
log_error "No patterns specified. Use '-- <pattern>...' or configure gtr.copy.include"
if [ -z "$patterns" ] && [ -z "$dir_includes" ]; then
log_error "No patterns specified. Use '-- <pattern>...' or configure gtr.copy.include or gtr.copy.includeDirs"
exit 1
fi

Expand Down Expand Up @@ -85,15 +87,17 @@ cmd_copy() {

if [ "$dry_run" -eq 1 ]; then
log_step "[dry-run] Would copy to: $dst_branch"
copy_patterns "$src_path" "$dst_path" "$patterns" "$excludes" "true" "true"
[ -n "$patterns" ] && copy_patterns "$src_path" "$dst_path" "$patterns" "$excludes" "true" "true"
[ -n "$dir_includes" ] && copy_directories "$src_path" "$dst_path" "$dir_includes" "$dir_excludes" "true"
else
log_step "Copying to: $dst_branch"
copy_patterns "$src_path" "$dst_path" "$patterns" "$excludes" "true"
[ -n "$patterns" ] && copy_patterns "$src_path" "$dst_path" "$patterns" "$excludes" "true"
[ -n "$dir_includes" ] && copy_directories "$src_path" "$dst_path" "$dir_includes" "$dir_excludes"
fi
copied_any=1
done

if [ "$copied_any" -eq 0 ]; then
log_warn "No files copied (source and target may be the same)"
fi
}
}
16 changes: 14 additions & 2 deletions lib/copy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ EOF
}

# Copy directories matching patterns (typically git-ignored directories like node_modules)
# Usage: copy_directories src_root dst_root dir_patterns excludes
# Usage: copy_directories src_root dst_root dir_patterns excludes [dry_run]
# dir_patterns: newline-separated directory names to copy (e.g., "node_modules", ".venv")
# excludes: newline-separated directory patterns to exclude (supports globs like "node_modules/.cache")
# WARNING: This copies entire directories including potentially sensitive files.
Expand All @@ -329,6 +329,7 @@ copy_directories() {
local dst_root="$2"
local dir_patterns="$3"
local excludes="$4"
local dry_run="${5:-false}"

if [ -z "$dir_patterns" ]; then
return 0
Expand Down Expand Up @@ -372,6 +373,13 @@ copy_directories() {
local dest_dir="$dst_root/$dir_path"
local dest_parent
dest_parent=$(dirname "$dest_dir")

if [ "$dry_run" = "true" ]; then
log_info "[dry-run] Would copy directory $dir_path"
copied_count=$((copied_count + 1))
continue
fi

mkdir -p "$dest_parent"

# Copy directory using CoW when available (preserves symlinks as symlinks)
Expand All @@ -392,7 +400,11 @@ EOF
cd "$old_pwd" || return 1

if [ "$copied_count" -gt 0 ]; then
log_info "Copied $copied_count directories"
if [ "$dry_run" = "true" ]; then
log_info "[dry-run] Would copy $copied_count directories"
else
log_info "Copied $copied_count directories"
fi
fi

return 0
Expand Down
56 changes: 56 additions & 0 deletions tests/cmd_copy.bats
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,39 @@ teardown() {
[ -f "$TEST_WORKTREES_DIR/copy-target/config.json" ]
}

@test "cmd_copy copies configured includeDirs" {
mkdir -p "$TEST_REPO/.zed"
echo "settings" > "$TEST_REPO/.zed/settings.json"
git config --add gtr.copy.includeDirs ".zed"

run cmd_copy copy-target
[ "$status" -eq 0 ]
[ -f "$TEST_WORKTREES_DIR/copy-target/.zed/settings.json" ]
}

@test "cmd_copy dry-run does not copy configured includeDirs" {
mkdir -p "$TEST_REPO/.zed"
echo "settings" > "$TEST_REPO/.zed/settings.json"
git config --add gtr.copy.includeDirs ".zed"

run cmd_copy copy-target --dry-run
[ "$status" -eq 0 ]
[ ! -d "$TEST_WORKTREES_DIR/copy-target/.zed" ]
}

@test "cmd_copy applies configured excludeDirs" {
mkdir -p "$TEST_REPO/.zed/cache"
echo "settings" > "$TEST_REPO/.zed/settings.json"
echo "token" > "$TEST_REPO/.zed/cache/token"
git config --add gtr.copy.includeDirs ".zed"
git config --add gtr.copy.excludeDirs ".zed/cache"

run cmd_copy copy-target
[ "$status" -eq 0 ]
[ -f "$TEST_WORKTREES_DIR/copy-target/.zed/settings.json" ]
[ ! -e "$TEST_WORKTREES_DIR/copy-target/.zed/cache/token" ]
}

# ── --all flag ───────────────────────────────────────────────────────────────

@test "cmd_copy --all copies to all worktrees" {
Expand All @@ -47,6 +80,29 @@ teardown() {
[ -f "$TEST_WORKTREES_DIR/copy-target-2/.env" ]
}

@test "cmd_copy --all copies configured includeDirs to all worktrees" {
create_test_worktree "copy-target-2"
mkdir -p "$TEST_REPO/.zed"
echo "settings" > "$TEST_REPO/.zed/settings.json"
git config --add gtr.copy.includeDirs ".zed"

run cmd_copy --all
[ "$status" -eq 0 ]
[ -f "$TEST_WORKTREES_DIR/copy-target/.zed/settings.json" ]
[ -f "$TEST_WORKTREES_DIR/copy-target-2/.zed/settings.json" ]
}

@test "cmd_copy --from copies configured includeDirs from source worktree" {
create_test_worktree "copy-source"
mkdir -p "$TEST_WORKTREES_DIR/copy-source/.idea"
echo "workspace" > "$TEST_WORKTREES_DIR/copy-source/.idea/workspace.xml"
git config --add gtr.copy.includeDirs ".idea"

run cmd_copy copy-target --from copy-source
[ "$status" -eq 0 ]
[ -f "$TEST_WORKTREES_DIR/copy-target/.idea/workspace.xml" ]
}

# ── Error cases ──────────────────────────────────────────────────────────────

@test "cmd_copy fails with no arguments" {
Expand Down
Loading