installer skips the clone when run from inside a checkout
在检出目录内运行时安装脚本跳过克隆
`scripts/install.sh` is written for the `curl ... | sh` path: it clones the harness into `~/.dsh/source`, then installs, links, and launches. Contributors who already have a checkout and run the same script directly (`sh scripts/install.sh`) got a second, unrelated clone at `~/.dsh/source` — installing and linking a different tree than the one they were working in, with no way to exercise the local script against the
English
Problem
scripts/install.sh is written for the curl ... | sh path: it clones the harness into ~/.dsh/source, then installs, links, and launches. Contributors who already have a checkout and run the same script directly (sh scripts/install.sh) got a second, unrelated clone at ~/.dsh/source — installing and linking a different tree than the one they were working in, with no way to exercise the local script against the local source.
Decision
The script detects when it is executing from inside a real checkout and, in that mode, reuses that checkout and skips the clone/update step entirely, leaving the working tree untouched.
Detection keys on $0: under curl ... | sh the script text arrives on stdin, so $0 is the shell name and no file path resolves; running a checked-out copy makes $0 the script file. When $0 is a readable file whose parent is a scripts/ directory inside a tree that carries both the bin/dsh launcher and scripts/install.sh, the script sets IN_REPO=1 and repoints DSH_SOURCE at that repo root. Step 2 then prints a "using existing checkout" line and does nothing else — no git fetch, no git checkout -B, so the user's working tree and branch are never mutated. DSH_REF is advisory and ignored in this mode.
Explicit DSH_SOURCE wins over detection: the value is captured before defaulting, and in-repo detection only repoints an unset DSH_SOURCE (or one already equal to the detected repo root). Setting DSH_SOURCE to a different directory opts back into the normal clone/update path, so the escape hatch to install a separate tree from within a checkout still exists.
Alternatives considered
Detect via git rev-parse --show-toplevel on the current directory. Rejected: curl ... | sh frequently runs from inside some unrelated git repo (the user's cwd), which would false-positive and skip the clone against a tree that is not dsh. Anchoring on $0's own location ties the decision to where the script physically lives, and the bin/dsh + scripts/install.sh markers confirm it is actually a dsh checkout.
Always skip the clone whenever run from a file, ignoring DSH_SOURCE. Rejected: a contributor may legitimately run the in-repo script to provision a separate ~/.dsh/source install; honoring an explicit DSH_SOURCE that differs from the checkout preserves that path.
Consequences
Running sh scripts/install.sh from a checkout now installs, links, and launches that checkout instead of cloning a parallel one, which also makes the local script testable against local source. The cost is a detection block that couples to the repo layout (scripts/ beside bin/dsh); if the launcher or script ever moves, the markers must move with it. The behavior is documented in the script header and both README files, and verified by running the four paths (in-repo skip, curl-style clone, explicit DSH_SOURCE elsewhere opting back in, explicit DSH_SOURCE equal to repo root still skipping).
中文
问题
scripts/install.sh是为curl ... | sh路径编写的:它把 harness 克隆到~/.dsh/source,然后安装、软链接并启动。已经有检出的贡献者若直接运行同一脚本(sh scripts/install.sh),会在~/.dsh/source得到第二份无关的克隆——安装并软链接的是与他们正在工作的树不同的另一棵树,且无从用本地脚本验证本地源码。
决策
脚本会检测自身是否在真实检出内执行;在该模式下,它复用该检出并完全跳过克隆/更新步骤,保持工作树不受影响。
检测依据是$0:在curl ... | sh下脚本文本经由 stdin 到达,因此$0是 shell 名称、无路径可解析;运行已检出的副本会使$0成为脚本文件本身。当$0是一个可读文件、其父目录是一个scripts/目录、且该树同时带有bin/dsh启动器和scripts/install.sh时,脚本会设置IN_REPO=1并把DSH_SOURCE重新指向该仓库根。步骤 2 随后打印一行"using existing checkout"并不做其他事——不执行git fetch、不执行git checkout -B,因此用户的工作树和分支绝不会被改动。DSH_REF在该模式下仅供参考、被忽略。
显式的DSH_SOURCE优先于检测:该值在默认化之前就被捕获,检测只会重新指向未设置的DSH_SOURCE(或已经等于检测到的仓库根的那个)。把DSH_SOURCE设为其他目录会重新回到正常的克隆/更新路径,因此在检出目录内安装另一棵独立树的退路依然存在。
备选方案
通过对当前目录执行git rev-parse --show-toplevel来检测。 已否决:curl ... | sh常常在某个无关的 git 仓库(用户的cwd)内运行,这会误判并对一棵并非 dsh 的树跳过克隆。把决策锚定在$0自身的位置,使其绑定到脚本实际所在之处,而bin/dsh + scripts/install.sh标记则确认它确实是一个 dsh 检出。
只要从文件运行就总是跳过克隆,忽略DSH_SOURCE。 已否决:贡献者可能合理地运行检出内脚本来配置一份独立的~/.dsh/source安装;尊重与检出不同的显式DSH_SOURCE保留了该路径。
影响
现在从检出目录运行sh scripts/install.sh会安装、软链接并启动该检出,而不是克隆一份平行副本,这也让本地脚本可以针对本地源码进行测试。代价是一段与仓库布局耦合的检测逻辑(scripts/与bin/dsh并列);若启动器或脚本将来移动,标记必须随之移动。该行为记录在脚本头部和两份 README 中,并通过运行四条路径来验证(检出内跳过、curl 式克隆、显式DSH_SOURCE指向他处而回到克隆、显式DSH_SOURCE等于仓库根仍跳过)。