Skip to content
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: 2 additions & 2 deletions pygit2/_pygit2.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -432,8 +432,8 @@ class Diff:
def from_c(diff, repo) -> Diff: ...
@staticmethod
def parse_diff(git_diff: str | bytes) -> Diff: ...
def __getitem__(self, index: int) -> Patch: ... # Diff_getitem
def __iter__(self) -> Iterator[Patch]: ... # -> DiffIter
def __getitem__(self, index: int) -> Patch | None: ... # Diff_getitem
def __iter__(self) -> Iterator[Patch | None]: ... # -> DiffIter
def __len__(self) -> int: ...

class DiffDelta:
Expand Down
5 changes: 5 additions & 0 deletions src/diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,11 @@ diff_get_patch_byindex(git_diff *diff, size_t idx)
if (err < 0)
return Error_set(err);

/* libgit2 may decide not to create a patch if the file is
"unchanged or binary", but this isn't an error case */
if (patch == NULL)
Py_RETURN_NONE;

return (PyObject*) wrap_patch(patch, NULL, NULL);
}

Expand Down
31 changes: 31 additions & 0 deletions test/test_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import textwrap
from collections.abc import Iterator
from itertools import chain
from pathlib import Path

import pytest

Expand Down Expand Up @@ -459,3 +460,33 @@ def test_diff_blobs(emptyrepo: Repository) -> None:
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


def test_diff_unchanged_file_no_patch(testrepo) -> None:
repo = testrepo

# Convert hello.txt line endings to CRLF
path = Path(repo.workdir) / 'hello.txt'
data = path.read_bytes()
data = data.replace(b'\n', b'\r\n')
path.write_bytes(data)

# Enable CRLF filter
repo.config['core.autocrlf'] = 'input'

diff = repo.diff()
assert len(diff) == 1

# Get patch #0 in the same diff several times.
# git_patch_from_diff eventually decides that the file is "unchanged";
# it returns a NULL patch in this case.
# https://libgit2.org/docs/reference/main/patch/git_patch_from_diff
for i in range(10): # loop typically exits in the third iteration
patch = diff[0]
if patch is None: # libgit2 decides the file is unchanged
break
assert patch.delta.new_file.path == path.name
assert patch.text == '' # no content change (just line endings)
else:
# Didn't find the edge case that this test is supposed to exercise.
assert False, 'libgit2 rebuilt a new patch every time'
Loading