docs(skills): say how to resolve the main clone

Both skills said to derive the main clone from the checkout without saying
how, and dsh-upgrade names dsh-customize as the owner of checkout discovery
— so the technique belonged there and was missing.

dsh-customize now gives it: `git rev-parse --git-common-dir` from the
checkout yields the shared git directory, whose parent is the main clone.
It also names the two ways to get this wrong — the answer is relative for a
plain clone, and paths must be compared physically, since macOS reaches
/var through a symlink to /private/var.

dsh-upgrade links to that procedure rather than restating it.

Verified against both shapes: an adopted clone outside the container, and a
curl-shaped install whose clone is at <source>/master.
This commit is contained in:
Turtle
2026-07-31 22:26:11 +08:00
parent 2c29fedaf9
commit f3ff2e6ab4
2 changed files with 2 additions and 2 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ Make personal DSH changes in task worktrees and integrate them under the staging
Do not assume a path or branch name. DSH is usually installed from source with a personal staging branch; create one for the user only when none exists.
1. Inspect `command -v dsh` in the user's launch environment before resolving symlinks.
2. Follow the launcher through the full symlink chain to identify the source checkout. The standard [`scripts/install.sh`](../../scripts/install.sh) keeps staging checkouts under one container `${DSH_SOURCE}` (default `~/.dsh/source`), each a git worktree `${DSH_SOURCE}/staging-<timestamp>`. The main clone — the one real clone whose object store every worktree shares — is at `${DSH_SOURCE}/master` for a `curl` install, but installing from an existing clone adopts that clone wherever it lives, so derive it from the checkout rather than assuming it sits in the container or on any particular branch. `${DSH_BIN_DIR}/dsh` links to `${DSH_SOURCE}/current/bin/dsh`, and the stable `current` symlink points at the active staging worktree, so resolve `current` to reach the real checkout. All paths are configurable; an older install may link PATH straight at a worktree (no `current`) or use scattered sibling clones — follow the launcher rather than assuming a layout.
2. Follow the launcher through the full symlink chain to identify the source checkout. The standard [`scripts/install.sh`](../../scripts/install.sh) keeps staging checkouts under one container `${DSH_SOURCE}` (default `~/.dsh/source`), each a git worktree `${DSH_SOURCE}/staging-<timestamp>`. The main clone — the one real clone whose object store every worktree shares — is at `${DSH_SOURCE}/master` for a `curl` install, but installing from an existing clone adopts that clone wherever it lives, so never assume it sits in the container or on any particular branch. Resolve it from the checkout: `git -C <checkout> rev-parse --git-common-dir` gives the shared git directory (a linked worktree reports the real clone's, not its own), and its parent is the main clone. That answer is relative for a plain clone, so anchor it against the checkout before use, and resolve it physically — comparing a resolved path against an unresolved one silently misidentifies the clone, since macOS reaches `/var` through a symlink to `/private/var`. `${DSH_BIN_DIR}/dsh` links to `${DSH_SOURCE}/current/bin/dsh`, and the stable `current` symlink points at the active staging worktree, so resolve `current` to reach the real checkout. All paths are configurable; an older install may link PATH straight at a worktree (no `current`) or use scattered sibling clones — follow the launcher rather than assuming a layout.
3. Verify the checkout with Git, then record its branch, tip, status, remotes, worktrees, in-progress operations, and applicable `AGENTS.md` files.
4. Treat the launcher checkout's branch as staging unless the user says otherwise. The installed launcher must resolve to a staging worktree on a staging branch, never the main clone or a task, preparation, review, publication, or detached checkout. Ask if the launcher, checkout, or branch ownership is ambiguous; warn explicitly for a detached HEAD, the main clone, or a non-staging branch.
+1 -1
View File
@@ -9,7 +9,7 @@ Prepare and validate the upgrade in a fresh staging worktree of the main clone,
## Layout
A source-installed DSH keeps its staging checkouts and `current` under one container directory `<source>` (default `~/.dsh/source`): each staging checkout is a git worktree `<source>/staging-<timestamp>` on branch `dsh-staging/<timestamp>`. The main clone — the one real clone holding the object store every worktree shares, and never a launcher target — is at `<source>/master` for a `curl` install, but the container owns worktrees rather than the repository: installing from an existing clone adopts that clone wherever it already lives, so resolve it with `git rev-parse --git-common-dir` from the staging worktree instead of assuming a path. Do not assume the main clone sits on `master` or that its `origin` is authoritative upstream — an adopted clone keeps whatever branch and remotes it had, and may point at a fork. The upgrade fetches upstream separately, per step 1. The stable symlink `<source>/current` points at the active staging worktree, and the PATH launcher links to `<source>/current/bin/dsh`, so the launcher resolves PATH -> `current` -> staging worktree. Cutover repoints `current` alone; the PATH launcher is written once at install and never moves. All worktrees share the main clone's single `.git` object store; the main clone's `.git/info/exclude` is inherited by every linked worktree, so one `.agents/merge.lock` entry there excludes the lock in all of them. An older install may link PATH straight at a worktree (no `current`) or use scattered sibling clones; if so, follow the recorded launcher checkout rather than assuming this layout, treat that sibling clone as its own main clone, and create `current` and repoint PATH to `current/bin/dsh` as a one-time migration at cutover.
A source-installed DSH keeps its staging checkouts and `current` under one container directory `<source>` (default `~/.dsh/source`): each staging checkout is a git worktree `<source>/staging-<timestamp>` on branch `dsh-staging/<timestamp>`. The main clone — the one real clone holding the object store every worktree shares, and never a launcher target — is at `<source>/master` for a `curl` install, but the container owns worktrees rather than the repository: installing from an existing clone adopts that clone wherever it already lives, so resolve it from the staging worktree by the procedure in [`dsh-customize`](../dsh-customize/SKILL.md) instead of assuming a path. Do not assume the main clone sits on `master` or that its `origin` is authoritative upstream — an adopted clone keeps whatever branch and remotes it had, and may point at a fork. The upgrade fetches upstream separately, per step 1. The stable symlink `<source>/current` points at the active staging worktree, and the PATH launcher links to `<source>/current/bin/dsh`, so the launcher resolves PATH -> `current` -> staging worktree. Cutover repoints `current` alone; the PATH launcher is written once at install and never moves. All worktrees share the main clone's single `.git` object store; the main clone's `.git/info/exclude` is inherited by every linked worktree, so one `.agents/merge.lock` entry there excludes the lock in all of them. An older install may link PATH straight at a worktree (no `current`) or use scattered sibling clones; if so, follow the recorded launcher checkout rather than assuming this layout, treat that sibling clone as its own main clone, and create `current` and repoint PATH to `current/bin/dsh` as a one-time migration at cutover.
## Names