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

feat: implement muse merge-tree — three-way merge without working-tree mutation

- Pure in-memory three-way merge using existing diff_snapshots / detect_conflicts / apply_merge primitives - Resolves branch refs via HEAD, branch name, or full commit ID - Computes LCA via find_merge_base (bidirectional BFS) or --base override - Conflict paths reported with null object_id in merged_manifest - --write-objects persists the conflict-free merged snapshot for use with commit-tree - No MERGE_STATE.json written, no working-tree I/O, no branch ref updates - 25 tests: clean merge, conflicts, trivial, explicit base, working-tree isolation, write-objects, text output, error cases, ANSI rejection, 50-file stress

sha256:1b4d8fc22bde0b07389ba32ab25df236d960705dbd7a9917bc8f7acd91212358 sha
+77 ~33 symbols
sha256:38ea2e597dfe8f312d91451f5ed3a65d8950e12bc1ea70e63884d477575e3ccd snapshot
+77
symbols added
~33
symbols modified
0
dead code introduced
Semantic Changes 110 symbols
~ muse/cli/commands/merge_tree.py .py 24 symbols added
+ _SAFE_REF_RE variable variable _SAFE_REF_RE L90–90
+ _print_text function function _print_text L288–309
+ _resolve_ref function function _resolve_ref L98–117
+ Any import import Any L69–69
+ ExitCode import import ExitCode L71–71
+ _json import import _json L65–65
+ annotations import import annotations L62–62
+ apply_merge import import apply_merge L72–72
+ argparse import import argparse L64–64
+ detect_conflicts import import detect_conflicts L72–72
+ diff_snapshots import import diff_snapshots L72–72
+ find_merge_base import import find_merge_base L72–72
+ get_head_commit_id import import get_head_commit_id L79–79
+ logging import import logging L66–66
+ re import import re L67–67
+ read_commit import import read_commit L79–79
+ read_current_branch import import read_current_branch L79–79
+ read_snapshot import import read_snapshot L79–79
+ require_repo import import require_repo L78–78
+ sanitize_display import import sanitize_display L85–85
+ sys import import sys L68–68
+ logger variable variable logger L87–87
+ register function function register L125–163
+ run function function run L171–285
~ tests/test_cmd_merge_tree.py .py 52 symbols added
+ _REPO_ID variable variable _REPO_ID L37–37
+ _commit function function _commit L77–102
+ _counter variable variable _counter L38–38
+ _env function function _env L61–62
+ _init_repo function function _init_repo L50–58
+ _invoke function function _invoke L105–107
+ _setup_conflicting_repo function function _setup_conflicting_repo L135–142
+ _setup_divergent_repo function function _setup_divergent_repo L110–132
+ _sha function function _sha L46–47
+ _write_files function function _write_files L65–74
+ CliRunner import import CliRunner L24–24
+ CommitRecord import import CommitRecord L27–27
+ Manifest import import Manifest L33–33
+ SnapshotRecord import import SnapshotRecord L27–27
+ 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
+ pathlib import import pathlib L19–19
+ pytest import import pytest L22–22
+ uuid import import uuid L20–20
+ write_commit import import write_commit L27–27
+ write_object import import write_object L25–25
+ write_snapshot import import write_snapshot L27–27
+ runner variable variable runner L35–35
+ test_ansi_in_branch_name_rejected function function test_ansi_in_branch_name_rejected L403–406
+ test_ansi_in_second_branch_name_rejected function function test_ansi_in_second_branch_name_rejected L409–412
+ test_both_branches_nonexistent_exits_nonzero function function test_both_branches_nonexistent_exits_nonzero L357–360
+ test_branch_order_does_not_affect_conflict_detection function function test_branch_order_does_not_affect_conflict_detection L387–395
+ test_clean_merge_exits_zero function function test_clean_merge_exits_zero L150–154
+ test_clean_merge_json_schema function function test_clean_merge_json_schema L157–164
+ test_clean_merge_manifest_contains_both_changes function function test_clean_merge_manifest_contains_both_changes L176–185
+ test_clean_merge_no_conflicts function function test_clean_merge_no_conflicts L167–173
+ test_conflicting_merge_exits_nonzero function function test_conflicting_merge_exits_nonzero L193–197
+ test_conflicting_merge_manifest_has_null_for_conflicts function function test_conflicting_merge_manifest_has_null_for_conflicts L209–214
+ test_conflicting_merge_reports_conflict_paths function function test_conflicting_merge_reports_conflict_paths L200–206
+ test_explicit_base_nonexistent_exits_nonzero function function test_explicit_base_nonexistent_exits_nonzero L250–257
+ test_explicit_base_override function function test_explicit_base_override L239–247
+ test_no_common_ancestor_exits_nonzero function function test_no_common_ancestor_exits_nonzero L363–370
+ test_no_merge_state_written function function test_no_merge_state_written L276–281
+ test_no_working_tree_mutation function function test_no_working_tree_mutation L265–273
+ test_nonexistent_branch_exits_nonzero function function test_nonexistent_branch_exits_nonzero L350–354
+ test_same_inputs_same_output function function test_same_inputs_same_output L378–384
+ test_stress_50_files_30_pct_conflicts function function test_stress_50_files_30_pct_conflicts L420–452
+ test_text_output_conflict_mentions_path function function test_text_output_conflict_mentions_path L338–342
+ test_text_output_shows_branch_names function function test_text_output_shows_branch_names L330–335
+ test_trivial_merge_one_side_unchanged function function test_trivial_merge_one_side_unchanged L222–231
+ test_write_objects_creates_snapshot function function test_write_objects_creates_snapshot L289–299
+ test_write_objects_not_default function function test_write_objects_not_default L316–322
+ test_write_objects_snapshot_matches_manifest function function test_write_objects_snapshot_matches_manifest L302–313
← Older Oldest on task/merge-tree
All commits
Newer → Latest on task/merge-tree

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:1b4d8fc22bde0b07389ba32ab25df236d960705dbd7a9917bc8f7acd91212358 --body "your comment"