gabriel / muse public
feat patch task/restore-command #1 / 1
gabriel · 166 days ago · Apr 14, 2026 · Diff

feat: implement muse restore — working-tree and stage file restoration

Dedicated file restoration: --worktree (default) restores disk from stage or HEAD; --staged unstages (removes stage entry); --staged --worktree resets both. --source <ref> targets any commit or branch. Delegates object fetch to restore_object (inode-preserving, integrity-verified). 26 TDD tests: unit helpers, worktree/staged/both modes, --source, multi-path, dry-run, JSON, security (path traversal rejected), stress (100 files).

sha256:8e9d40a19ecb5debe9a28b776dee78555efe0be65c32d92a2ab1ed7b3e3dc2c2 sha
+82 ~110 symbols
sha256:a079ae256f517a71793b6673d0e6f67dfbb92dc0a0598e0e5a30e6f9108e58bd snapshot
+82
symbols added
~110
symbols modified
0
dead code introduced
Semantic Changes 192 symbols
~ muse/cli/commands/restore.py .py 28 symbols added
+ _RestoreResult class class _RestoreResult L98–104
+ _resolve_file_path function function _resolve_file_path L148–181
+ _resolve_source_manifest function function _resolve_source_manifest L112–145
+ ExitCode import import ExitCode L76–76
+ Manifest import import Manifest L79–79
+ StagedFileMap import import StagedFileMap L88–88
+ TypedDict import import TypedDict L74–74
+ _json import import _json L70–70
+ annotations import import annotations L67–67
+ argparse import import argparse L69–69
+ contain_path import import contain_path L87–87
+ get_head_commit_id import import get_head_commit_id L79–79
+ logging import import logging L71–71
+ pathlib import import pathlib L72–72
+ read_commit import import read_commit L79–79
+ read_current_branch import import read_current_branch L79–79
+ read_repo_id import import read_repo_id L78–78
+ read_snapshot import import read_snapshot L79–79
+ read_stage import import read_stage L88–88
+ require_repo import import require_repo L78–78
+ resolve_commit_ref import import resolve_commit_ref L79–79
+ restore_object import import restore_object L77–77
+ sanitize_display import import sanitize_display L87–87
+ sys import import sys L73–73
+ write_stage import import write_stage L88–88
+ logger variable variable logger L90–90
+ register function function register L189–246
+ run function function run L254–417
~ tests/test_cmd_restore.py .py 53 symbols added
+ _REPO_ID variable variable _REPO_ID L33–33
+ _commit_files function function _commit_files L63–92
+ _counter variable variable _counter L45–45
+ _env function function _env L59–60
+ _init_repo function function _init_repo L48–56
+ _invoke function function _invoke L95–97
+ _sha function function _sha L41–42
+ CliRunner import import CliRunner L23–23
+ CommitRecord import import CommitRecord L27–27
+ Manifest import import Manifest L28–28
+ SnapshotRecord import import SnapshotRecord L27–27
+ StagedFileMap import import StagedFileMap L29–29
+ annotations import import annotations L14–14
+ compute_commit_id import import compute_commit_id L26–26
+ compute_snapshot_id import import compute_snapshot_id L26–26
+ datetime import import datetime L16–16
+ hashlib import import hashlib L17–17
+ json import import json L18–18
+ make_entry import import make_entry L29–29
+ pathlib import import pathlib L19–19
+ pytest import import pytest L21–21
+ read_stage import import read_stage L29–29
+ write_commit import import write_commit L27–27
+ write_object import import write_object L25–25
+ write_snapshot import import write_snapshot L27–27
+ write_stage import import write_stage L29–29
+ runner variable variable runner L31–31
+ test_resolve_file_path_inside_repo function function test_resolve_file_path_inside_repo L123–127
+ test_resolve_file_path_traversal_raises function function test_resolve_file_path_traversal_raises L130–135
+ test_resolve_source_manifest_empty_repo function function test_resolve_source_manifest_empty_repo L115–120
+ test_resolve_source_manifest_from_head function function test_resolve_source_manifest_from_head L105–112
+ test_restore_100_modified_files function function test_restore_100_modified_files L443–456
+ test_restore_dry_run_json function function test_restore_dry_run_json L389–398
+ test_restore_dry_run_no_disk_change function function test_restore_dry_run_no_disk_change L365–373
+ test_restore_dry_run_no_stage_change function function test_restore_dry_run_no_stage_change L376–386
+ test_restore_exit_zero_on_success function function test_restore_exit_zero_on_success L191–196
+ test_restore_file_not_in_head_exits_nonzero function function test_restore_file_not_in_head_exits_nonzero L199–203
+ test_restore_json_output_structure function function test_restore_json_output_structure L406–416
+ test_restore_multiple_paths function function test_restore_multiple_paths L346–357
+ test_restore_path_traversal_rejected function function test_restore_path_traversal_rejected L424–428
+ test_restore_source_file_not_in_that_commit_exits_nonzero function function test_restore_source_file_not_in_that_commit_exits_nonzero L332–338
+ test_restore_source_ref_not_found_exits_nonzero function function test_restore_source_ref_not_found_exits_nonzero L325–329
+ test_restore_source_ref_restores_from_commit function function test_restore_source_ref_restores_from_commit L309–322
+ test_restore_staged_does_not_touch_disk function function test_restore_staged_does_not_touch_disk L225–237
+ test_restore_staged_not_staged_is_noop function function test_restore_staged_not_staged_is_noop L272–277
+ test_restore_staged_path_traversal_rejected function function test_restore_staged_path_traversal_rejected L431–435
+ test_restore_staged_removes_added_file function function test_restore_staged_removes_added_file L240–256
+ test_restore_staged_removes_modification function function test_restore_staged_removes_modification L211–222
+ test_restore_staged_undeletes_from_stage function function test_restore_staged_undeletes_from_stage L259–269
+ test_restore_staged_worktree_resets_both function function test_restore_staged_worktree_resets_both L285–301
+ test_restore_worktree_does_not_touch_stage function function test_restore_worktree_does_not_touch_stage L155–172
+ test_restore_worktree_from_staged_content function function test_restore_worktree_from_staged_content L175–188
+ test_restore_worktree_overwrites_modified_file function function test_restore_worktree_overwrites_modified_file L143–152
← Older Oldest on task/restore-command
All commits
Newer → Latest on task/restore-command

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:8e9d40a19ecb5debe9a28b776dee78555efe0be65c32d92a2ab1ed7b3e3dc2c2 --body "your comment"