Describe the bug
moon query changed-files --base <X> --head <Y> does not return the diff between X and Y. It silently drops --head and instead returns git diff <X> (one-arg, i.e. base → working tree) unioned with git status (local uncommitted state). Files touched in commits after --head, plus any local
modifications, show up as false positives. This breaks any commit-by-commit walk (release notes, per-commit "which projects were affected" gating, etc.).
Steps to reproduce
Repro repo: https://github.com/nicolasgere/moon-bug-repro — three linear commits: PARENT (root), MID (touches only pkg-a/a.txt), TIP (touches only pkg-b/b.txt), plus later README commits on main.
- Clone and install the pinned Moon version:
git clone https://github.com/nicolasgere/moon-bug-repro.git
cd moon-bug-repro
proto install # pins moon 2.2.3 via .prototools
- Resolve the three commits:
MID="$(git rev-list -1 --grep='^commit2: only pkg-a' HEAD)"
PARENT="$(git rev-parse "${MID}^")"
- Compare Git vs Moon for the
PARENT..MID range:
git diff --name-only "$PARENT" "$MID"
# pkg-a/a.txt
moon query changed-files --base "$PARENT" --head "$MID" -q | jq '.files'
# [
# "pkg-b/b.txt", <- false positive (only changed in TIP, after --head)
# "pkg-a/a.txt",
# "README.md" <- false positive (only changed on main after TIP)
# ]
--remote produces the same wrong result.
- With
MOON_LOG=trace, Moon parses the args correctly:
moon_app::queries::changed_files Against remote using base "<PARENT>" with head "<MID>"
…but then issues a one-arg git diff (no <HEAD>):
git diff --name-status --no-color --relative --ignore-submodules -z <PARENT>
…followed by:
moon_app::queries::changed_files Against local index
git status --porcelain --untracked-files --ignore-submodules -z
So the effective query is git diff <BASE> ∪ git status, regardless of --head. Confirmed by running the same one-arg command directly — it returns exactly Moon's buggy file list.
Expected behavior
When both --base and --head are passed as explicit revisions, moon query changed-files should:
- Run
git diff --name-status … <BASE> <HEAD> (two-arg) and return only the files in that tree-to-tree diff.
- Not consult
git status / the local index — the user requested a diff between two SHAs, not a working-tree comparison.
i.e. the result should match git diff --name-only <BASE> <HEAD>.
Screenshots
N/A — terminal output included above.
Environment
System:
OS: macOS 26.3
CPU: (18) arm64 Apple M5 Pro
Memory: 461.39 MB / 48.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 22.14.0 - /Users/nicolas/.proto/tools/node/22.14.0/bin/node
npm: 10.9.2 - /Users/nicolas/.proto/tools/node/22.14.0/bin/npm
pnpm: 10.29.3 - /Users/nicolas/.proto/shims/pnpm
Utilities:
Git: 2.53.0 - /opt/homebrew/bin/git
moon: 2.2.3 (installed via proto 0.56.4)
Additional context
- Affects any workflow that walks history commit-by-commit and pipes ranges into
moon query changed-files or moon query projects --affected — release-notes generators and per-commit affected-project gating will silently report wrong results.
- The bug shows up even with a clean working tree (no uncommitted edits); the false positives come from commits after
--head, because git diff <BASE> compares base → working tree.
- Suspected location: the changed-files query path in
moon_app::queries::changed_files — the explicit---head branch appears to fall through to the same code as the implicit/local case.
Describe the bug
moon query changed-files --base <X> --head <Y>does not return the diff betweenXandY. It silently drops--headand instead returnsgit diff <X>(one-arg, i.e. base → working tree) unioned withgit status(local uncommitted state). Files touched in commits after--head, plus any localmodifications, show up as false positives. This breaks any commit-by-commit walk (release notes, per-commit "which projects were affected" gating, etc.).
Steps to reproduce
Repro repo: https://github.com/nicolasgere/moon-bug-repro — three linear commits:
PARENT(root),MID(touches onlypkg-a/a.txt),TIP(touches onlypkg-b/b.txt), plus later README commits onmain.PARENT..MIDrange:--remoteproduces the same wrong result.MOON_LOG=trace, Moon parses the args correctly:git diff(no<HEAD>):git diff <BASE>∪git status, regardless of--head. Confirmed by running the same one-arg command directly — it returns exactly Moon's buggy file list.Expected behavior
When both
--baseand--headare passed as explicit revisions,moon query changed-filesshould:git diff --name-status … <BASE> <HEAD>(two-arg) and return only the files in that tree-to-tree diff.git status/ the local index — the user requested a diff between two SHAs, not a working-tree comparison.i.e. the result should match
git diff --name-only <BASE> <HEAD>.Screenshots
N/A — terminal output included above.
Environment
Additional context
moon query changed-filesormoon query projects --affected— release-notes generators and per-commit affected-project gating will silently report wrong results.--head, becausegit diff <BASE>compares base → working tree.moon_app::queries::changed_files— the explicit---headbranch appears to fall through to the same code as the implicit/local case.