mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-04 08:28:36 +00:00
fix(gitstore): return real git object ids instead of hex-of-hex
`porcelain.commit()` and `repo.refs[...]` hand back object ids as a
40-character hex string that is already encoded to bytes. Calling `.hex()`
on that encodes the ASCII a second time, so every id GitStore produced or
displayed was double-encoded:
auto_commit() -> '62623234'
git log --abbrev=8 -> 'bb244606'
The module is self-consistently wrong, so `/dream-log` and `/dream-restore`
work as long as the id came from nanobot itself. What does not work is
crossing the boundary: ids in logs and commit output match nothing in
`git log`, and an id copied from `git log` cannot be resolved:
_resolve_sha(own id) -> b'bb244606d780...'
_resolve_sha(real git id) -> None
Use `.decode()` at the four sites that consume dulwich object ids. Nothing
persists an id — callers either display it or resolve it live — so there is
no stored state in the old format.
Adds two regression tests: the id returned by `auto_commit` must equal
`git log --abbrev=8`, and a real git id must resolve through `_resolve_sha`.
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
bb2f6cf324
commit
92361cbeac
@ -176,7 +176,10 @@ class GitStore:
|
||||
)
|
||||
if cast(object, sha_bytes) is None:
|
||||
return None
|
||||
sha = sha_bytes.hex()[:8]
|
||||
# porcelain.commit returns the id as a 40-char hex string that is
|
||||
# already encoded to bytes; .hex() would encode those ASCII bytes
|
||||
# again and produce an id no git command can resolve.
|
||||
sha = sha_bytes.decode()[:8]
|
||||
logger.debug("Git auto-commit: {} ({})", sha, message)
|
||||
return sha
|
||||
except Exception as exc:
|
||||
@ -200,7 +203,7 @@ class GitStore:
|
||||
return None
|
||||
|
||||
while sha:
|
||||
if sha.hex().startswith(short_sha):
|
||||
if sha.decode().startswith(short_sha):
|
||||
return sha
|
||||
commit_obj = repo[sha]
|
||||
if commit_obj.type_name != b"commit":
|
||||
@ -280,7 +283,7 @@ class GitStore:
|
||||
msg = commit.message.decode("utf-8", errors="replace").strip()
|
||||
if message_prefix is None or msg.startswith(message_prefix):
|
||||
entries.append(CommitInfo(
|
||||
sha=sha.hex()[:8],
|
||||
sha=sha.decode()[:8],
|
||||
message=msg,
|
||||
timestamp=ts,
|
||||
))
|
||||
@ -484,7 +487,7 @@ class GitStore:
|
||||
with Repo(str(self._workspace)) as repo:
|
||||
commit = cast("Commit", repo[full_sha])
|
||||
parent = commit.parents[0] if commit.parents else None
|
||||
diff = self.diff_commits(parent.hex()[:8], c.sha) if parent else ""
|
||||
diff = self.diff_commits(parent.decode()[:8], c.sha) if parent else ""
|
||||
return c, diff
|
||||
return None
|
||||
except Exception as exc:
|
||||
|
||||
@ -310,3 +310,25 @@ class TestNestedRepoProtection:
|
||||
|
||||
assert result is False
|
||||
assert not (workspace / ".git").exists()
|
||||
|
||||
|
||||
class TestCommitIdEncoding:
|
||||
"""Commit ids must be usable with git, not hex-of-hex."""
|
||||
|
||||
def test_auto_commit_returns_the_real_short_sha(self, git, tmp_path):
|
||||
(tmp_path / "MEMORY.md").write_text("- a fact\n", encoding="utf-8")
|
||||
sha = git.auto_commit("memory update")
|
||||
expected = subprocess.run(
|
||||
["git", "-C", str(tmp_path), "log", "-1", "--format=%h", "--abbrev=8"],
|
||||
capture_output=True, text=True, check=True,
|
||||
).stdout.strip()
|
||||
assert sha == expected
|
||||
|
||||
def test_a_real_git_sha_resolves(self, git, tmp_path):
|
||||
(tmp_path / "MEMORY.md").write_text("- a fact\n", encoding="utf-8")
|
||||
git.auto_commit("memory update")
|
||||
real = subprocess.run(
|
||||
["git", "-C", str(tmp_path), "log", "-1", "--format=%h", "--abbrev=8"],
|
||||
capture_output=True, text=True, check=True,
|
||||
).stdout.strip()
|
||||
assert git._resolve_sha(real) is not None
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user