---
name: git-worktree
description: >
  Create a git worktree to isolate changes on a working branch.
  Use when the user says /git-worktree, /worktree, 'worktree', 'isole les changements',
  'travaille dans un worktree', 'create a worktree', or needs to work in isolation
  on a branch without affecting the main working directory.
argument-hint: "<branch name or GitLab issue IID>"
allowed-tools:
  - Bash
  - Glob
  - Grep
  - Read
  - AskUserQuestion
  - EnterWorktree
  - ExitWorktree
---

Create a git worktree to isolate changes on a working branch, keeping the main working directory clean.

## Required tools

- `jq`

Run `pysae-ai-tools tools require <tools>` before starting; if it exits non-zero, abort and report the install command from stderr to the user.

## Step 1 — Detect context

```bash
CTX=$(pysae-ai-tools internal detect-context)
IS_CI=$(echo "$CTX" | jq -r '.is_ci')
GIT_BRANCH=$(echo "$CTX" | jq -r '.git_branch // empty')
MR_SOURCE_BRANCH=$(echo "$CTX" | jq -r '.mr_source_branch // empty')
MR_IID=$(echo "$CTX" | jq -r '.mr_iid // empty')
DEFAULT_BRANCH=$(echo "$CTX" | jq -r '.default_branch // "main"')
```

If `IS_CI` is `true`, **do not create a worktree**. Stay on the current branch and return immediately:
> Worktree non créé : mode CI (on reste sur la branche courante).

## Step 2 — Check IDE connection (local mode only)

An IDE MCP server (e.g. VS Code, JetBrains) connected to the session means worktrees will desynchronize the IDE — files edited in the worktree won't appear in the open editor.

**This check is mandatory and must be mechanical — never infer from "I don't see an IDE in the environment". The MCP tools may be deferred (listed only by name in system-reminders) rather than directly loaded.** Run this exact probe:

```
ToolSearch(query: "select:mcp__ide__getDiagnostics", max_results: 1)
```

Interpret the result strictly:

- **Result contains a `<function>` block for `mcp__ide__getDiagnostics`** → IDE is connected.
- **Result is empty / no match** → also scan the current conversation's system-reminder messages for the literal string `mcp__ide__`. If found anywhere → IDE is connected.
- **Still no signal after both checks** → no IDE connected, proceed.

