Fix patching

This commit is contained in:
2026-03-20 05:16:13 -07:00
parent 5b82916a29
commit b086012292
3 changed files with 206 additions and 103 deletions
+39 -18
View File
@@ -11,6 +11,7 @@ import os
import sys
import re
import shutil
import difflib
from pathlib import Path
from typing import List, Dict, Optional, Any
import argparse
@@ -204,18 +205,18 @@ class GitPatchHandler:
}
def _try_fuzzy_apply(self, patch_file: str, target_dir: str, previous_result: subprocess.CompletedProcess) -> Dict[str, Any]:
"""Try applying patch with fuzzy matching"""
self._log("Attempting fuzzy patch application")
"""Try applying patch with --reject to apply what fits, then check for leftover .rej files"""
self._log("Attempting fuzzy patch application with --reject")
try:
cmd = [
'git', 'apply',
'--3way',
'--allow-overlap',
'--verbose',
'--reject', # Apply parts that work, reject others
'--reject', # Apply hunks that work, write .rej for those that don't
str(patch_file)
]
result = subprocess.run(
cmd,
cwd=target_dir,
@@ -223,15 +224,34 @@ class GitPatchHandler:
text=True,
timeout=30
)
if result.returncode == 0 or 'applied' in result.stdout.lower():
# Check for leftover .rej files — these mean hunks were skipped
rej_files = list(Path(target_dir).rglob('*.rej'))
if rej_files:
rej_names = [str(r.relative_to(target_dir)) for r in rej_files]
self._log(f"Found {len(rej_files)} reject file(s): {rej_names}")
# Clean up .rej files so they don't pollute the tree
for rej in rej_files:
try:
rej.unlink()
except OSError:
pass
return {
'success': True,
'message': 'Patch applied with rejects',
'success': False,
'message': f'Patch partially applied — {len(rej_files)} hunk(s) rejected',
'output': result.stdout,
'error': result.stderr,
'method': 'git-fuzzy',
'had_rejects': 'reject' in result.stdout.lower()
'rejected_files': rej_names
}
if result.returncode == 0:
return {
'success': True,
'message': 'Patch applied cleanly (fuzzy)',
'output': result.stdout,
'error': result.stderr,
'method': 'git-fuzzy'
}
else:
return {
@@ -242,7 +262,7 @@ class GitPatchHandler:
'error': result.stderr,
'method': 'git-fuzzy'
}
except Exception as e:
return {
'success': False,
@@ -357,11 +377,15 @@ class GitPatchHandler:
files = []
for line in patch_content.split('\n'):
if line.startswith('--- ') or line.startswith('+++ '):
file_path = line.split(' ')[1]
if file_path != '/dev/null' and not file_path.startswith('a/') and not file_path.startswith('b/'):
# Clean up git-style prefixes
clean_path = re.sub(r'^(a|b)/', '', file_path)
files.append(clean_path)
parts = line.split(' ', 1)
if len(parts) < 2:
continue
file_path = parts[1].split('\t')[0].strip() # handle timestamps after tab
if file_path == '/dev/null':
continue
# Strip git-style a/ or b/ prefixes (standard in git format-patch output)
clean_path = re.sub(r'^[ab]/', '', file_path)
files.append(clean_path)
return list(set(files))
def _count_lines_changed(self, patch_content: str) -> int:
@@ -606,8 +630,5 @@ def print_patch_results(result: Dict[str, Any]) -> None:
print(f" [ROLLED BACK]")
# Add difflib for the create_patch method
import difflib
if __name__ == '__main__':
main()