Skip to main content

Fixes erroneous git apply patches to the best of its ability.

Project description

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

# 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:

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:

# 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:

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:

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)

Advanced Features

Patch Analysis

Analyze patches without modifying them:

from patch_fixer.analyzer import analyze_patch, get_patch_summary

with open("patch.diff") as f:
    lines = f.readlines()

# Get detailed information
info = analyze_patch(lines)
print(f"Files: {info.total_files}, Added: {info.total_additions}, Removed: {info.total_deletions}")

# Get human-readable summary
print(get_patch_summary(lines))

Custom Processing Hooks

Add custom logic to patch processing:

def log_hunks(hunk_lines, context):
    print(f"Processing hunk in {context['current_file']}")
    return hunk_lines

fixed = fix_patch(patch_lines, original, pre_hunk_hook=log_hunks)

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

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

patch_fixer-0.5.1.tar.gz (36.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

patch_fixer-0.5.1-py3-none-any.whl (29.1 kB view details)

Uploaded Python 3

File details

Details for the file patch_fixer-0.5.1.tar.gz.

File metadata

  • Download URL: patch_fixer-0.5.1.tar.gz
  • Upload date:
  • Size: 36.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for patch_fixer-0.5.1.tar.gz
Algorithm Hash digest
SHA256 f2a05caaee201cbe3ef5db2633d59c66173cce7e2a3e4924ed9358f6ef0fac3c
MD5 f5c373d13e20ae8b5f4c039d2d6ae15d
BLAKE2b-256 f6e42b77794aa1c98a48dc1abcf2651bd1d22074591cc5c1879d2869a06d6956

See more details on using hashes here.

File details

Details for the file patch_fixer-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: patch_fixer-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 29.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for patch_fixer-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 43ff4ee463bbfddb575e88a48dfc0fd0e05e75e909975e0ad3869b83fa5eabb3
MD5 40246ba06fdb54de7747c8e8ccc2a364
BLAKE2b-256 392a6107384f2e442f8aef5b8631dff3ceeed4a2c0bb71e465eb1ad21a2b19ca

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page