If the probe is ambiguous or errors out, **default to "IDE connected"** (fail-safe — better to skip a worktree than to desynchronize the user's editor).

When IDE is detected:

- **Invoked directly by the user:** warn and ask for confirmation:
  > Un IDE est connecté à cette session. Les worktrees changent le répertoire de travail, ce qui peut désynchroniser l'IDE. Tu veux quand même continuer ?
  Only proceed if the user confirms. If not, suggest working directly on the branch instead.

- **Invoked by another skill (delegated):** skip the worktree silently — just log a short message and return without creating anything:
  > Worktree non créé : IDE connecté (risque de désynchronisation).

## Step 3 — Determine the target branch

Use context from Step 1 (`detect_context`) and `$ARGUMENTS`:

1. **Existing branch name** in `$ARGUMENTS` (e.g. `feat/42-add-login`) → use it directly
2. **GitLab ref** in `$ARGUMENTS` (`#42`, `!99`, URL) → `detect_context` already resolved it:
   - If `MR_SOURCE_BRANCH` is set → use it
   - If only `ISSUE_IID` is set (no MR) → derive branch from issue title:
     ```bash
     ISSUE_TITLE=$(echo "$CTX" | jq -r '.issue_title // empty')
     SLUG=$(echo "${ISSUE_TITLE}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | cut -c1-40 | sed 's/-$//')
     BRANCH="feat/${ISSUE_IID}-${SLUG}"
     ```
3. **No argument** → auto-detect from context:
   - If `GIT_BRANCH` is not `DEFAULT_BRANCH` → already on a feature branch, use it
   - If `MR_SOURCE_BRANCH` is set → use it (MR detected for current branch)
   - Otherwise → ask the user what branch to work on

Check if the branch already exists (locally or remote):
```bash
git branch -a --list "*${BRANCH}*"
```

**Determine the base ref** — the ref the new branch starts from and is rebased onto. **Default: the repo's default branch.** A caller can override it with `--base <branch|tag>` in `$ARGUMENTS` to start from somewhere else — e.g. `/ci-release` (support release) passes the `support/vX.Y.x` branch, `/code-implement` (hotfix) passes the release tag. **Never force the default branch when a base is provided** — rebasing a support fix onto the default branch would pull the whole main line into it.

```bash
BASE_REF="${DEFAULT_BRANCH}"
ARG_BASE=$(printf '%s\n' "$ARGUMENTS" | sed -n 's@.*--base[ =]\([^ ]\+\).*@\1@p')
[ -n "$ARG_BASE" ] && BASE_REF="${ARG_BASE#origin/}"

# Resolve whether BASE_REF is a remote branch or a tag, and the concrete rebase target.
if git ls-remote --exit-code --tags origin "${BASE_REF}" >/dev/null 2>&1; then
  BASE_KIND=tag;    REBASE_TARGET="${BASE_REF}"
else
  BASE_KIND=branch; REBASE_TARGET="origin/${BASE_REF}"
fi
```

## Step 4 — Create the worktree

**Toujours fetch la base AVANT de créer le worktree.** La base se résout depuis une réf locale (`origin/<base>` ou le tag), qui n'est à jour que du dernier fetch : sans ce fetch préalable, on tire une branche depuis une base **en retard sur le HEAD réel d'origin** (features déjà mergées absentes, conflits artificiels au rebase).

```bash
if [ "$BASE_KIND" = tag ]; then
  git fetch origin "refs/tags/${BASE_REF}:refs/tags/${BASE_REF}"
else
  git fetch origin "${BASE_REF}"
fi
```

Then use the `EnterWorktree` tool to create an isolated worktree. Use the branch name as the worktree name:

```
EnterWorktree(name: "<branch-name>")
```

This creates a worktree in `.claude/worktrees/<name>` with a new branch based on HEAD, and switches the session into it.

## Step 5 — Set up the branch

**Toujours rebaser sur la base résolue** (`REBASE_TARGET` — la branche par défaut, ou la branche support / le tag passé via `--base`) dès l'entrée dans le worktree, quelle que soit la branche courante du repo principal, puis **vérifier** que la base est bien le HEAD distant fraîchement fetché :

```bash
git reset --hard "${REBASE_TARGET}"
# Hard guarantee: the work starts from the resolved base's true HEAD, never a stale local ref.
[ "$(git rev-parse HEAD)" = "$(git rev-parse "${REBASE_TARGET}")" ] || { echo "FATAL: worktree base != ${REBASE_TARGET}" >&2; exit 1; }
```

### If the branch already exists remotely:
```bash
git fetch origin "${BRANCH}"
git checkout "${BRANCH}"
```

### If the branch is new:
La branche locale est maintenant alignée sur la base résolue (`REBASE_TARGET`). Renommer la branche locale, pousser et configurer le tracking :
```bash
git branch -m "${BRANCH}"
git push -u origin "${BRANCH}"
```

## Step 6 — Confirm

Report to the user:
- Worktree location
- Branch name
- Base branch / tracking info
- Remind them that they can exit with `/code-worktree exit` or by asking to "exit the worktree"

> 📂 **Changement de répertoire de travail**
> Je travaille maintenant dans : `<WORKTREE_PATH>`
> Branche : `<BRANCH>`
> Pour sortir du worktree : demande-moi de « sortir du worktree ».

## Exiting the worktree

When the user asks to exit/leave the worktree ("exit worktree", "sors du worktree", "quitte le worktree"):

1. Check for uncommitted changes: `git status --porcelain`
2. Check for unpushed commits: `git log origin/<BRANCH>..HEAD --oneline 2>/dev/null`
3. If there are uncommitted or unpushed changes, warn the user and ask what to do:
   - **Keep** the worktree (changes preserved on disk)
   - **Remove** the worktree (discard everything)
4. Use `ExitWorktree` with the appropriate action
5. Confirm the directory change to the user:
   > 📂 **Retour au répertoire principal**
   > Je travaille maintenant dans : `<ORIGINAL_PATH>`

## Rules

- **Always use EnterWorktree/ExitWorktree** — never create worktrees manually with `git worktree add`
- **One worktree per session** — if already in a worktree, inform the user and ask if they want to exit first
- **Language**: French for communication, English for commands

$ARGUMENTS
