Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,6 @@ Contributors are:
-Jonas Scharpf <jonas.scharpf _at_ checkmk.com>
-Gordon Marx
-Enji Cooper
-Harshita Yadav <harshitayadav504 _at_ gmail.com>

Portions derived from other open source works and are clearly marked.
27 changes: 27 additions & 0 deletions git/objects/commit.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,11 +369,38 @@ def iter_parents(self, paths: Union[PathLike, Sequence[PathLike]] = "", **kwargs

return self.iter_items(self.repo, self, paths, **kwargs)

@property
def is_shallow(self) -> bool:
"""Check whether this commit is a shallow boundary (graft) commit.

A commit at the boundary of a shallow clone appears to have no
parents from Git's perspective, even though the underlying commit
object still references a parent SHA that was never fetched. Calling
:attr:`stats` (or anything else that diffs against the parent) on
such a commit will raise :exc:`~git.exc.GitCommandError` because the
parent object does not exist locally.

:return:
True if this commit's hexsha appears in the repository's
``shallow`` file, False otherwise (including for non-shallow
repositories).
"""
shallow_file = os.path.join(self.repo.git_dir, "shallow")
if not os.path.isfile(shallow_file):
return False
with open(shallow_file, "r") as f:
return self.hexsha in f.read().split()

@property
def stats(self) -> Stats:
"""Create a git stat from changes between this commit and its first parent
or from all changes done if this is the very first commit.

:note:
If this commit is at the boundary of a shallow clone (see
:attr:`is_shallow`), this will raise :exc:`~git.exc.GitCommandError`
because the parent object was never fetched.

:return:
:class:`Stats`
"""
Expand Down
21 changes: 20 additions & 1 deletion test/test_commit.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from gitdb import IStream

from git import Actor, Commit, Repo
from git import Actor, Commit, GitCommandError, Repo
from git.objects.util import tzoffset, utc
from git.repo.fun import touch

Expand Down Expand Up @@ -164,6 +164,25 @@ def check_entries(d, has_change_type=False):
self.assertEqual(commit.committer_tz_offset, 14400, commit.committer_tz_offset)
self.assertEqual(commit.message, "initial project\n")

@with_rw_directory
def test_is_shallow(self, rw_dir):
"""A commit at the shallow boundary should report is_shallow, and
accessing its stats should raise GitCommandError."""
full_repo = self.rorepo
shallow_path = osp.join(rw_dir, "shallow_clone")
shallow_repo = Repo.clone_from(full_repo.git_dir, shallow_path, depth=2, no_local=True)

commits = list(shallow_repo.iter_commits())
boundary_commit = commits[-1]

self.assertTrue(boundary_commit.is_shallow)
with self.assertRaises(GitCommandError):
boundary_commit.stats

if len(commits) > 1:
non_boundary_commit = commits[0]
self.assertFalse(non_boundary_commit.is_shallow)

def test_renames(self):
commit = self.rorepo.commit("185d847ec7647fd2642a82d9205fb3d07ea71715")
files = commit.stats.files
Expand Down
Loading