mpatch 1.3.5

A smart, context-aware patch tool that applies diffs using fuzzy matching, ideal for AI-generated code.
Documentation
# Mpatch

[![CI Status](https://img.shields.io/github/actions/workflow/status/romelium/mpatch/ci.yml?branch=main&style=flat-square&logo=githubactions&logoColor=white)](https://github.com/romelium/mpatch/actions/workflows/ci.yml)
[![Latest Release](https://img.shields.io/github/v/release/romelium/mpatch?style=flat-square&logo=github&logoColor=white)](https://github.com/romelium/mpatch/releases/latest)
[![Crates.io](https://img.shields.io/crates/v/mpatch?style=flat-square&logo=rust&logoColor=white)](https://crates.io/crates/mpatch)
[![License: MIT](https://img.shields.io/crates/l/mpatch)](https://opensource.org/licenses/MIT)
[![Downloads](https://img.shields.io/crates/d/mpatch?style=flat-square)](https://crates.io/crates/mpatch)

`mpatch` is a context-aware patching utility designed to handle the "messy" reality of modern development. Unlike standard `patch` or `git apply`, which fail if line numbers or context don't match exactly, `mpatch` uses **fuzzy matching** to locate changes based on the surrounding code structure.

It is specifically engineered to apply diffs generated by **LLMs (ChatGPT, Gemini, Claude, Copilot)**, which often hallucinate line numbers or provide slightly outdated context.

---

## The Problem vs. The Solution

You ask an AI to refactor a function. It gives you a diff. However, you modified a comment in that function 5 minutes ago.

**Standard `patch`:** Fails. The context lines don't match byte-for-byte.
**`mpatch`:** Succeeds. It sees the code structure is the same and applies the fix.

| Original File (Modified Locally) | AI-Generated Patch (Stale Context) | `mpatch` Result |
| :--- | :--- | :--- |
| <pre>fn main() {<br>    // I changed this comment<br>    println!("Hello");<br>}</pre> | <pre> fn main() {<br>     // Original comment<br>-    println!("Hello");<br>+    println!("World");<br> }</pre> | <pre>fn main() {<br>    // I changed this comment<br>    println!("World");<br>}</pre> |

---

## Key Features

*   **🧠 Fuzzy Matching:** Uses a similarity algorithm to find the best location for a patch when exact matches fail. It handles stale context, whitespace changes, and minor code drift.
*   **🤖 Format Agnostic:** Automatically detects and parses:
    *   **Markdown** code blocks (standard AI output).
    *   **Raw Unified Diffs** (`git diff` output).
*   **✨ Smart Indentation:** Automatically adjusts the indentation of added lines to match the target file. Perfect for applying patches that were nested inside Markdown lists or have different tab/space styles.
*   **🛡️ Secure:** Built-in path traversal protection prevents malicious patches from writing outside the target directory (`../../etc/passwd`).
*   **⚡ High Performance:** Fuzzy searching is computationally expensive, so `mpatch` parallelizes the search across all CPU cores using `rayon`.
*   **🔍 Dry Run:** Preview changes with `--dry-run` before touching your filesystem.

---

## Installation

### Option 1: Pre-compiled Binaries (Recommended)

We provide pre-compiled binaries for Windows, macOS, and Linux.

**Using [`cargo-binstall`](https://github.com/cargo-bins/cargo-binstall#installation) (Fastest):**
```bash
cargo binstall mpatch
```

**Manual Download:**
1.  Go to the [**Releases Page**]https://github.com/romelium/mpatch/releases.
2.  Download the archive for your architecture (see table below).
3.  Extract and add to your `PATH`.

| Platform | Architecture | Target | Notes |
| :--- | :--- | :--- | :--- |
| **macOS** | Universal | `universal-apple-darwin` | **Best for Mac.** Runs natively on M1/M2/M3 & Intel. |
| | x64 | `x86_64-apple-darwin` | Older Intel Macs. |
| | ARM64 | `aarch64-apple-darwin` | Apple Silicon (M1/M2/M3). |
| **Windows** | x64 | `x86_64-pc-windows-msvc` | Standard 64-bit Windows. |
| | ARM64 | `aarch64-pc-windows-msvc` | Surface Pro X, Parallels. |
| **Linux** | x64 | `x86_64-unknown-linux-gnu` | Ubuntu, Debian, Fedora, etc. |
| | x64 (Static) | `x86_64-unknown-linux-musl` | **Alpine Linux**, Docker containers. |
| | ARM64 | `aarch64-unknown-linux-gnu` | Raspberry Pi 4/5, AWS Graviton. |
| | ARM64 (Static) | `aarch64-unknown-linux-musl` | Alpine on ARM64. |
| | ARMv7 | `armv7-unknown-linux-gnueabihf` | Older Raspberry Pi (2/3), IoT. |
| | ARMv7 (Static) | `armv7-unknown-linux-musleabihf` | Static binaries for ARMv7. |

### Verifying Signatures

All release artifacts are signed with GPG. You can verify the integrity of the downloaded files using the `.sig` signature file and our public key (`public.key`), which is included in the release assets.

1.  **Import the public key:**
    ```bash
    gpg --import public.key
    ```

2.  **Verify the archive:**
    ```bash
    # Example for Linux x64
    gpg --verify mpatch-x86_64-unknown-linux-gnu-v1.3.5.tar.gz.sig mpatch-x86_64-unknown-linux-gnu-v1.3.5.tar.gz
    ```

### Option 2: Build from Source

```bash
cargo install mpatch
```

---

## CLI Usage

### Basic Application
Apply a patch file (Markdown, Diff, or Conflict markers) to a target directory.

```bash
mpatch changes.md ./src
```

### Preview Changes (Dry Run)
See exactly what will happen without modifying files.

```bash
mpatch --dry-run changes.md ./src
```

### Adjusting Sensitivity
If `mpatch` is matching the wrong place, increase the strictness (default is 0.7). If it's failing to find a match, lower it.

```bash
# Stricter (needs 90% similarity)
mpatch --fuzz-factor 0.9 changes.md ./src

# Disable fuzzy matching (exact match only)
mpatch --fuzz-factor 0.0 changes.md ./src
```

### Debugging
If a patch fails, generate a comprehensive debug report (includes file states, logs, and diffs) to analyze why.

```bash
mpatch -vvvv changes.md ./src
# Generates: mpatch-debug-report-[timestamp].md
```

---

## Library Usage

`mpatch` is designed to be the patching engine for AI coding agents and tools. It exposes a robust Rust API.

Add to `Cargo.toml`:
```toml
[dependencies]
mpatch = "1.3.5"
```

### 1. Simple One-Shot (String to String)
Ideal for processing text in memory.

```rust
use mpatch::{patch_content_str, ApplyOptions};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let original_code = "fn main() { println!(\"Old\"); }";

    // Input can be Markdown, Raw Diff, or Conflict Markers
    let patch_text = r#"
    ```diff
    --- a/main.rs
    +++ b/main.rs
    @@ -1 +1 @@
    -fn main() { println!("Old"); }
    +fn main() { println!("New"); }
    ```
    "#;

    let options = ApplyOptions::new(); // Default fuzz_factor: 0.7
    let new_code = patch_content_str(patch_text, Some(original_code), &options)?;

    assert_eq!(new_code, "fn main() { println!(\"New\"); }");
    Ok(())
}
```

### 2. Batch Application (File System)
Ideal for CLI tools applying multi-file patches.

```rust
use mpatch::{parse_auto, apply_patches_to_dir, ApplyOptions};
use std::path::Path;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let diff_content = include_str!("../tests/fixtures/changes.md");

    // 1. Parse (automatically detects format)
    let patches = parse_auto(diff_content)?;

    // 2. Apply
    let target_dir = Path::new("./src");
    let options = ApplyOptions::new();

    let results = apply_patches_to_dir(&patches, target_dir, options);

    if results.all_succeeded() {
        println!("All patches applied successfully!");
    } else {
        // Inspect specific failures
        for (path, result) in results.hard_failures() {
            eprintln!("Failed to process {}: {}", path.display(), result);
        }
    }
    Ok(())
}
```

---

## Supported Input Formats

`mpatch` automatically detects the format. You don't need to specify flags.

1.  **Markdown Code Blocks:**
    Standard output from LLMs. Supports ` ```diff `, ` ```rust `, or even generic blocks if they contain diff headers.
2.  **Unified Diffs:**
    Standard `git diff` or `diff -u` output.

---

## Performance

Fuzzy matching is an $O(N \times M)$ operation. To ensure speed on large files:
1.  **Heuristics:** `mpatch` first attempts exact matches and "whitespace-insensitive" exact matches before falling back to fuzzy search.
2.  **Anchoring:** It scans for unique lines in the patch to narrow the search window.
3.  **Parallelism:** If a full scan is required, it uses [Rayon]https://github.com/rayon-rs/rayon to distribute the workload across all available CPU cores.

*Benchmarks are available in `benches/mpatch_bench.rs`.*

---

## Contributing

Contributions are welcome!

*   **Bug Reports:** Please run `mpatch -vvvv ...` to generate a debug report and attach it to your issue.
*   **Development:**
    ```bash
    git clone https://github.com/romelium/mpatch.git
    cd mpatch
    cargo test
    ```

## License

MIT License. See [LICENSE](LICENSE) for details.