Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a6dcd1e

Browse filesBrowse files
authored
Merge pull request #2155 from puneetdixit200/fix-initial-index-diff
Support index diffs against the empty tree
2 parents da05ac6 + 4de94bc commit a6dcd1e
Copy full SHA for a6dcd1e

5 files changed

+101-10Lines changed: 101 additions & 10 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎git/diff.py‎

Copy file name to clipboardExpand all lines: git/diff.py
+19-4Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# This module is part of GitPython and is released under the
44
# 3-Clause BSD License: https://opensource.org/license/bsd-3-clause/
55

6-
__all__ = ["DiffConstants", "NULL_TREE", "INDEX", "Diffable", "DiffIndex", "Diff"]
6+
__all__ = ["DiffConstants", "NULL_TREE", "NULL_TREE_SHA", "INDEX", "Diffable", "DiffIndex", "Diff"]
77

88
import enum
99
import re
@@ -84,6 +84,9 @@ class DiffConstants(enum.Enum):
8484
:const:`git.NULL_TREE` and :const:`Diffable.NULL_TREE`.
8585
"""
8686

87+
NULL_TREE_SHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
88+
"""SHA of Git's canonical empty tree object."""
89+
8790
INDEX: Literal[DiffConstants.INDEX] = DiffConstants.INDEX
8891
"""Stand-in indicating you want to diff against the index.
8992
@@ -599,7 +602,14 @@ def _index_from_patch_format(cls, repo: "Repo", proc: Union["Popen", "Git.AutoIn
599602

600603
# FIXME: Here SLURPING raw, need to re-phrase header-regexes linewise.
601604
text_list: List[bytes] = []
602-
handle_process_output(proc, text_list.append, None, finalize_process, decode_streams=False)
605+
stderr_list: List[bytes] = []
606+
607+
def finalize_process_with_stderr(proc: Union["Popen", "Git.AutoInterrupt"]) -> None:
608+
finalize_process(proc, stderr=b"".join(stderr_list))
609+
610+
handle_process_output(
611+
proc, text_list.append, stderr_list.append, finalize_process_with_stderr, decode_streams=False
612+
)
603613

604614
# For now, we have to bake the stream.
605615
text = b"".join(text_list)
@@ -765,11 +775,16 @@ def _index_from_raw_format(cls, repo: "Repo", proc: "Popen") -> "DiffIndex[Diff]
765775
# :100644 100644 687099101... 37c5e30c8... M .gitignore
766776

767777
index: "DiffIndex" = DiffIndex()
778+
stderr_list: List[bytes] = []
779+
780+
def finalize_process_with_stderr(proc: Union["Popen", "Git.AutoInterrupt"]) -> None:
781+
finalize_process(proc, stderr=b"".join(stderr_list))
782+
768783
handle_process_output(
769784
proc,
770785
lambda byt: cls._handle_diff_line(byt, repo, index),
771-
None,
772-
finalize_process,
786+
stderr_list.append,
787+
finalize_process_with_stderr,
773788
decode_streams=False,
774789
)
775790

Collapse file

‎git/index/base.py‎

Copy file name to clipboardExpand all lines: git/index/base.py
+40-3Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,12 +1480,11 @@ def reset(
14801480

14811481
return self
14821482

1483-
# FIXME: This is documented to accept the same parameters as Diffable.diff, but this
1484-
# does not handle NULL_TREE for `other`. (The suppressed mypy error is about this.)
14851483
def diff(
14861484
self,
1487-
other: Union[ # type: ignore[override]
1485+
other: Union[
14881486
Literal[git_diff.DiffConstants.INDEX],
1487+
Literal[git_diff.DiffConstants.NULL_TREE],
14891488
"Tree",
14901489
"Commit",
14911490
str,
@@ -1512,6 +1511,44 @@ def diff(
15121511
if other is self.INDEX:
15131512
return git_diff.DiffIndex()
15141513

1514+
if other == git_diff.NULL_TREE or other == git_diff.NULL_TREE_SHA:
1515+
args: List[Union[PathLike, str]] = [
1516+
"--cached",
1517+
git_diff.NULL_TREE_SHA,
1518+
"--abbrev=40",
1519+
"--full-index",
1520+
]
1521+
1522+
if not any(x in kwargs for x in ("find_renames", "no_renames", "M")):
1523+
args.append("-M")
1524+
1525+
if create_patch:
1526+
args.append("-p")
1527+
args.append("--no-ext-diff")
1528+
else:
1529+
args.append("--raw")
1530+
args.append("-z")
1531+
1532+
args.append("--no-color")
1533+
1534+
if paths is not None and not isinstance(paths, (tuple, list)):
1535+
paths = [paths]
1536+
1537+
if paths:
1538+
args.append("--")
1539+
args.extend(paths)
1540+
1541+
kwargs["as_process"] = True
1542+
proc = self.repo.git.diff(*args, **kwargs)
1543+
1544+
diff_method = (
1545+
git_diff.Diff._index_from_patch_format if create_patch else git_diff.Diff._index_from_raw_format
1546+
)
1547+
index = diff_method(self.repo, proc)
1548+
1549+
proc.wait()
1550+
return index
1551+
15151552
# Index against anything but None is a reverse diff with the respective item.
15161553
# Handle existing -R flags properly.
15171554
# Transform strings to the object so that we can call diff on it.
Collapse file

‎test/lib/helper.py‎

Copy file name to clipboardExpand all lines: test/lib/helper.py
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def __init__(self, input_string):
9090
self.stdout = io.BytesIO(input_string)
9191
self.stderr = io.BytesIO()
9292

93-
def wait(self):
93+
def wait(self, stderr=None):
9494
return 0
9595

9696
poll = wait
Collapse file

‎test/test_index.py‎

Copy file name to clipboardExpand all lines: test/test_index.py
+35-1Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
import ddt
2424
import pytest
2525

26-
from git import BlobFilter, Diff, Git, IndexFile, Object, Repo, Tree
26+
from git import BlobFilter, Diff, Git, IndexFile, NULL_TREE, Object, Repo, Tree
27+
from git.diff import NULL_TREE_SHA
2728
from git.exc import (
2829
CheckoutError,
2930
GitCommandError,
@@ -555,6 +556,39 @@ def test_index_file_diffing(self, rw_repo):
555556
rval = index.checkout("lib")
556557
assert len(list(rval)) > 1
557558

559+
@with_rw_directory
560+
def test_index_file_diff_null_tree_with_initial_index(self, rw_dir):
561+
repo = Repo.init(rw_dir)
562+
filename = ".gitkeep"
563+
file_path = osp.join(repo.working_tree_dir, filename)
564+
with open(file_path, "w") as fp:
565+
fp.write("# Initial file\n")
566+
567+
index = repo.index
568+
index.add([filename])
569+
index.write()
570+
571+
index = IndexFile(repo)
572+
self.assertEqual(len(index.diff(None)), 0)
573+
574+
diff = index.diff(NULL_TREE)
575+
self.assertEqual(len(diff), 1)
576+
self.assertEqual(diff[0].change_type, "A")
577+
assert diff[0].new_file
578+
self.assertEqual(diff[0].b_path, filename)
579+
580+
self.assertEqual(len(index.diff(NULL_TREE, paths=filename)), 1)
581+
self.assertEqual(len(index.diff(NULL_TREE_SHA, paths=filename)), 1)
582+
self.assertEqual(len(index.diff(NULL_TREE, paths="missing")), 0)
583+
584+
patch = index.diff(NULL_TREE, create_patch=True)
585+
self.assertEqual(len(patch), 1)
586+
self.assertIn(b"+# Initial file", patch[0].diff)
587+
588+
with self.assertRaises(GitCommandError) as exc_info:
589+
index.diff(NULL_TREE, bogus_option=True)
590+
self.assertIn("usage: git diff", exc_info.exception.stderr)
591+
558592
def _count_existing(self, repo, files):
559593
"""Return count of files that actually exist in the repository directory."""
560594
existing = 0
Collapse file

‎test/test_remote.py‎

Copy file name to clipboardExpand all lines: test/test_remote.py
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,12 @@ def test_multiple_urls(self, rw_repo):
687687

688688
def test_fetch_error(self):
689689
rem = self.rorepo.remote("origin")
690-
with self.assertRaisesRegex(GitCommandError, "[Cc]ouldn't find remote ref __BAD_REF__"):
690+
msg = (
691+
r"[Cc]ouldn't find remote ref __BAD_REF__|"
692+
r"could not read Username|"
693+
r"expected flush after ref listing"
694+
)
695+
with self.assertRaisesRegex(GitCommandError, msg):
691696
rem.fetch("__BAD_REF__")
692697

693698
@with_rw_repo("0.1.6", bare=False)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.