How diff-match-patch Generates Code Change Previews in code-graph-rag
Short answer: The FileEditor class uses Google's diff-match-patch library to compute semantic differences between original and modified function code, then renders a unified diff preview using Python's difflib.
The code-graph-rag repository implements a surgical code-editing system that lets LLMs propose precise changes to specific functions. Understanding how it generates readable change previews requires examining the FileEditor class in codebase_rag/tools/file_editor.py, where diff-match-patch performs the heavy lifting of comparing code versions.
The Core diff-match-patch Workflow
The preview generation follows a four-step pipeline that balances algorithmic precision with human readability.
Step 1: Extract Original Function Source
FileEditor.get_function_source_code() uses Tree-sitter parsers to locate and extract the exact source text of the target function:
original_code = self.get_function_source_code(
file_path, function_name, line_number
)
This ensures the diff operates on semantic units (complete functions) rather than arbitrary line ranges.
Step 2: Generate Raw Diff
The diff_match_patch.diff_main() method produces a low-level edit script:
diffs = self.dmp.diff_main(original_code, new_code)
This returns a list of tuples: (operation, text) where operation is -1 (delete), 0 (equal), or 1 (insert).
Step 3: Semantic Cleanup
Raw diffs often contain noisy, minimal edits. The diff_cleanupSemantic() method merges adjacent operations and eliminates trivial differences:
self.dmp.diff_cleanupSemantic(diffs)
This step is crucial for code—grouping related changes so x = 1 becoming x = 2 appears as a single replacement rather than delete-then-insert.
Step 4: Render Unified Diff Preview
Finally, difflib.unified_diff formats the result as the standard @@ -a,b +c,d @@ format developers recognize:
diff = difflib.unified_diff(
original_code.splitlines(keepends=True),
new_code.splitlines(keepends=True),
fromfile=f"original/{function_name}",
tofile=f"new/{function_name}",
)
return "".join(diff)
Complete Implementation in FileEditor.get_diff
The full method in codebase_rag/tools/file_editor.py (lines 63-86) orchestrates this pipeline:
def get_diff(
self,
file_path: str,
function_name: str,
new_code: str,
line_number: int | None = None,
) -> str | None:
original_code = self.get_function_source_code(
file_path, function_name, line_number
)
if not original_code:
return None
diffs = self.dmp.diff_main(original_code, new_code)
self.dmp.diff_cleanupSemantic(diffs)
diff = difflib.unified_diff(
original_code.splitlines(keepends=True),
new_code.splitlines(keepends=True),
fromfile=f"original/{function_name}",
tofile=f"new/{function_name}",
)
return "".join(diff)
Why diff-match-patch and difflib Together?
The dual-library approach serves complementary purposes:
- diff-match-patch – Provides semantic diff cleanup optimized for natural language and code, reducing false positives from formatting changes
- difflib.unified_diff – Generates the industry-standard unified format that appears in Git, code review tools, and developer workflows
This combination ensures the preview is both algorithmically sound and immediately comprehensible to users.
From Preview to Applied Patch
When users approve a preview, the same diff_match_patch instance creates and applies the actual patch. The replace_code_block method (lines 41-53) handles this:
patches = self.dmp.patch_make(original_content, modified_content)
patched_content, results = self.dmp.patch_apply(patches, original_content)
The patch_apply method returns both the modified content and a list of boolean results indicating which hunks succeeded—enabling precise error reporting if a patch fails partially.
Practical Example: Generating a Preview
from codebase_rag.tools.file_editor import FileEditor
# Initialize editor with project root
editor = FileEditor(project_root="/path/to/project")
# Proposed function replacement
new_code = """
def calculate_total(items):
return sum(item.price for item in items) # Modernized
"""
# Generate preview diff
preview = editor.get_diff(
file_path="cart/utils.py",
function_name="calculate_total",
new_code=new_code,
)
print(preview)
Sample output:
--- original/calculate_total
+++ new/calculate_total
@@ -1,5 +1,3 @@
def calculate_total(items):
- total = 0
- for item in items:
- total += item.price
- return total
+ return sum(item.price for item in items) # Modernized
This preview appears in the LLM interface for user approval before apply_patch_to_file executes the change.
Key Source Files
| File | Role |
|---|---|
codebase_rag/tools/file_editor.py |
Contains FileEditor class with get_diff(), replace_code_block(), and apply_patch_to_file() |
codebase_rag/constants/__init__.py |
Defines status message templates like MSG_SURGICAL_SUCCESS |
codebase_rag/parser_loader.py |
Loads Tree-sitter parsers for function extraction |
codebase_rag/tool_descriptions.py |
Exposes REPLACE_CODE tool to the LLM |
Summary
- diff-match-patch generates semantically meaningful diffs through
diff_main()followed bydiff_cleanupSemantic() - difflib.unified_diff renders the final preview in the standard unified format
- The
FileEditorclass incodebase_rag/tools/file_editor.pycoordinates extraction, comparison, cleanup, and formatting - Identical diff-match-patch primitives create and apply patches after user approval
- Tree-sitter integration ensures diffs operate on complete, syntactically valid functions
Frequently Asked Questions
Can diff-match-patch handle large files efficiently?
According to the code-graph-rag implementation, diff-match-patch operates on function-level chunks rather than entire files. The get_function_source_code() method extracts only the relevant function body, keeping inputs small. For typical function sizes, the O(ND) Myers algorithm in diff-match-patch performs acceptably.
What happens if the original function changes after preview generation?
The patch_apply method in apply_patch_to_file includes fuzzy matching that tolerates minor context shifts. If the patch fails, results contains False for failed hunks, and the system reports partial failures via MSG_SURGICAL_SUCCESS or similar status constants.
Why use semantic cleanup instead of raw diffs?
Raw diffs from diff_main() produce minimal edit sequences that often split logically related changes. diff_cleanupSemantic() merges adjacent operations and respects word boundaries and code structure, yielding previews that align with developer mental models.
Is the unified diff output compatible with git apply?
The output format matches standard unified diff, but paths are synthetic (original/{function_name} rather than real filesystem paths). For Git compatibility, transform the header or use patch_apply directly through code-graph-rag's API instead of external Git tooling.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →