diff --git a/plugins/git/.apm/skills/git-worktrees/SKILL.md b/plugins/git/.apm/skills/git-worktrees/SKILL.md index 2a74445..f69223c 100644 --- a/plugins/git/.apm/skills/git-worktrees/SKILL.md +++ b/plugins/git/.apm/skills/git-worktrees/SKILL.md @@ -24,18 +24,19 @@ metadata: | Operation | Run | |---|---| -| Create on an existing branch | `git worktree add ` | +| Create on a branch that already exists locally | `git worktree add ` | | Create on a new branch | `git worktree add -b ` | | Create on the branch named after the path basename | `git worktree add ` — checks that branch out if it exists, else creates it from HEAD | | Create and reset an existing branch to HEAD — discards its commits | `git worktree add -B ` | -| Create tracking a remote branch | `git worktree add /` | -| Throwaway experiment, no branch | `git worktree add -d ` | +| Create a local branch tracking a remote one | `git worktree add --track -b /` — always correct. `git worktree add ` expands to exactly this, but **only** when `` has no local copy (gate below) | +| Throwaway experiment, no branch | `git worktree add -d ` — detached HEAD | +| **Never** `git worktree add /` | That ref resolves, so the shortcut never fires and you get **a detached HEAD, no branch, no upstream**. Commits there go unreachable once HEAD moves, and `git push` needs an explicit refspec. Use the tracking row above | | List | `git worktree list -v`, or `--porcelain -z` to parse | | Lock or unlock | `git worktree lock [--reason ] ` / `git worktree unlock ` | | Move | `git worktree move ` | | Remove | `git worktree remove ` | | Prune stale metadata | `git worktree prune --dry-run`, then without the flag | -| Repair after a manual move | `git worktree repair []` — from the main worktree to fix all links, or from the moved worktree itself | +| Repair after a manual move | `git worktree repair` — in the main worktree if *it* moved, or inside a linked worktree that moved. `git worktree repair ...` — from any worktree, naming each moved linked worktree's new path | If the operation needs anything the table does not carry — the full `add` flag table, orphan branches, sparse-checkout, locking for removable media, remote @@ -47,6 +48,7 @@ Gates: - **`move`, `remove` — the main worktree cannot be moved or removed.** Only linked worktrees, the ones `git worktree add` created, are candidates. - **`add`, `move`, `remove` — escalate force flags one step at a time.** `-f` overrides a safeguard such as an unclean tree; `move` and `remove` need `-ff` on top of that when the worktree is locked. Confirm with the user before either — both discard state. - **`lock`, `move`, `remove`, `repair` — identify a worktree by full path, unique basename, or unique partial path.** An ambiguous name errors rather than picking; `git worktree list` shows the usable identifiers. +- **`add` — the bare-name tracking shortcut needs exactly one remote.** `git worktree add ` sets up tracking only when `` is absent locally, no `-b`/`-B`/`-d` is given, and exactly one remote carries the name. With several, it fires only if `checkout.defaultRemote` names one. When the remote is ambiguous or unknown, use `--track -b`. - **`add` — lock at creation, not after.** `git worktree add --lock` is atomic, where add-then-`lock` leaves a window in which the worktree is unprotected. ## Step 2 — Report diff --git a/plugins/git/.apm/skills/git-worktrees/references/worktrees.md b/plugins/git/.apm/skills/git-worktrees/references/worktrees.md index ebade88..a5cedef 100644 --- a/plugins/git/.apm/skills/git-worktrees/references/worktrees.md +++ b/plugins/git/.apm/skills/git-worktrees/references/worktrees.md @@ -15,16 +15,29 @@ or moved. Every other worktree is a **linked worktree** created by `git worktree ## `add` forms ```bash -git worktree add # check out an existing branch — non-destructive +git worktree add # exists locally: check it out — non-destructive git worktree add -b # create a new branch; fails if it exists git worktree add # branch named after $(basename ): checked out # if it exists, else created from HEAD git worktree add -B # create the branch, or reset an existing one to HEAD, # discarding the commits it carried -git worktree add / # track a remote branch +git worktree add --track -b / + # new local branch tracking the remote — always works +git worktree add # absent locally and in exactly one remote: + # Git expands this to the --track -b form above git worktree add -d # detached HEAD, no branch ``` +The same `git worktree add ` spelling appears twice above and does two +different things: it checks out a local branch when one exists, and only otherwise falls +through to the remote-tracking shortcut. Read the local branch list before relying on either. + +**Do not write `git worktree add /`.** A remote-tracking ref resolves as a +commit-ish, so the tracking shortcut never fires and the worktree lands on a **detached HEAD with +no local branch and no upstream** — commits there go unreachable once HEAD moves or the worktree is +removed, and `git push` fails without an explicit refspec. That spelling is correct only as the +final argument of the `--track -b` form. + ## Full `add` flag table | Flag | Meaning | @@ -69,19 +82,40 @@ git worktree unlock # when reconnected ## Remote-branch disambiguation ```bash -git worktree add / +git worktree add --track -b / # explicit: no guessing at all +git worktree add # shortcut: needs one clear remote ``` -For ambiguous names across remotes, `checkout.defaultRemote` config disambiguates explicitly, or `--guess-remote` auto-matches by path basename (default controlled by `worktree.guessRemote` config). If a branch name matches multiple remotes during `worktree add` and neither is set, Git refuses rather than guessing. +The shortcut fires only when `` is not found locally, none of `-b`/`-B`/`--detach` were +given, and a tracking branch of that name exists in exactly one remote. When several remotes carry +the name, `checkout.defaultRemote` picks one for disambiguation purposes; with no such setting the +shortcut has no single remote to resolve against and does not apply. + +`--guess-remote` covers the *other* spelling — `git worktree add ` with no `` at +all. It bases the new branch on the remote-tracking branch matching `$(basename )` when +exactly one remote has it, and marks that branch as upstream. Its default comes from the +`worktree.guessRemote` config. ## Repair after a manual move ```bash -git worktree repair # run from the main worktree: fixes the links to every linked worktree -git worktree repair # run from a moved linked worktree: fixes its own pointer back to main +git worktree repair # the MAIN worktree moved: run it there to reconnect every linked + # worktree back to the main worktree +git worktree repair # a LINKED worktree moved: run it inside that recently-moved worktree +git worktree repair ... # reconnect a specific linked worktree — runnable from any worktree, + # naming each moved tree's new path ``` -`repair` reestablishes the bidirectional pointers a manual move breaks, but only for the side it is -run from. Run it from the wrong directory and it reports nothing and fixes nothing. +Which form applies depends on what moved: + +| What moved | Remedy | +|---|---| +| The main worktree (or bare repo) | `git worktree repair` in the main worktree | +| One linked worktree | `git worktree repair` inside that worktree | +| Several linked worktrees | `git worktree repair ...` from any worktree, listing each new path | +| Both main and linked worktrees | `git worktree repair ...` in the main worktree, naming each linked worktree's new path — this restores the connections in both directions | + +Only the no-argument form is tied to the current directory. The `...` form is not — it +reestablishes the connection to every path you name, run from any worktree. ## Configuration @@ -111,6 +145,10 @@ git worktree remove ../temp context switch: ```bash -git worktree add ../review-pr-123 origin/feature-xyz +git worktree add ../review-pr-123 origin/feature-xyz # detached HEAD — read-only review +git worktree add --track -b feature-xyz ../review-pr-123 origin/feature-xyz # if you will commit # open ../review-pr-123 in a second editor window or terminal ``` + +Pick the second form the moment you intend to push anything back: the first leaves no branch to +push and no upstream to push to. diff --git a/plugins/git/skills/git-worktrees/SKILL.md b/plugins/git/skills/git-worktrees/SKILL.md index 2a74445..f69223c 100644 --- a/plugins/git/skills/git-worktrees/SKILL.md +++ b/plugins/git/skills/git-worktrees/SKILL.md @@ -24,18 +24,19 @@ metadata: | Operation | Run | |---|---| -| Create on an existing branch | `git worktree add ` | +| Create on a branch that already exists locally | `git worktree add ` | | Create on a new branch | `git worktree add -b ` | | Create on the branch named after the path basename | `git worktree add ` — checks that branch out if it exists, else creates it from HEAD | | Create and reset an existing branch to HEAD — discards its commits | `git worktree add -B ` | -| Create tracking a remote branch | `git worktree add /` | -| Throwaway experiment, no branch | `git worktree add -d ` | +| Create a local branch tracking a remote one | `git worktree add --track -b /` — always correct. `git worktree add ` expands to exactly this, but **only** when `` has no local copy (gate below) | +| Throwaway experiment, no branch | `git worktree add -d ` — detached HEAD | +| **Never** `git worktree add /` | That ref resolves, so the shortcut never fires and you get **a detached HEAD, no branch, no upstream**. Commits there go unreachable once HEAD moves, and `git push` needs an explicit refspec. Use the tracking row above | | List | `git worktree list -v`, or `--porcelain -z` to parse | | Lock or unlock | `git worktree lock [--reason ] ` / `git worktree unlock ` | | Move | `git worktree move ` | | Remove | `git worktree remove ` | | Prune stale metadata | `git worktree prune --dry-run`, then without the flag | -| Repair after a manual move | `git worktree repair []` — from the main worktree to fix all links, or from the moved worktree itself | +| Repair after a manual move | `git worktree repair` — in the main worktree if *it* moved, or inside a linked worktree that moved. `git worktree repair ...` — from any worktree, naming each moved linked worktree's new path | If the operation needs anything the table does not carry — the full `add` flag table, orphan branches, sparse-checkout, locking for removable media, remote @@ -47,6 +48,7 @@ Gates: - **`move`, `remove` — the main worktree cannot be moved or removed.** Only linked worktrees, the ones `git worktree add` created, are candidates. - **`add`, `move`, `remove` — escalate force flags one step at a time.** `-f` overrides a safeguard such as an unclean tree; `move` and `remove` need `-ff` on top of that when the worktree is locked. Confirm with the user before either — both discard state. - **`lock`, `move`, `remove`, `repair` — identify a worktree by full path, unique basename, or unique partial path.** An ambiguous name errors rather than picking; `git worktree list` shows the usable identifiers. +- **`add` — the bare-name tracking shortcut needs exactly one remote.** `git worktree add ` sets up tracking only when `` is absent locally, no `-b`/`-B`/`-d` is given, and exactly one remote carries the name. With several, it fires only if `checkout.defaultRemote` names one. When the remote is ambiguous or unknown, use `--track -b`. - **`add` — lock at creation, not after.** `git worktree add --lock` is atomic, where add-then-`lock` leaves a window in which the worktree is unprotected. ## Step 2 — Report diff --git a/plugins/git/skills/git-worktrees/references/worktrees.md b/plugins/git/skills/git-worktrees/references/worktrees.md index ebade88..a5cedef 100644 --- a/plugins/git/skills/git-worktrees/references/worktrees.md +++ b/plugins/git/skills/git-worktrees/references/worktrees.md @@ -15,16 +15,29 @@ or moved. Every other worktree is a **linked worktree** created by `git worktree ## `add` forms ```bash -git worktree add # check out an existing branch — non-destructive +git worktree add # exists locally: check it out — non-destructive git worktree add -b # create a new branch; fails if it exists git worktree add # branch named after $(basename ): checked out # if it exists, else created from HEAD git worktree add -B # create the branch, or reset an existing one to HEAD, # discarding the commits it carried -git worktree add / # track a remote branch +git worktree add --track -b / + # new local branch tracking the remote — always works +git worktree add # absent locally and in exactly one remote: + # Git expands this to the --track -b form above git worktree add -d # detached HEAD, no branch ``` +The same `git worktree add ` spelling appears twice above and does two +different things: it checks out a local branch when one exists, and only otherwise falls +through to the remote-tracking shortcut. Read the local branch list before relying on either. + +**Do not write `git worktree add /`.** A remote-tracking ref resolves as a +commit-ish, so the tracking shortcut never fires and the worktree lands on a **detached HEAD with +no local branch and no upstream** — commits there go unreachable once HEAD moves or the worktree is +removed, and `git push` fails without an explicit refspec. That spelling is correct only as the +final argument of the `--track -b` form. + ## Full `add` flag table | Flag | Meaning | @@ -69,19 +82,40 @@ git worktree unlock # when reconnected ## Remote-branch disambiguation ```bash -git worktree add / +git worktree add --track -b / # explicit: no guessing at all +git worktree add # shortcut: needs one clear remote ``` -For ambiguous names across remotes, `checkout.defaultRemote` config disambiguates explicitly, or `--guess-remote` auto-matches by path basename (default controlled by `worktree.guessRemote` config). If a branch name matches multiple remotes during `worktree add` and neither is set, Git refuses rather than guessing. +The shortcut fires only when `` is not found locally, none of `-b`/`-B`/`--detach` were +given, and a tracking branch of that name exists in exactly one remote. When several remotes carry +the name, `checkout.defaultRemote` picks one for disambiguation purposes; with no such setting the +shortcut has no single remote to resolve against and does not apply. + +`--guess-remote` covers the *other* spelling — `git worktree add ` with no `` at +all. It bases the new branch on the remote-tracking branch matching `$(basename )` when +exactly one remote has it, and marks that branch as upstream. Its default comes from the +`worktree.guessRemote` config. ## Repair after a manual move ```bash -git worktree repair # run from the main worktree: fixes the links to every linked worktree -git worktree repair # run from a moved linked worktree: fixes its own pointer back to main +git worktree repair # the MAIN worktree moved: run it there to reconnect every linked + # worktree back to the main worktree +git worktree repair # a LINKED worktree moved: run it inside that recently-moved worktree +git worktree repair ... # reconnect a specific linked worktree — runnable from any worktree, + # naming each moved tree's new path ``` -`repair` reestablishes the bidirectional pointers a manual move breaks, but only for the side it is -run from. Run it from the wrong directory and it reports nothing and fixes nothing. +Which form applies depends on what moved: + +| What moved | Remedy | +|---|---| +| The main worktree (or bare repo) | `git worktree repair` in the main worktree | +| One linked worktree | `git worktree repair` inside that worktree | +| Several linked worktrees | `git worktree repair ...` from any worktree, listing each new path | +| Both main and linked worktrees | `git worktree repair ...` in the main worktree, naming each linked worktree's new path — this restores the connections in both directions | + +Only the no-argument form is tied to the current directory. The `...` form is not — it +reestablishes the connection to every path you name, run from any worktree. ## Configuration @@ -111,6 +145,10 @@ git worktree remove ../temp context switch: ```bash -git worktree add ../review-pr-123 origin/feature-xyz +git worktree add ../review-pr-123 origin/feature-xyz # detached HEAD — read-only review +git worktree add --track -b feature-xyz ../review-pr-123 origin/feature-xyz # if you will commit # open ../review-pr-123 in a second editor window or terminal ``` + +Pick the second form the moment you intend to push anything back: the first leaves no branch to +push and no upstream to push to.