repomatic.metadata.git module

Git commit-range logic of Metadata.

Resolves the commit range an event bundles, the release commits inside it, what those commits changed, and the per-commit matrices built by rewinding the checkout. This is the one concern that can touch the repository state, always restoring it (see _restored_worktree).

class repomatic.metadata.git.GitMetadata[source]

Bases: object

Commit ranges, changed files, and the per-commit matrices.

A concern mixin of Metadata: never instantiated on its own, and reads sibling concerns through self.

git_stash_count()[source]

Returns the number of stashes.

Return type:

int

git_deepen(commit_hash, max_attempts=10, deepen_increment=50)[source]

Deepen a shallow clone until the provided commit_hash is found.

Progressively fetches more commits from the current repository until the specified commit is found or max attempts is reached.

Returns True if the commit was found, False otherwise.

Return type:

bool

commit_matrix(commits)[source]

Pre-compute a matrix of commits.

Danger

This method temporarily modifies the state of the repository to compute version metadata from the past.

To prevent any loss of uncommitted data, it stashes local changes before its checkouts and restores the initial state however the scan exits, through _restored_worktree().

The list of commits is augmented with long and short SHA values, as well as current version. Most recent commit is first, oldest is last.

Returns a ready-to-use matrix structure:

{
    "commit": [
        "346ce664f055fbd042a25ee0b7e96702e95",
        "6f27db47612aaee06fdf08744b09a9f5f6c2",
    ],
    "include": [
        {
            "commit": "346ce664f055fbd042a25ee0b7e96702e95",
            "short_sha": "346ce66",
            "current_version": "2.0.1",
        },
        {
            "commit": "6f27db47612aaee06fdf08744b09a9f5f6c2",
            "short_sha": "6f27db4",
            "current_version": "2.0.0",
        },
    ],
}
Return type:

Matrix | None

property changed_files: tuple[str, ...] | None[source]

Returns the list of files changed in the current event’s commit range.

Uses git diff --name-only between the start and end of the commit range. Returns None if no commit range is available (e.g., outside CI).

property binary_affecting_paths: tuple[str, ...][source]

Path prefixes that affect compiled binaries for this project.

Combines the static BINARY_AFFECTING_PATHS (common files like pyproject.toml, uv.lock, tests/) with project-specific source directories derived from [project.scripts] in pyproject.toml.

For example, a project with mpm = "meta_package_manager.__main__:main" adds meta_package_manager/ as an affecting path. This makes the check reusable across downstream repositories without hardcoding source directories.

property head_commit_message: str[source]

Returns github.event.head_commit.message from the event payload.

Set for push events. Empty string for events that do not carry a head commit (pull_request, schedule, workflow_dispatch).

property yaml_changed: bool[source]

Returns True when the current event’s commit range touches at least one YAML file.

Lets per-job lint gates short-circuit on pushes / PRs that don’t touch YAML. Falls back to “repo contains any YAML file” when the commit range is unavailable (workflow_dispatch), preserving the existing behavior of those manual runs.

property zsh_changed: bool[source]

Returns True when the current event’s commit range touches at least one Zsh file.

Falls back to “repo contains any Zsh file” when the commit range is unavailable.

property workflows_changed: bool[source]

Returns True when the current event’s commit range touches at least one GitHub workflow file.

Falls back to “repo contains any workflow file” when the commit range is unavailable.

property skip_binary_build: bool[source]

Returns True if binary builds should be skipped for this event.

Binary builds are expensive and time-consuming. This property identifies contexts where the changes cannot possibly affect compiled binaries, allowing workflows to skip Nuitka compilation jobs.

Three mechanisms are checked:

  1. Branch name — PRs from known non-code branches (documentation, .mailmap, .gitignore, etc.) are skipped.

  2. Version-bump commit — Push events whose head commit is a user-initiated version bump (Bump (major|minor) version to) are skipped: the bump merge changes only version strings and uv.lock, so the new binary differs from the previous one only in the baked-in version string. The [changelog] Post-release bump prefix is deliberately not checked here: the prepare-release merge bundles the release commit with the post-release-bump commit, and the release commit must still produce its binary.

  3. Changed files — Push events where all changed files fall outside binary_affecting_paths are skipped. This avoids ~2h of Nuitka builds for documentation-only commits to main.

property commit_range: tuple[str | None, str] | None[source]

Range of commits bundled within the triggering event.

A workflow run is triggered by a singular event, which might encapsulate one or more commits. This means the workflow will only run once on the last commit, even if multiple new commits were pushed.

This is critical for releases where two commits are pushed together:

  1. [changelog] Release vX.Y.Z — the release commit

  2. [changelog] Post-release bump vX.Y.Z vX.Y.Z — the post-release bump

Without extracting the full commit range, the release commit would be missed since github.event.head_commit only exposes the post-release bump.

This property also enables processing each commit individually when we want to keep a carefully constructed commit history. The typical example is a pull request that is merged upstream but we’d like to produce artifacts (builds, packages, etc.) for each individual commit.

The default GITHUB_SHA environment variable is not enough as it only points to the last commit. We need to inspect the commit history to find all new ones. New commits need to be fetched differently in push and pull_request events.

See also

Pull request events on GitHub are a bit complex, see: The Many SHAs of a GitHub Pull Request.

property current_commit: Commit[source]

Returns the current Commit object.

Raises if HEAD cannot be resolved (an empty repository), mirroring the previous behavior where traversing an empty history raised too.

property current_commit_matrix: Matrix | None[source]

Pre-computed matrix with long and short SHA values of the current commit.

property new_commits: tuple[Commit, ...] | None[source]

Returns list of all Commit objects bundled within the triggering event.

This extracts all commits from the push event, not just head_commit. For releases, this typically includes both the release commit and the post-release bump commit, allowing downstream jobs to process each one.

Commits are returned in chronological order (oldest first, most recent last).

property new_commits_matrix: Matrix | None[source]

Pre-computed matrix with long and short SHA values of new commits.

property new_commits_hash: tuple[str, ...] | None[source]

List all hashes of new commits.

property release_commits: tuple[Commit, ...] | None[source]

Returns list of Commit objects to be tagged within the triggering event.

This filters new_commits to find release commits that need special handling: tagging, PyPI publishing, and GitHub release creation.

This is essential because when a release is pushed, github.event.head_commit only exposes the post-release bump commit, not the release commit. By extracting all commits from the event (via new_commits) and filtering for release commits here, we ensure the release workflow can properly identify and process the [changelog] Release vX.Y.Z commit.

We cannot identify a release commit based on the presence of a vX.Y.Z tag alone. That’s because the tag is not present in the prepare-release pull request produced by the changelog.yaml workflow. The tag is created later by the release.yaml workflow, when the pull request is merged to main.

Our best option is to identify a release based on the full commit message, using the template from the changelog.yaml workflow.

property release_commits_matrix: Matrix | None[source]

Pre-computed matrix with long and short SHA values of release commits.

property release_commits_hash: tuple[str, ...] | None[source]

List all hashes of release commits.