chore(gitignore): ignore installer .install_method stamp (salvage of #54855) (#67364)

* chore(gitignore): ignore installer .install_method stamp

Salvage of #54855 by @drissman — rebased onto current main with root-scoped
rule and sister-marker comments alongside .update-incomplete.

Closes #66189

Root cause: scripts/install.sh writes <install>/.install_method but git
did not ignore it, so managed checkouts show ?? .install_method and
hermes update may autostash the untracked marker.

Fix: add /.install_method to .gitignore (repo-root only).

Verification: git check-ignore -v .install_method

* test(update): assert .install_method survives update autostash (#66189)

Add hermetic regression mirroring the .hermes-bootstrap-complete test:
adopt the real .gitignore, drop the installer .install_method stamp, run
the exact 'git stash push --include-untracked' the updater uses, and assert
the marker is neither swept nor reported dirty. Requested by hermes-sweeper
review on #67364.
This commit is contained in:
Bartok 2026-07-22 13:40:44 -05:00 committed by GitHub
parent 5a40fd3777
commit c07973aa81
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 55 additions and 0 deletions

5
.gitignore vendored
View File

@ -150,6 +150,11 @@ docs/superpowers/*
.update-incomplete
.update-incomplete.lock
# Installer-written method stamp in the managed checkout root (scripts/install.sh).
# Runtime metadata only — never a code change. Ignore so `git status` stays clean
# and `hermes update`'s untracked autostash does not treat it as a local edit (#66189 / #54855).
/.install_method
# Tool Search live-test harness output — non-deterministic model transcripts,
# regenerated by scripts/tool_search_livetest.py. Never an artifact of the repo.
scripts/out/

View File

@ -901,3 +901,53 @@ def test_bootstrap_marker_not_autostashed_by_update(tmp_path):
["git", "status", "--porcelain"], cwd=tmp_path, capture_output=True, text=True
).stdout
assert ".hermes-bootstrap-complete" not in status
def test_install_method_marker_not_autostashed_by_update(tmp_path):
"""#66189: the installer ``.install_method`` stamp must be git-ignored so
``hermes update``'s ``git stash push --include-untracked`` does not sweep it
into an autostash on every run.
``scripts/install.sh`` writes ``$INSTALL_DIR/.install_method`` as runtime
metadata; it is a sibling of ``.hermes-bootstrap-complete`` /
``.update-incomplete`` and must be ignored the same way. Behavioral +
hermetic: adopt the project's real ``.gitignore`` (the contract under test),
drop the marker, and confirm the exact stash invocation the updater uses
leaves it untouched.
"""
import shutil
import subprocess
if shutil.which("git") is None:
pytest.skip("git not available")
repo_gitignore = Path(hermes_main.__file__).resolve().parents[1] / ".gitignore"
def git(*args):
return subprocess.run(
["git", *args], cwd=tmp_path, capture_output=True, text=True, check=True
)
git("init", "-q")
git("config", "user.email", "t@example.com")
git("config", "user.name", "t")
(tmp_path / ".gitignore").write_text(repo_gitignore.read_text())
(tmp_path / "tracked.txt").write_text("x\n")
git("add", "-A")
git("commit", "-qm", "init")
marker = tmp_path / ".install_method"
marker.write_text("managed\n")
# Exact flags used by hermes update (hermes_cli/main.py).
git("stash", "push", "--include-untracked", "-m", "hermes-update-autostash")
assert marker.exists(), (
".install_method was swept into the update autostash — it must be listed "
"in .gitignore so `git stash -u` skips it (#66189)."
)
# It must not even register as a dirty/untracked change.
status = subprocess.run(
["git", "status", "--porcelain"], cwd=tmp_path, capture_output=True, text=True
).stdout
assert ".install_method" not in status