-
-
Notifications
You must be signed in to change notification settings - Fork 9.1k
fix(cli): resolve the graph from the primary checkout in linked worktrees (#2008) #2064
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v8
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| """#2008: read commands resolve the graph from the primary checkout when they | ||
| are run from a linked git worktree that has no ``graphify-out/`` of its own. | ||
|
|
||
| Agent workflows (Claude Code etc.) increasingly run every task in its own | ||
| worktree, where ``graphify explain``/``query``/``path``/``affected`` used to fail | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using Path here improves readability. Is there any scenario where _GRAPHIFY_OUT could be missing or invalid? If so, should that be handled explicitly?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks !!! Agreed on Path. On _GRAPHIFY_OUT — it isn't a value that gets passed in while the program runs. It's a fixed setting loaded once at the top of the file (line 14), so it's always a valid string (defaults to graphify-out). If it were ever wrong, the program wouldn't even start — it'd fail right at import, not inside this function. The only tricky case is when it's set to an absolute path, and that's already handled at line 114 (the os.path.isabs check). So there's nothing extra to handle here. That said, I'm happy to add a check if you'd still like one just to be safe. |
||
| hard with "graph file not found" because the graph lives in the primary checkout. | ||
| """ | ||
| from __future__ import annotations | ||
|
|
||
| import shutil | ||
| import subprocess | ||
| from pathlib import Path | ||
|
|
||
| import pytest | ||
|
|
||
|
|
||
| def _git(*args, cwd): | ||
| subprocess.run(["git", *args], cwd=cwd, check=True, capture_output=True, text=True) | ||
|
|
||
|
|
||
| def _init_repo(tmp_path) -> Path: | ||
| primary = tmp_path / "primary" | ||
| primary.mkdir() | ||
| _git("init", "-q", ".", cwd=primary) | ||
| _git("config", "user.email", "t@t.co", cwd=primary) | ||
| _git("config", "user.name", "t", cwd=primary) | ||
| (primary / "f.txt").write_text("x", encoding="utf-8") | ||
| _git("add", "-A", cwd=primary) | ||
| _git("commit", "-qm", "init", cwd=primary) | ||
| return primary | ||
|
|
||
|
|
||
| def _write_graph(where: Path) -> Path: | ||
| graph = where / "graphify-out" / "graph.json" | ||
| graph.parent.mkdir(parents=True) | ||
| graph.write_text("{}", encoding="utf-8") | ||
| return graph | ||
|
|
||
|
|
||
| def test_default_graph_path_resolves_from_linked_worktree(tmp_path, monkeypatch): | ||
| """From a linked worktree with no local graphify-out, the read-command default | ||
| graph path falls back to the primary checkout's graph.""" | ||
| if shutil.which("git") is None: # pragma: no cover | ||
| pytest.skip("git not available") | ||
| primary = _init_repo(tmp_path) | ||
| graph = _write_graph(primary) | ||
| linked = tmp_path / "linked" | ||
| _git("worktree", "add", "-q", str(linked), "-b", "feature", cwd=primary) | ||
|
|
||
| monkeypatch.chdir(linked) | ||
| from graphify.cli import _default_graph_path | ||
| assert Path(_default_graph_path()).resolve() == graph.resolve() | ||
|
|
||
|
|
||
| def test_default_graph_path_prefers_local_graph_in_worktree(tmp_path, monkeypatch): | ||
| """A worktree that built its own graph keeps using it (local wins).""" | ||
| if shutil.which("git") is None: # pragma: no cover | ||
| pytest.skip("git not available") | ||
| primary = _init_repo(tmp_path) | ||
| _write_graph(primary) | ||
| linked = tmp_path / "linked" | ||
| _git("worktree", "add", "-q", str(linked), "-b", "feature", cwd=primary) | ||
| local_graph = _write_graph(linked) | ||
|
|
||
| monkeypatch.chdir(linked) | ||
| from graphify.cli import _default_graph_path | ||
| assert Path(_default_graph_path()).resolve() == local_graph.resolve() | ||
|
|
||
|
|
||
| def test_default_graph_path_primary_checkout_unaffected(tmp_path, monkeypatch): | ||
| """In the primary checkout the default stays the local graphify-out path, even | ||
| when the graph does not exist yet (normal 'run extract' error path preserved).""" | ||
| if shutil.which("git") is None: # pragma: no cover | ||
| pytest.skip("git not available") | ||
| primary = _init_repo(tmp_path) | ||
|
|
||
| monkeypatch.chdir(primary) | ||
| from graphify.cli import _default_graph_path | ||
| assert Path(_default_graph_path()) == Path("graphify-out") / "graph.json" | ||
|
|
||
|
|
||
| def test_default_graph_path_outside_git_repo_unaffected(tmp_path, monkeypatch): | ||
| """Outside any git repo the resolver must not crash and returns the local default.""" | ||
| monkeypatch.chdir(tmp_path) | ||
| from graphify.cli import _default_graph_path | ||
| assert Path(_default_graph_path()) == Path("graphify-out") / "graph.json" | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice helper function. Would it be worth adding a short docstring explaining why graph.json is the default output path?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks !!! Actually both new functions already carry docstrings, If I mention specifically _default_graph_path (lines 85–93) and _worktree_primary_graph (lines 104–113). _default_graph_path explains why <GRAPHIFY_OUT>/graph.json is the default and how the worktree fallback kicks in, and _worktree_primary_graph documents the git-dir vs. git-common-dir check and every case where it returns None. Btw I am happy to extend further if any part seems less explanatory.