Skip to content

Add Commit.is_shallow property; document stats() limitation at shallow boundary - #2167

Merged
Byron merged 4 commits into
gitpython-developers:mainfrom
harshitayadavv:add-is-shallow-property
Jul 12, 2026
Merged

Add Commit.is_shallow property; document stats() limitation at shallow boundary#2167
Byron merged 4 commits into
gitpython-developers:mainfrom
harshitayadavv:add-is-shallow-property

Conversation

@harshitayadavv

Copy link
Copy Markdown
Contributor

Problem

Accessing .stats on a commit at the boundary of a shallow clone raises
git.exc.GitCommandError: fatal: bad object <sha>. This happens because
the commit object itself still references its parent's SHA, but that
parent was never fetched — it's beyond the shallow depth. There's currently
no way to detect this ahead of time without hitting the crash.

Reproduction

git clone --depth 5 <any repo with more history> repo
cd repo
python -c "
import git
repo = git.Repo('.')
oldest = list(repo.iter_commits())[-1]
print(oldest.parents)   # non-empty -- references a SHA that doesn't exist locally
oldest.stats            # raises GitCommandError: fatal: bad object <sha>
"

Fix

Adds a Commit.is_shallow property that checks whether the commit's hexsha
appears in the repository's shallow file -- a cheap, local check with no
git subprocess call. Also documents this limitation in the stats
docstring, pointing to is_shallow.

Includes a test (test_is_shallow) that reproduces the failure via a real
local shallow clone (using no_local=True, since Git ignores --depth for
local-optimized clones) and confirms both that the boundary commit reports
is_shallow == True and that .stats raises as expected on it.

Ran the full test suite locally (Windows, Python 3.11): 660 passed, 9
unrelated pre-existing failures (Windows symlink privilege requirements,
a missing-remote assumption in one tutorial test, and PATH resolution in
shell-impostor tests) -- none touching commit.py or stats.

AI disclosure

Per CONTRIBUTING.md: I used Claude to help design, implement, and test
this change. I reviewed, ran, and verified every step myself, including
reproducing the underlying bug firsthand before writing the fix.

harshitayadavv and others added 2 commits July 5, 2026 18:27
…llow boundary

Accessing .stats on a commit at the boundary of a shallow clone raises
GitCommandError because the commit's parent SHA was never fetched. This
adds an is_shallow property to detect this case ahead of time by checking
the repository's shallow file, and documents the limitation on stats().

Co-authored-by: Claude <noreply@anthropic.com>

@Byron Byron left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for giving this a shot.

Can we reduce this to just the documentation change for a quick merge? Otherwise, the .is_shallow() should rather be on Repo to support testing multiple commits at the same time. I wouldn't want to encourage per-commit calls given they are IO-heavy then. Alternatively, offer a way to get a set of hashes that are the shallow boundary so users can do their is-contained checks themselves.

Per @Byron's feedback: dropping the is_shallow property, since a
per-commit property re-reads the shallow file on every call, which
is IO-heavy when checking many commits. Keeping just the stats()
docstring note about the limitation for a quick merge. Happy to
follow up with a Repo-level implementation (e.g. returning the set
of shallow-boundary hashes) as a separate PR if useful.
@harshitayadavv

Copy link
Copy Markdown
Contributor Author

@Byron Done, reduced to just the docstring note on stats(). Happy to follow up separately with a Repo-level version (e.g. a method returning the set of shallow-boundary hashes) if that'd be useful.

@Byron
Byron merged commit 40f1424 into gitpython-developers:main Jul 12, 2026
30 checks passed
736-c41-2c1-e464fc974 pushed a commit to Swiss-Armed-Forces/Loom that referenced this pull request Aug 16, 2026
This MR contains the following updates:

