feat(git): add git_reflog tool for HEAD/ref movement forensics (#181)#185
Conversation
Exposes git reflog with structured output (new SHA, selector, action, message) so pre-commit and non-commit HEAD movements (aborted merges, resets, checkouts) are visible through the MCP interface. git_log only shows committed history. Params: repo_path, ref (default HEAD), max_count, all. Closes #181 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…lifier 'merge origin/main: ...' now parses action='merge' (was 'merge origin/main') while 'commit (amend)' / 'rebase (start)' qualifiers are preserved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @MementoRC's task —— View job PR Review: feat(git): add git_reflog toolTasks:
Overall this is a solid, well-scoped addition. The implementation is clean and the test suite is thorough. A few issues worth addressing before merging: Bugs / Correctness1. def git_reflog(
repo: Repo,
ref: str = "HEAD",
max_count: int | None = None,
all: bool = False, # ← shadows built-in `all()`
) -> list[dict]:This works but is poor practice and will trigger linters. Rename to 2. Parenthetical qualifier only captures the first token ( _parts = pre_colon.split()
if len(_parts) >= 2 and _parts[1].startswith("("):
action = f"{_parts[0]} {_parts[1]}"If the parenthetical contains a space (e.g., 3. 4. Format string contains NUL but output is split by newlines ( Code Quality5. all: bool = Field(default=False, ...)Same built-in shadowing issue in the model — minor, but consistent with item 1. 6. Inconsistent error return type ( except GitCommandError as e:
return [{"error": f"Reflog failed: {str(e)}"}]The return type is
7. Superfluous Performance8. No output size guard — SecurityNo security concerns. The Test CoverageThe 36 tests are well-structured and cover the main paths:
Missing tests:
Minor Nits
Summary: The core functionality is correct and the tests are solid. The main items to address are: (1) rename |
|
Claude finished @MementoRC's task —— View job PR Review: feat(git): add git_reflog toolTasks:
This is a clean, well-scoped addition. The implementation is solid and the test suite is comprehensive. I've compared against the previous review and verified what was addressed. A few items remain. Remaining Issues from Previous Review1. Both the function parameter and the Pydantic model field are still named 2. Parenthetical qualifier captures only first token ( Still present. For a subject like import re
m = re.match(r'^(\w+(?:\s+\([^)]+\))?)', pre_colon)
action = m.group(1) if m else "unknown"3. The comment says 4. Inconsistent error return type ( All other operations in this file return New Observations5. No size guard for unbounded queries (
6. The SecurityNo concerns. The Test CoverageThe 36 tests are well-structured:
Summary: Core functionality is correct and tests are solid. The primary items to address before merging are: (1) rename |
- Correct old_sha source (verified %gP behavior empirically; %gP yields
a reflog selector like HEAD@{1}, not a commit SHA. old_sha is now
derived from entry[i+1].new_sha, since reflog is newest-first).
- Robust action parsing via regex for multi-word parenthetical qualifiers
('commit (initial import)' now captured in full).
- Match git_log error convention (return str on failure, list[dict]|str
return annotation).
- Rename `all` param -> show_all (alias 'all' preserves MCP API);
function param keeps `all` with # noqa: A002 since dispatch bypasses
Pydantic; GitReflog model uses show_all + validation_alias='all'.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @MementoRC's task —— View job PR Review: feat(git): add git_reflog toolTasks:
This revision addresses most of the prior review feedback. Here's what was fixed and what still warrants attention. Fixed Since Previous Reviews ✅
Remaining Issues1. The Pydantic model was correctly renamed to def git_reflog(
repo: Repo,
ref: str = "HEAD",
max_count: int | None = None,
all: bool = False, # noqa: A002 ← still shadows built-in
) -> list[dict] | str:And line 326: Critical runtime concern: To resolve cleanly: either rename the function parameter to 2. Tests call The tests bypass the Pydantic model and call the function with 3. No size guard for unbounded queries
4. The Code Quality: What's Good
SecurityNo concerns. SummaryThe implementation is functionally correct and the tests are solid. The primary outstanding item is the |
|
Thanks for the thorough review — addressed in a04be55 (rebased on the latest Fixed
Known limitation I want to flag rather than hide: the adjacent-entry derivation of Not done (intentional): #8 output-size guard — the
|
… max_count contract - Use `all` consistently (model field + param both 'all' w/ noqa); drop the show_all alias indirection so schema key == function kwarg. - Add large-output warning matching git_log/git_show. - Document max_count<=0 as no-limit; add ge=0 to the model field. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @MementoRC's task —— View job PR Review: feat(git): add git_reflog toolTasks:
This revision addresses all previously raised issues. The implementation is ready to merge. Here's the final state: Resolved Since Previous Reviews ✅
|
|
Follow-up review addressed in 7024899:
Still open for your call from the prior round: |
Closes #181.
Summary
The server had no
git_reflogtool, so pre-commit and non-commit HEAD movements were invisible through the MCP interface (git_logonly shows committed history). This blocked forensics on aborted merges, resets, and thecheckout: moving from X to Ysequences that precede them.Adds
git_reflogwith structured output.API
repo_path(required),ref(optional, defaultHEAD),max_count(optional),all(optional bool →--all)new_sha,old_sha(omitted for the initial all-zeros entry), selector label (e.g.HEAD@{0}),action(checkout/merge/reset/commit/rebase/…), andmessage.Implementation
git/_commit_ops.py:git_reflog()viarepo.git.reflog('show', '--format=…', '--no-abbrev', '--no-patch', …)with NUL-separated%H/%gD/%gP/%gsfields. Action = the reflog verb, dropping the operand (merge origin/main: …→merge) while preserving parenthetical qualifiers (commit (amend),rebase (start)).git/models.py:GitReflogmodel.git/operations.py: re-export.lean/registry_git.py:ToolDefinitionregistered next togit_log.tests/unit/git/test_git_reflog.py: 36 tests (parsing, old_sha sentinel handling, action extraction across 7 subject patterns,max_count,all, error paths).README.md: tool counts 55→56 / 54→55 accessible / 26→27 git.Test plan
pixi run -e quality test-unit— passes (exit 0)pixi run -e quality lint(ruff F,E9) — clean🤖 Generated with Claude Code