From 0314b8e7cf8bfa4de8170da2b3ba9d62eff037c4 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Sat, 17 Oct 2026 09:39:01 +0200 Subject: [PATCH] reuse_refs_check: sibling repos beside the MAIN clone for a worktree (R-1114) FELHOM_WORKSPACE (set by felhom-controller's runner) names where the sibling repos are; the worktree's own main clone is skipped. Unset: unchanged. Test red-proved both ways. Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS --- scripts/CHANGELOG.md | 8 ++++++++ scripts/reuse_refs_check.py | 24 ++++++++++++++++++++++-- scripts/test_reuse_refs_check.py | 24 ++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/scripts/CHANGELOG.md b/scripts/CHANGELOG.md index d317b5cb..29dea761 100644 --- a/scripts/CHANGELOG.md +++ b/scripts/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2026-10-17 — reuse_refs_check.py: sibling repos beside the MAIN clone, for a worktree (R-1114) + +`find_siblings` reads `FELHOM_WORKSPACE` when set — felhom-controller's runner sets it to the main clone's parent +(`controller/scripts/shared_scripts.py`) — and skips the worktree's own main clone, so a path deleted in the worktree +never resolves in the main clone. Unset, nothing changes (the other three runners). Test +`test_worktree_searches_the_workspace_not_its_own_main_clone`, red-proved both ways (no env → the sibling is not found; +no skip → the main clone is searched). + ## 2026-10-16 — build-hub.sh 1.25.0: a version number is pushed once (R-1098) `scripts/build-hub.sh` refuses `--push`/`--multiarch` of a tag the registry already has, and refuses when the registry diff --git a/scripts/reuse_refs_check.py b/scripts/reuse_refs_check.py index 67e0f6a3..f83703e9 100644 --- a/scripts/reuse_refs_check.py +++ b/scripts/reuse_refs_check.py @@ -115,13 +115,33 @@ def index_for(root): return _index_cache[root] +def _main_clone_of_worktree(root): + """The main clone of a linked worktree (its `.git` FILE reads `gitdir:
/.git/worktrees/`), else None.""" + try: + with open(os.path.join(root, ".git")) as fh: + line = fh.readline().strip() + except OSError: # a directory (a main clone) or absent + return None + if not line.startswith("gitdir:"): + return None + gitdir = os.path.realpath(line[len("gitdir:"):].strip()) + head, tail = os.path.split(os.path.dirname(gitdir)) #
/.git, "worktrees" + if tail != "worktrees" or os.path.basename(head) != ".git": + return None + return os.path.dirname(head) + + def find_siblings(root): """Immediate sibling dirs of that are themselves git working trees. One level only. Returns (list_of_paths, error_message_or_None). A sibling repo that is simply absent is NEVER a failure — a clone in isolation must still be able to check itself. """ - parent = os.path.dirname(os.path.abspath(root)) + # FELHOM_WORKSPACE (R-1114): set by felhom-controller's runner to the MAIN clone's parent when is a + # worktree outside git/ (its own parent holds other worktrees, not the sibling repos). The main clone of + # itself is then skipped: a path deleted in the worktree must not resolve in the main clone. + parent = os.environ.get("FELHOM_WORKSPACE") or os.path.dirname(os.path.abspath(root)) + own_main = _main_clone_of_worktree(root) try: entries = sorted(os.listdir(parent)) except OSError as e: @@ -129,7 +149,7 @@ def find_siblings(root): sibs = [] for e in entries: p = os.path.join(parent, e) - if os.path.abspath(p) == os.path.abspath(root): + if os.path.abspath(p) == os.path.abspath(root) or (own_main and os.path.realpath(p) == own_main): continue if os.path.isdir(p) and os.path.exists(os.path.join(p, ".git")): sibs.append(p) diff --git a/scripts/test_reuse_refs_check.py b/scripts/test_reuse_refs_check.py index d39096aa..34409cc0 100644 --- a/scripts/test_reuse_refs_check.py +++ b/scripts/test_reuse_refs_check.py @@ -17,6 +17,7 @@ import shutil import sys import tempfile import unittest +from unittest import mock SCRIPT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "reuse_refs_check.py") @@ -119,6 +120,29 @@ class ReuseRefsCheckTest(unittest.TestCase): self.assertEqual(rc, 0, out) self.assertIn("cross-repo", out) + # ── R-1114: a worktree outside git/ searches the workspace, never its own main clone ── + def test_worktree_searches_the_workspace_not_its_own_main_clone(self): + ws = os.path.join(self.tmp, "git") + main = os.path.join(ws, "mainrepo") + os.makedirs(os.path.join(main, ".git", "worktrees", "b3")) + write(os.path.join(main, "only", "in", "main.go"), "package in\n") + shared = os.path.join(ws, "felhom.eu") + os.makedirs(os.path.join(shared, ".git")) + write(os.path.join(shared, "scripts", "x.py"), "# gate\n") + wt = os.path.join(self.tmp, "wt", "b3") + write(os.path.join(wt, ".git"), "gitdir: %s\n" % os.path.join(main, ".git", "worktrees", "b3")) + write(os.path.join(wt, "REUSE.md"), "run `felhom.eu/scripts/x.py`\n") + rc, out = self.run_check(wt) + self.assertNotEqual(rc, 0, "without FELHOM_WORKSPACE the worktree's own parent holds no felhom.eu:\n" + out) + with mock.patch.dict(os.environ, {"FELHOM_WORKSPACE": ws}): + rc, out = self.run_check(wt) + self.assertEqual(rc, 0, out) + self.assertNotIn("mainrepo", out.split("siblings searched:")[-1]) # its own main clone is skipped + # a path that exists only in the main clone (deleted in the worktree) must NOT resolve there + write(os.path.join(wt, "REUSE.md"), "see `only/in/main.go`\n") + rc, out = self.run_check(wt) + self.assertNotEqual(rc, 0, out) + def test_non_git_sibling_is_not_searched(self): plain = os.path.join(self.tmp, "notarepo") # no .git — not a repo, must not resolve write(os.path.join(plain, "pkg", "x.go"), "package pkg\n")