Skip to content

repository - diff blobs: consider the values of context_lines and interhunk_lines #1360

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion pygit2/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,9 @@ def diff(

# Case 4: Diff blob to blob
if isinstance(a, Blob) and isinstance(b, Blob):
return a.diff(b)
opt_values.insert(1, 'file')
opt_values.insert(1, 'file')
return a.diff(b, *opt_values)

raise ValueError('Only blobs and treeish can be diffed')

Expand Down
17 changes: 13 additions & 4 deletions src/blob.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,15 @@ PyDoc_STRVAR(Blob_diff__doc__,
" Treat old blob as if it had this filename.\n"
"\n"
"new_as_path : str\n"
" Treat new blob as if it had this filename.\n");
" Treat new blob as if it had this filename.\n"
"\n"
"context_lines: int\n"
" Number of unchanged lines that define the boundary of a hunk\n"
" (and to display before and after).\n"
"\n"
"interhunk_lines: int\n"
" Maximum number of unchanged lines between hunk boundaries\n"
" before the hunks will be merged into one.\n");

PyObject *
Blob_diff(Blob *self, PyObject *args, PyObject *kwds)
Expand All @@ -70,11 +78,12 @@ Blob_diff(Blob *self, PyObject *args, PyObject *kwds)
char *old_as_path = NULL, *new_as_path = NULL;
Blob *other = NULL;
int err;
char *keywords[] = {"blob", "flag", "old_as_path", "new_as_path", NULL};
char *keywords[] = {"blob", "flag", "old_as_path", "new_as_path", "context_lines", "interhunk_lines", NULL};

if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!Iss", keywords,
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!IssHH", keywords,
&BlobType, &other, &opts.flags,
&old_as_path, &new_as_path))
&old_as_path, &new_as_path,
&opts.context_lines, &opts.interhunk_lines))
return NULL;

if (Object__load((Object*)self) == NULL) { return NULL; } // Lazy load
Expand Down
76 changes: 76 additions & 0 deletions test/test_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,68 @@
delete mode 100644 c/d
"""

TEXT_BLOB1 = """Common header of the file
Copy link
Author

@eantoranz eantoranz Apr 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it was much simpler to create tailored blobs out of thin air than... hunt down for usable examples in the repos already available in the test data.

Blob 1 line 1
Common middle line 1
Common middle line 2
Common middle line 3
Blob 1 line 2
Common footer of the file
"""

TEXT_BLOB2 = """Common header of the file
Blob 2 line 1
Common middle line 1
Common middle line 2
Common middle line 3
Blob 2 line 2
Common footer of the file
"""

PATCH_BLOBS_DEFAULT = """diff --git a/file b/file
index 0b5ac93..ddfdbcc 100644
--- a/file
+++ b/file
@@ -1,7 +1,7 @@
Common header of the file
-Blob 1 line 1
+Blob 2 line 1
Common middle line 1
Common middle line 2
Common middle line 3
-Blob 1 line 2
+Blob 2 line 2
Common footer of the file
"""

PATCH_BLOBS_NO_LEEWAY = """diff --git a/file b/file
index 0b5ac93..ddfdbcc 100644
--- a/file
+++ b/file
@@ -2 +2 @@ Common header of the file
-Blob 1 line 1
+Blob 2 line 1
@@ -6 +6 @@ Common middle line 3
-Blob 1 line 2
+Blob 2 line 2
"""

PATCH_BLOBS_ONE_CONTEXT_LINE = """diff --git a/file b/file
index 0b5ac93..ddfdbcc 100644
--- a/file
+++ b/file
@@ -1,3 +1,3 @@
Common header of the file
-Blob 1 line 1
+Blob 2 line 1
Common middle line 1
@@ -5,3 +5,3 @@ Common middle line 2
Common middle line 3
-Blob 1 line 2
+Blob 2 line 2
Common footer of the file
"""


def test_diff_empty_index(dirtyrepo):
repo = dirtyrepo
Expand Down Expand Up @@ -382,3 +444,17 @@ def test_parse_diff_bad():
)
with pytest.raises(pygit2.GitError):
pygit2.Diff.parse_diff(diff)


def test_diff_blobs(emptyrepo):
repo = emptyrepo
blob1 = repo.create_blob(TEXT_BLOB1.encode())
blob2 = repo.create_blob(TEXT_BLOB2.encode())
diff_default = repo.diff(blob1, blob2)
assert diff_default.text == PATCH_BLOBS_DEFAULT
diff_no_leeway = repo.diff(blob1, blob2, context_lines=0)
assert diff_no_leeway.text == PATCH_BLOBS_NO_LEEWAY
diff_one_context_line = repo.diff(blob1, blob2, context_lines=1)
assert diff_one_context_line.text == PATCH_BLOBS_ONE_CONTEXT_LINE
diff_all_together = repo.diff(blob1, blob2, context_lines=1, interhunk_lines=1)
assert diff_all_together.text == PATCH_BLOBS_DEFAULT