mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-04-06 03:03:36 +00:00
fix(memory): use parent tree in dream-restore revert to properly undo commit
The revert method was using the commit's own tree instead of its parent's, which meant /dream-restore would restore TO that commit rather than UNDO it. Also add root commit guard to prevent crash when reverting the initial commit.
This commit is contained in:
parent
475ea06294
commit
a662ace8dd
@ -238,10 +238,11 @@ class GitStore:
|
||||
# -- restore ---------------------------------------------------------------
|
||||
|
||||
def revert(self, commit: str) -> str | None:
|
||||
"""Restore all tracked memory files to their state at the given commit.
|
||||
"""Revert (undo) the changes introduced by the given commit.
|
||||
|
||||
Restores all tracked memory files to the state at the commit's parent,
|
||||
then creates a new commit recording the revert.
|
||||
|
||||
This reads the file contents from the target commit, writes them back,
|
||||
and creates a new commit. Does not require merge3.
|
||||
Returns the new commit SHA, or None on failure.
|
||||
"""
|
||||
if not self.is_initialized():
|
||||
@ -255,13 +256,20 @@ class GitStore:
|
||||
logger.warning("Git revert: SHA not found: {}", commit)
|
||||
return None
|
||||
|
||||
restored: list[str] = []
|
||||
with Repo(str(self._workspace)) as repo:
|
||||
commit_obj = repo[full_sha]
|
||||
if commit_obj.type_name != b"commit":
|
||||
return None
|
||||
tree = repo[commit_obj.tree]
|
||||
|
||||
if not commit_obj.parents:
|
||||
logger.warning("Git revert: cannot revert root commit {}", commit)
|
||||
return None
|
||||
|
||||
# Use the parent's tree — this undoes the commit's changes
|
||||
parent_obj = repo[commit_obj.parents[0]]
|
||||
tree = repo[parent_obj.tree]
|
||||
|
||||
restored: list[str] = []
|
||||
for filepath in self._tracked_files:
|
||||
content = self._read_blob_from_tree(repo, tree, filepath)
|
||||
if content is not None:
|
||||
@ -273,7 +281,7 @@ class GitStore:
|
||||
return None
|
||||
|
||||
# Commit the restored state
|
||||
msg = f"revert: restore to {commit}"
|
||||
msg = f"revert: undo {commit}"
|
||||
return self.auto_commit(msg)
|
||||
except Exception:
|
||||
logger.warning("Git revert failed for {}", commit)
|
||||
|
||||
@ -205,10 +205,14 @@ class TestRevert:
|
||||
git_ready.auto_commit("v2")
|
||||
|
||||
commits = git_ready.log()
|
||||
new_sha = git_ready.revert(commits[1].sha) # revert to init
|
||||
new_sha = git_ready.revert(commits[0].sha) # undo v2 → back to init
|
||||
assert new_sha is not None
|
||||
assert (ws / "SOUL.md").read_text(encoding="utf-8") == ""
|
||||
|
||||
def test_cannot_revert_root_commit(self, git_ready):
|
||||
commits = git_ready.log()
|
||||
assert git_ready.revert(commits[-1].sha) is None
|
||||
|
||||
def test_invalid_sha_returns_none(self, git_ready):
|
||||
assert git_ready.revert("deadbeef") is None
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user