# Mpatch
[](https://github.com/romelium/mpatch/actions/workflows/ci.yml)
[](https://github.com/romelium/mpatch/releases/latest)
[](https://crates.io/crates/mpatch)
[](https://opensource.org/licenses/MIT)
[](https://www.rust-lang.org/)
[](https://crates.io/crates/mpatch)
**A smart, context-aware patch tool for the modern developer.**
`mpatch` applies unified diffs to your codebase, but with a twist. Instead of relying on strict line numbers, it finds the correct location to apply changes based on the *surrounding context*. It's designed to work seamlessly with patches generated by AI, copied from pull requests, or stored in markdown files.
---
## Why `mpatch`?
The primary motivation for `mpatch` comes from working with Large Language Models (LLMs).
When you ask an AI like ChatGPT, Claude, or Copilot to refactor code, it often provides the changes in a convenient markdown format with ` ```diff` or ` ```patch` blocks. **However, you can't trust that the line numbers are correct.** Sometimes, even the surrounding context lines aren't a perfect, character-for-character match to your current code. A standard `patch` command will often fail in these situations.
**This is the core problem `mpatch` was built to solve.**
It intelligently ignores line numbers and uses a fuzzy, context-based search to find where the patch *should* apply. This makes it highly resilient to the small inaccuracies common in AI-generated diffs, allowing you to apply them with confidence.
This same logic makes it perfect for other common developer scenarios where patches are less formal:
* **Code Snippets:** Using a diff copied from a GitHub comment, a blog post, or a team chat.
* **Iterative Development:** Applying a patch to a branch that has slightly diverged from where the patch was created.
---
## Core Features
* **Markdown-Aware:** Directly parses unified diffs from within ````diff ` or ````patch ` code blocks in any text or markdown file.
* **Context-Driven:** Ignores `@@ ... @@` line numbers, finding patch locations by matching context lines. This makes it resilient to minor preceding changes in a file.
* **Fuzzy Matching:** If an exact context match isn't found, `mpatch` uses a sophisticated similarity algorithm to find the *best* fuzzy match. This logic can handle cases where lines have been added or removed near the patch location, allowing patches to apply even when the surrounding context has moderately diverged.
* **Safe & Secure:** Includes a `--dry-run` mode to preview changes and built-in protection against path traversal attacks.
* **Flexible:** Handles multiple files and multiple hunks in a single pass. It correctly processes file creations, modifications, and deletions (by removing all content from a file).
* **Informative Logging:** Adjustable verbosity levels (`-v`, `-vv`) to see exactly what `mpatch` is doing.
---
## Installation
### Method 1: Using `cargo-binstall` (Recommended)
For users with the [Rust toolchain](https://rustup.rs/), `cargo-binstall` is the fastest way to install `mpatch`. It downloads pre-compiled binaries, avoiding a local build.
First, install `cargo-binstall` if you don't have it:
```bash
cargo install cargo-binstall
```
Then, install `mpatch`:
```bash
cargo binstall mpatch
```
### Method 2: From GitHub Releases (Manual)
For users who don't need to build from source, pre-compiled binaries are the simplest option.
1. Navigate to the [**GitHub Releases page**](https://github.com/romelium/mpatch/releases).
2. Download the appropriate archive for your system (e.g., `mpatch-x86_64-unknown-linux-gnu.tar.gz`).
3. Extract the `mpatch` executable.
4. Move the executable to a directory in your system's `PATH` (e.g., `/usr/local/bin` on Linux/macOS, or `~/.cargo/bin`).
### Method 3: From Crates.io (Build from Source)
If you have the [Rust toolchain](https://rustup.rs/) installed, you can compile and install `mpatch` from the official package registry:
```bash
cargo install mpatch
```
### Method 4: From Source (for Developers)
To build the very latest development version or to contribute to the project:
```bash
# Install directly from the main branch of the repository
cargo install --git https://github.com/romelium/mpatch.git
# Or, to work on the code locally:
git clone https://github.com/romelium/mpatch.git
cd mpatch
cargo install --path .
```
---
## Usage
### Basic Command
```bash
mpatch [OPTIONS] <INPUT_FILE> <TARGET_DIR>
```
### Verifying Changes with `--dry-run`
Before modifying any files, you can preview the exact changes using the `-n` or `--dry-run` flag. This is the safest way to start.
```bash
mpatch --dry-run changes.md my-project/
```
This will produce a diff of the proposed changes for each file, printed directly to your terminal:
```
----- Proposed Changes for src/main.rs -----
--- a
+++ b
@@ -1,5 +1,5 @@
fn main() {
- // This is the original program
- println!("Hello, world!");
+ // This is the updated program
+ println!("Hello, mpatch!");
}
------------------------------------
DRY RUN completed. No files were modified.
```
### Applying Changes
Once you are confident in the proposed changes, run the command without `--dry-run`. Use `-v` for informational output.
```bash
mpatch -v changes.md my-project/
```
You will see a confirmation log:
```
Found 1 patch operation(s) to perform.
Fuzzy matching enabled with threshold: 0.70
>>> Operation 1/1
Applying patch to: src/main.rs
Applying Hunk 1/1...
Successfully wrote changes to 'my-project/src/main.rs'
--- Summary ---
Successful operations: 1
Failed operations: 0
```
### Key Options
* `-n`, `--dry-run`: Show what changes would be made without modifying any files.
* `-f`, `--fuzz-factor <FACTOR>`: Set the similarity threshold for fuzzy matching, from `0.0` (disabled) to `1.0` (exact match). Default is `0.7`.
* `-v`, `--verbose`: Increase logging output. Use `-v` for info, `-vv` for debug, `-vvv` for trace, and `-vvvv` to generate a comprehensive debug report file.
---
## Troubleshooting
If a patch doesn't apply as expected, the best first step is to increase the logging verbosity to understand what `mpatch` is doing.
* **Run with `-v`:** This shows which files and hunks are being processed.
* **Run with `-vv`:** This provides detailed debug information, including why a hunk might have failed to apply (e.g., "ambiguous match", "context not found").
* **Run with `-vvv`:** This enables trace-level logging, showing the fuzzy matching scores and every step of the decision-making process.
### Generating a Debug Report
For complex issues, the easiest way to gather all necessary information for a bug report is to use the `-vvvv` flag.
```bash
mpatch -vvvv changes.md my-project/
```
This command will:
1. Print full trace logs to your terminal.
2. Create a file named `mpatch-debug-report-[timestamp].md` in your current directory.
This single markdown file contains everything needed to reproduce the issue: the command you ran, system information, the full input patch file, the original content of all target files, and the complete trace log.
---
## License
This project is licensed under [MIT LICENSE](LICENSE)
## Contributing
Contributions are welcome! Whether it's a bug report, a feature request, or a pull request, your input is valued.
### Reporting Issues
When opening an issue, the best way to help us is to provide a debug report.
1. Run your command again with the `-vvvv` flag.
```bash
mpatch -vvvv [YOUR_ARGS]
```
2. This will create a `mpatch-debug-report-[timestamp].md` file.
3. Create a new issue on GitHub.
4. Drag and drop the generated `.md` file into the issue description to attach it.
5. Add any additional comments about what you expected to happen versus what actually happened.
This self-contained report gives us all the context we need to investigate the problem efficiently.
### Pull Requests
1. Fork the repository.
2. Create a new branch for your feature or bug fix.
3. Make your changes.
4. Add tests for your changes in the `tests/` directory.
5. Ensure all tests pass by running `cargo test`.
6. Format your code with `cargo fmt`.
7. Submit a pull request with a clear description of your changes.