Git Repository Manager¶
Manage Git repositories with operations like clone, commit, push, and PR creation.
Overview¶
The Repo and GitRepo classes provide a high-level interface for Git operations in GitHub Actions, including repository management, branch operations, tagging, and pull request creation.
Note: You can use Repo and GitRepo classes interchangeably - they are aliases.
API Reference¶
Repo(url=None, path=None, cleanup=False, depth=None, single_branch=False, clone_branch=None, clone_ref=None, github_token=None, clone_no_checkout=False, retry_attempts=3, retry_backoff_seconds=1.0, retry_backoff_multiplier=2.0, redactor=None)¶
Initializes the Git repository manager.
Either url or path parameter is required.
If url is provided, the repo will be cloned into a temp directory. And you can access the path of the repository with repo.repo_path variable.
If path is provided, the existing local repo will be used.
Parameters¶
url(str, optional): URL of the Git repository to clonepath(str, optional): Path to an existing local Git repositorycleanup(bool, default=False): Enable cleanup mode (see below)depth(int, optional): Create a shallow clone with specified depth (faster clones)single_branch(bool, default=False): Clone only a single branch (faster clones)clone_branch(str, optional): Clone a specific branch directly. This is mostly clone-scoped, and is also used as a fallback base branch when the active branch cannot be determined.clone_ref(str, optional): Checkout a specific branch/tag/SHA after clone.github_token(str, optional): GitHub token used for private clone authentication and as the default token forcreate_pr().clone_no_checkout(bool, default=False): Clone with no working tree checkout (equivalent togit clone --no-checkout)retry_attempts(int, default=3): Retry attempts for clone/fetch/pull operationsretry_backoff_seconds(float, default=1.0): Initial backoff in seconds between retriesretry_backoff_multiplier(float, default=2.0): Multiplier for exponential backoffredactor(callable, optional): Custom redaction callback for sensitive error text
Cleanup Mode (cleanup=True)¶
When cleanup=True, the repository is force-synchronized to the original base branch captured at construction time on both context entry and exit:
git fetch --prune(non-fatal if it fails)Pre-sync:
git reset --hardthengit clean -fdx(clear local changes/untracked files)Checkout base branch:
If
origin/<base_branch>exists:git checkout -B <base_branch> origin/<base_branch>Otherwise:
git checkout <base_branch>(non-fatal; logs on failure)
Post-sync reset:
If
origin/<base_branch>exists:git reset --hard origin/<base_branch>(falls back togit reset --hardon failure)Otherwise:
git reset --hard
Post-sync clean:
git clean -fdx(removes untracked, directories, ignored files)git pull origin <base_branch>(non-fatal)
This synchronization happens twice: once on __enter__ (before your work) and once on __exit__ (after your work), guaranteeing the repo is clean, on the base branch, and up to date. All steps are defensive: errors never raise, they only log.
example:
>> from github_action_toolkit import Repo
>> with Repo(url="https://github.com/user/repo.git") as repo:
>> print(repo.get_current_branch())
# Output:
# main
Shallow clone example:
>> # Clone only the latest commit for faster CI workflows
>> with Repo(url="https://github.com/user/repo.git", depth=1, single_branch=True) as repo:
>> print(f"Cloned to {repo.repo_path}")
Clone private repo with token and explicit clone ref example:
>> with Repo(
>> url="https://github.com/org/private-repo.git",
>> github_token=os.getenv("GITHUB_TOKEN"),
>> clone_branch="main",
>> clone_ref="v1.2.3",
>> clone_no_checkout=True,
>> ) as repo:
>> print(repo.repo_path)
Retry and operation metadata example:
>> with Repo(url="https://github.com/user/repo.git", retry_attempts=4) as repo:
>> repo.fetch()
>> print(repo.get_operation_metadata("fetch"))
# Example output:
# {'attempts': 2, 'retries': 1, 'elapsed_ms': 438, 'success': True}
Common git failure modes are raised as typed exceptions from github_action_toolkit.exceptions:
GitAuthenticationErrorGitNetworkErrorGitReferenceErrorGitCloneError
Basic Operations¶
Repo.get_current_branch()¶
Returns the name of the currently active Git branch.
example:
>> repo.get_current_branch()
# Output:
# feature/my-branch
Repo.create_new_branch(branch_name)¶
Creates and checks out a new branch from the current branch.
example:
>> repo.create_new_branch("feature/auto-update")
Repo.add(file_path)¶
Stages a specific file for commit.
example:
>> repo.add("README.md")
Repo.commit(message)¶
Commits the currently staged files with the specified message.
example:
>> repo.commit("Update README")
Repo.add_all_and_commit(message)¶
Stages all changes in the repository and commits them with the given message.
example:
>> repo.add_all_and_commit("Auto-update configuration files")
Repo.push(remote="origin", branch=None)¶
Pushes the current branch to the specified remote (default is origin). If branch is not provided, pushes the currently active branch.
example:
>> repo.push()
Repo.pull(remote="origin", branch=None)¶
Pulls the latest changes for the current branch from the specified remote (default is origin). If branch is not provided, pulls the currently active branch.
example:
>> repo.pull()
Repo.create_pr(github_token=None, title=None, body=None, head=None, base=None)¶
Creates a pull request on GitHub.
This method automatically infers most of the required values based on the current repository state, making it ideal for use in GitHub Actions or automation scripts.
Parameters:
github_token (optional): GitHub token with repo scope. If not provided,
Repo(..., github_token=...)is used. If class-level token is also not set, it falls back to environment variableGITHUB_TOKEN.title (optional): Title of the pull request. If not provided, the latest commit message will be used.
body (optional): Description body for the pull request. Defaults to an empty string.
head (optional): The name of the branch containing your changes. If not provided, the current active branch will be used.
base (optional): The branch you want to merge into. If not provided, it uses the branch that was active at the time the repo was cloned or opened.
example:
>> pr_url = repo.create_pr(
>> github_token=os.getenv("GITHUB_TOKEN"),
>> title="Auto PR",
>> body="This PR was created automatically.",
>> head="feature/auto-update",
>> base="main"
>> )
>> print(pr_url)
# Output:
# https://github.com/myuser/myrepo/pull/42
Or, using full automatic inference:
>> pr_url = repo.create_pr()
>> print(pr_url)
# Output:
# https://github.com/myuser/myrepo/pull/42
Advanced Git Operations¶
Repo.configure_safe_directory()¶
Configures the current repository as a git safe directory. This is essential when running in containers or with different users to avoid “dubious ownership” errors.
example:
>> repo.configure_safe_directory()
Repo.sparse_checkout_init(cone_mode=True)¶
Initialize sparse checkout for the repository. Sparse checkout allows you to check out only specific paths from a repository, which is useful for large repositories.
Parameters:
cone_mode(bool, default=True): Use cone mode for better performance
example:
>> repo.sparse_checkout_init()
Repo.sparse_checkout_set(paths)¶
Set the paths to include in sparse checkout.
Parameters:
paths(list[str]): List of paths to include in sparse checkout
example:
>> repo.sparse_checkout_set(["src/", "docs/", "README.md"])
Repo.sparse_checkout_add(paths)¶
Add additional paths to the existing sparse checkout configuration.
Parameters:
paths(list[str]): List of paths to add
example:
>> repo.sparse_checkout_add(["tests/"])
Complete sparse checkout example:
>> with Repo(url="https://github.com/user/large-repo.git") as repo:
>> repo.sparse_checkout_init()
>> repo.sparse_checkout_set(["src/", "docs/", "README.md"])
>> # Now only src/, docs/, and README.md are checked out
Repo.submodule_init()¶
Initialize git submodules in the repository.
example:
>> repo.submodule_init()
Repo.submodule_update(recursive=False, remote=False)¶
Update git submodules.
Parameters:
recursive(bool, default=False): Update submodules recursivelyremote(bool, default=False): Update to latest remote commit
example:
>> repo.submodule_update(recursive=True, remote=True)
Repo.configure_gpg_signing(key_id=None, program=None)¶
Configure GPG signing for commits.
Parameters:
key_id(str, optional): GPG key ID to use for signingprogram(str, optional): GPG program path
example:
>> repo.configure_gpg_signing(key_id="ABC123DEF456", program="/usr/bin/gpg")
Repo.configure_ssh_signing(key_path=None)¶
Configure SSH signing for commits (Git 2.34+).
Parameters:
key_path(str, optional): Path to SSH key for signing
example:
>> repo.configure_ssh_signing(key_path="/home/user/.ssh/id_ed25519.pub")
Repo.set_remote_url(remote, url, token=None)¶
Set or update remote URL with optional token authentication.
Parameters:
remote(str): Remote name (e.g., ‘origin’)url(str): Remote URLtoken(str, optional): Authentication token to embed in URL
example:
>> import os
>> repo.set_remote_url("origin", "https://github.com/user/repo.git", token=os.getenv("GITHUB_TOKEN"))
Tag Management¶
Repo.create_tag(tag, message=None, signed=False)¶
Create a git tag.
Parameters:
tag(str): Tag namemessage(str, optional): Tag message (creates annotated tag if provided)signed(bool, default=False): Create a signed tag
example:
>> # Lightweight tag
>> repo.create_tag("v1.0.0")
>> # Annotated tag
>> repo.create_tag("v1.0.0", message="Release version 1.0.0")
>> # Signed tag
>> repo.create_tag("v1.0.0", message="Release version 1.0.0", signed=True)
Repo.push_tag(tag, remote="origin")¶
Push a specific tag to remote.
Parameters:
tag(str): Tag nameremote(str, default=”origin”): Remote name
example:
>> repo.push_tag("v1.0.0")
Repo.delete_tag(tag, remote=False, remote_name="origin")¶
Delete a tag locally and optionally from remote.
Parameters:
tag(str): Tag nameremote(bool, default=False): Also delete from remoteremote_name(str, default=”origin”): Remote name
example:
>> # Delete locally only
>> repo.delete_tag("v1.0.0")
>> # Delete locally and from remote
>> repo.delete_tag("v1.0.0", remote=True)
Repo.get_latest_tag()¶
Get the most recent tag.
Returns:
str | None: Latest tag name or None if no tags exist
example:
>> latest = repo.get_latest_tag()
>> print(latest)
# Output: v2.0.0
Release Preparation¶
Repo.extract_changelog_section(changelog_path="CHANGELOG.md", version=None)¶
Extract a specific version section from a changelog file (Keep a Changelog format).
Parameters:
changelog_path(str, default=”CHANGELOG.md”): Path to CHANGELOG.md relative to repo rootversion(str, optional): Version to extract (defaults to Unreleased section)
Returns:
str: Changelog text for the version
example:
>> # Extract unreleased changes
>> unreleased = repo.extract_changelog_section()
>> print(unreleased)
>> # Extract specific version
>> v1_changes = repo.extract_changelog_section(version="v1.0.0")
>> print(v1_changes)
Repo.prepare_release(version, changelog_path="CHANGELOG.md", create_tag_flag=True, tag_message=None)¶
Helper for preparing a release with changelog extraction and automatic tagging.
Parameters:
version(str): Version number (e.g., ‘v1.0.0’)changelog_path(str, default=”CHANGELOG.md”): Path to CHANGELOG.mdcreate_tag_flag(bool, default=True): Whether to create a tagtag_message(str, optional): Message for the tag (defaults to changelog section)
Returns:
dict[str, str]: Dictionary with ‘version’, ‘changelog’, and optionally ‘tag’
example:
>> release_info = repo.prepare_release("v1.0.0")
>> print(f"Version: {release_info['version']}")
>> print(f"Changelog: {release_info['changelog']}")
>> print(f"Tag: {release_info['tag']}")
Complete release workflow example:
>> import os
>> from github_action_toolkit import Repo
>> with Repo(path=".") as repo:
>> # Configure signing
>> repo.configure_gpg_signing(key_id=os.getenv("GPG_KEY_ID"))
>>
>> # Prepare release
>> release_info = repo.prepare_release("v1.0.0")
>>
>> # Push tag to remote
>> repo.push_tag("v1.0.0")
>>
>> print(f"Released {release_info['version']}")
>> print(f"Changelog:\n{release_info['changelog']}")