Metadata-Version: 2.4
Name: patch-fixer
Version: 0.4.1
Summary: Fixes erroneous git apply patches to the best of its ability.
Maintainer-email: Alex Mueller <amueller474@gmail.com>
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/ajcm474/patch-fixer
Project-URL: Issues, https://github.com/ajcm474/patch-fixer/issues
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: GitPython
Provides-Extra: test
Requires-Dist: hypothesis; extra == "test"
Requires-Dist: pytest; extra == "test"
Requires-Dist: requests; extra == "test"
Dynamic: license-file

# patch-fixer
So you asked an LLM to generate a code diff, tried to apply it with `git apply`, and got a bunch of malformed patch errors? Well fear no more, `patch-fixer` is here to save the day... more or less.

This tool can also split patches into separate files based on file lists, making it easy to selectively apply changes.

## Installation
```bash
# Make sure you're using at least python 3.10
python -m venv .venv/
source .venv/bin/activate
pip install patch-fixer
```

## Usage

### Command Line Interface

After installation, `patch-fixer` provides a unified command-line interface:

#### Fixing broken patches:
```bash
patch-fixer fix original broken.patch fixed.patch
```
where:
- `original` is the file or directory you were trying to patch
- `broken.patch` is the malformed patch generated by the LLM
- `fixed.patch` is the output file containing the (hopefully) fixed patch

Options:
- `--fuzzy`: enable fuzzy string matching for better context matching (experimental)
- `--add-newline`: add final newlines when processing "No newline at end of file" markers


#### Splitting patches by file:
```bash
# Split with files specified on command line
patch-fixer split input.patch included.patch excluded.patch -f file1.py file2.py

# Split using a file list
patch-fixer split input.patch included.patch excluded.patch -i files_to_include.txt
```
where:
- `input.patch` is the patch file to split
- `included.patch` will contain changes for the specified files
- `excluded.patch` will contain changes for all other files
- `-f` allows specifying files directly on the command line
- `-i` reads the file list from a text file (one file per line)

### Python API

#### Fixing patches:
```python
from patch_fixer import fix_patch

patch_file = "/path/to/broken.patch"
original = "/path/to/original/state"    # file or directory being patched
with open(patch_file, encoding="utf-8") as f:
    patch_lines = f.readlines()
    
# basic usage
fixed_lines = fix_patch(patch_lines, original)

# with fuzzy matching enabled
fixed_lines = fix_patch(patch_lines, original, fuzzy=True)

# with final newline addition
fixed_lines = fix_patch(patch_lines, original, add_newline=True)

output_file = "/path/to/fixed.patch"
with open(output_file, 'w', encoding='utf-8') as f:
    f.writelines(fixed_lines)
```

#### Splitting patches:
```python
from patch_fixer import split_patch

with open("input.patch", encoding="utf-8") as f:
    patch_lines = f.readlines()

# split to include only specific files
files_to_include = ["./src/main.py", "./src/utils.py"]
included, excluded = split_patch(patch_lines, files_to_include)

# write the split patches
with open("included.patch", 'w', encoding='utf-8') as f:
    f.writelines(included)
    
with open("excluded.patch", 'w', encoding='utf-8') as f:
    f.writelines(excluded)
```

## Known Limitations

- When fixing patches with missing `index` lines, the tool requires the files to be in a git repository to regenerate the index. This is only needed for file deletions and renames.
- `patch-fixer` assumes the patch follows git's unified diff format.
- Current implementation is not very robust to corrupted hunk content
  - Much more comprehensive fuzzy string matching is planned

## Local Testing
```bash
git clone https://github.com/ajcm474/patch-fixer.git
cd patch-fixer
pip install -e .[test]
pytest
```
From version `0.3.0` onward (at least until version `1.0`), some test failures are expected
in bugfix versions as I like to use test-driven development to build out new features. 
Please only report test failures if the same test existed and passed in the most recent `0.x.0` version.

## License

This is free and open source software, released under the Apache 2.0 License. See `LICENSE` for details.
