-
Notifications
You must be signed in to change notification settings - Fork 48
Expand file tree
/
Copy pathworktree-add.sh
More file actions
executable file
·114 lines (103 loc) · 3.47 KB
/
Copy pathworktree-add.sh
File metadata and controls
executable file
·114 lines (103 loc) · 3.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/bin/bash
# worktree-add.sh — Create a git worktree with shared local state
#
# Usage:
# ./worktree-add.sh <directory> <branch> [base-ref]
#
# Examples:
# ./worktree-add.sh ../salesagent-schemas chore/schemas-split
# ./worktree-add.sh ../salesagent-review review/temp main
# ./worktree-add.sh ../salesagent-main main # existing branch (no -b)
#
# What it does:
# 1. Creates the worktree (new branch from base-ref, or checks out existing)
# 2. Symlinks .beads/ for shared task tracking
# 3. Symlinks untracked .claude/ dirs (research, settings, agent-memory)
# 4. Runs uv sync if uv is available
set -euo pipefail
MAIN_REPO="$(cd "$(dirname "$0")" && pwd)"
if [ $# -lt 2 ]; then
echo "Usage: $0 <directory> <branch> [base-ref]"
echo ""
echo "Examples:"
echo " $0 ../salesagent-schemas chore/schemas-split"
echo " $0 ../salesagent-main main"
exit 1
fi
TARGET="$1"
BRANCH="$2"
BASE="${3:-main}"
# Check if branch already exists
if git rev-parse --verify "$BRANCH" >/dev/null 2>&1; then
echo "Branch '$BRANCH' exists, checking out..."
git worktree add "$TARGET" "$BRANCH"
else
echo "Creating branch '$BRANCH' from '$BASE'..."
git worktree add "$TARGET" -b "$BRANCH" "$BASE"
fi
# Resolve to absolute path
TARGET="$(cd "$TARGET" && pwd)"
# Symlink .beads/ for shared task tracking
if [ -d "$MAIN_REPO/.beads" ]; then
rm -rf "$TARGET/.beads"
ln -sf "$MAIN_REPO/.beads" "$TARGET/.beads"
echo "Linked .beads/"
fi
# Symlink untracked .claude/ local state
# (tracked .claude/ files like rules/workflows come from git automatically)
mkdir -p "$TARGET/.claude"
for item in research settings.local.json agent-memory; do
if [ -e "$MAIN_REPO/.claude/$item" ]; then
rm -rf "$TARGET/.claude/$item"
ln -sf "$MAIN_REPO/.claude/$item" "$TARGET/.claude/$item"
echo "Linked .claude/$item"
fi
done
# Copy .env with unique CONDUCTOR_PORT for independent docker-compose up/down
if [ -f "$MAIN_REPO/.env" ]; then
cp "$MAIN_REPO/.env" "$TARGET/.env"
# Find a free port for this worktree's docker-compose stack
CONDUCTOR_PORT=$(python3 -c "
import socket
for p in range(8001, 8100):
try:
s = socket.socket()
s.bind(('', p))
s.close()
print(p)
break
except OSError:
s.close()
")
if [ -n "$CONDUCTOR_PORT" ]; then
# Append or replace CONDUCTOR_PORT in the worktree .env
if grep -q '^CONDUCTOR_PORT=' "$TARGET/.env" 2>/dev/null; then
sed -i '' "s/^CONDUCTOR_PORT=.*/CONDUCTOR_PORT=$CONDUCTOR_PORT/" "$TARGET/.env"
else
echo "CONDUCTOR_PORT=$CONDUCTOR_PORT" >> "$TARGET/.env"
fi
echo "Copied .env with CONDUCTOR_PORT=$CONDUCTOR_PORT"
else
echo "WARNING: Could not find free port in 8001-8100 for CONDUCTOR_PORT" >&2
echo "Copied .env without CONDUCTOR_PORT (will use default 8000)"
fi
else
echo "No .env found in main repo — worktree will need manual .env setup"
fi
# Install dependencies if uv is available
if command -v uv >/dev/null 2>&1; then
echo "Running uv sync..."
(cd "$TARGET" && uv sync --quiet)
echo "Dependencies installed."
fi
echo ""
echo "Worktree ready:"
echo " Path: $TARGET"
echo " Branch: $BRANCH"
if [ -n "${CONDUCTOR_PORT:-}" ]; then
echo " Port: $CONDUCTOR_PORT (docker compose → http://localhost:$CONDUCTOR_PORT)"
fi
echo ""
echo "To use: cd $TARGET"
echo "To test: cd $TARGET && docker compose up -d"
echo "To remove: git worktree remove $TARGET"