| Package | Type | Update | Change | OpenSSF |
|---|---|---|---|---|
| [gitpython](https://github.com/gitpython-developers/GitPython) | dev | patch | `3.1.50` → `3.1.52` | [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/gitpython-developers/GitPython/badge)](https://securityscorecards.dev/viewer/?uri=github.com/gitpython-developers/GitPython) |

---

### Release Notes

<details>
<summary>gitpython-developers/GitPython (gitpython)</summary>

### [`v3.1.52`](https://github.com/gitpython-developers/GitPython/releases/tag/3.1.52): Security

[Compare Source](gitpython-developers/GitPython@3.1.51...3.1.52)

<GHSA-rwj8-pgh3-r573>: Environment-variable exfiltration via os.path.expandvars() on Repo.clone\_from() URL

#### What's Changed

- Skip cross-drive relative config test on Windows by [@&#8203;Byron](https://github.com/Byron) in [#&#8203;2171](gitpython-developers/GitPython#2171)
- fix: preserve literal clone URLs by [@&#8203;Byron](https://github.com/Byron) in [#&#8203;2172](gitpython-developers/GitPython#2172)

**Full Changelog**: <gitpython-developers/GitPython@3.1.51...3.1.52>

### [`v3.1.51`](https://github.com/gitpython-developers/GitPython/releases/tag/3.1.51): - Security

[Compare Source](gitpython-developers/GitPython@3.1.50...3.1.51)

#### What's Changed

- Add AI-disclosure and quality requirements to the contribution guidelines by [@&#8203;Byron](https://github.com/Byron) in [#&#8203;2143](gitpython-developers/GitPython#2143)
- docs(cmd): clarify Git.execute() string vs list command argument by [@&#8203;mvanhorn](https://github.com/mvanhorn) in [#&#8203;2144](gitpython-developers/GitPython#2144)
- Rewrite Git.execute() command parameter docstring per [#&#8203;2146](gitpython-developers/GitPython#2146) by [@&#8203;EliahKagan](https://github.com/EliahKagan) in [#&#8203;2147](gitpython-developers/GitPython#2147)
- Document init script behavior with multiple master remotes by [@&#8203;EliahKagan](https://github.com/EliahKagan) in [#&#8203;2148](gitpython-developers/GitPython#2148)
- Bump git/ext/gitdb from `335c0f6` to `0a019a2` by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2149](gitpython-developers/GitPython#2149)
- Support relative worktree paths (git 2.48+ worktree.useRelativePaths) by [@&#8203;elovelan](https://github.com/elovelan) in [#&#8203;2151](gitpython-developers/GitPython#2151)
- Defer xfail condition evaluation with xfail\_if\_raises context manager by [@&#8203;elovelan](https://github.com/elovelan) in [#&#8203;2153](gitpython-developers/GitPython#2153)
- Run more submodule tests on Cygwin (fix flaky xfails) by [@&#8203;EliahKagan](https://github.com/EliahKagan) in [#&#8203;2154](gitpython-developers/GitPython#2154)
- Cut xtrace noise from POSIX-ownership diagnostic steps by [@&#8203;EliahKagan](https://github.com/EliahKagan) in [#&#8203;2156](gitpython-developers/GitPython#2156)
- Support index diffs against the empty tree by [@&#8203;puneetdixit200](https://github.com/puneetdixit200) in [#&#8203;2155](gitpython-developers/GitPython#2155)
- refactor: seperate out Progress type by [@&#8203;LoeschMaximilian](https://github.com/LoeschMaximilian) in [#&#8203;2157](gitpython-developers/GitPython#2157)
- Bump <https://github.com/astral-sh/ruff-pre-commit> from v0.15.12 to 0.15.15 in the pre-commit group by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2160](gitpython-developers/GitPython#2160)
- Bump actions/checkout from 6 to 7 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2164](gitpython-developers/GitPython#2164)
- Bump git/ext/gitdb from `0a019a2` to `4950ea9` by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2165](gitpython-developers/GitPython#2165)
- Bump <https://github.com/astral-sh/ruff-pre-commit> from v0.15.15 to 0.15.20 in the pre-commit group by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2166](gitpython-developers/GitPython#2166)
- Add Commit.is\_shallow property; document stats() limitation at shallow boundary by [@&#8203;harshitayadavv](https://github.com/harshitayadavv) in [#&#8203;2167](gitpython-developers/GitPython#2167)
- Allow relative config paths with includes by [@&#8203;Byron](https://github.com/Byron) in [#&#8203;2169](gitpython-developers/GitPython#2169)
- Reject abbreviated forms of unsafe git options by [@&#8203;Byron](https://github.com/Byron) in [#&#8203;2168](gitpython-developers/GitPython#2168)
- guard unsafe git command options by [@&#8203;Byron](https://github.com/Byron) in [#&#8203;2163](gitpython-developers/GitPython#2163)

#### New Contributors

- [@&#8203;elovelan](https://github.com/elovelan) made their first contribution in [#&#8203;2151](gitpython-developers/GitPython#2151)
- [@&#8203;puneetdixit200](https://github.com/puneetdixit200) made their first contribution in [#&#8203;2155](gitpython-developers/GitPython#2155)
- [@&#8203;LoeschMaximilian](https://github.com/LoeschMaximilian) made their first contribution in [#&#8203;2157](gitpython-developers/GitPython#2157)
- [@&#8203;harshitayadavv](https://github.com/harshitayadavv) made their first contribution in [#&#8203;2167](gitpython-developers/GitPython#2167)

**Full Changelog**: <gitpython-developers/GitPython@3.1.50...3.1.51>

</details>

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzAuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI3MC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiLCJyZW5vdmF0ZSJdfQ==-->

See merge request swiss-armed-forces/cyber-command/cea/loom!679

Co-authored-by: Loom MR Pipeline Trigger <group_103951964_bot_9504bb8dead6d4e406ad817a607f24be@noreply.gitlab.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants