Skip to content

Git Client API

The Git plugin adds core Git operations to Titan through a high-level client and reusable workflows. It covers branches, commits, status inspection, diffs, remotes, stashes, tags, and worktrees.

This page documents the plugin from a functional point of view, while also showing how each capability is called and which parameters it needs.


Requirements

To use the Git plugin in a project:

  • Enable the git plugin in .titan/config.toml
  • Install the git CLI and make sure it is available in PATH
  • Run Titan inside a Git repository

Example project configuration:

[plugins.git]
enabled = true

[plugins.git.config]
main_branch = "main"
default_remote = "origin"

Accessing the client

In Titan code, the public entry point is the Git plugin client:

git_plugin = config.registry.get_plugin("git")
client = git_plugin.get_client()

The client returns ClientResult[...] values. In practice, this means each call can succeed with data or return an error result.


Branch operations

Get the current branch

Returns the currently checked out branch name.

Call:

client.get_current_branch()

Parameters:

  • No parameters.

List branches

Returns local branches, or remote branches when requested.

Call:

client.get_branches(remote=False)

Parameters:

  • remote: Optional. Set to True to list remote branches instead of local ones.

Create a branch

Creates a new branch from a starting point.

Call:

client.create_branch(branch_name="feature/search", start_point="HEAD")

Parameters:

  • branch_name: Required. New branch name.
  • start_point: Optional. Git ref to branch from.

Delete a branch

Deletes a branch directly.

Call:

client.delete_branch(branch="feature/search", force=False)

Parameters:

  • branch: Required. Branch name to delete.
  • force: Optional. Force deletion.

Delete a branch safely

Deletes a branch only if it is not considered protected.

Call:

client.safe_delete_branch(branch="feature/search", force=False)

Parameters:

  • branch: Required. Branch name to delete.
  • force: Optional. Force deletion.

Checkout a branch

Switches the repository to another branch.

Call:

client.checkout("feature/search")

Parameters:

  • branch: Required. Branch name to checkout.

Check whether a branch exists on remote

Checks if a branch already exists in a remote repository.

Call:

client.branch_exists_on_remote(branch="feature/search", remote="origin")

Parameters:

  • branch: Required. Branch name.
  • remote: Optional. Remote name.

Update a branch from remote

Fetches and fast-forwards a branch from the remote.

Call:

client.update_branch(branch="main", remote="origin")

Parameters:

  • branch: Required. Branch to update.
  • remote: Optional. Remote name. Defaults to the configured default remote.

Update from the configured main branch

Updates the current branch from the configured main branch.

Call:

client.update_from_main()

Parameters:

  • No parameters.

Checkout safely

Stores the current branch, optionally stashes local changes, and then switches branches.

Call:

client.safe_checkout(branch="feature/search", auto_stash=True)

Parameters:

  • branch: Required. Branch to checkout.
  • auto_stash: Optional. Automatically stash uncommitted changes first.

Return to the original branch

Returns to the branch previously saved by safe_checkout.

Call:

client.return_to_original_branch()

Parameters:

  • No parameters.

Check whether a branch is protected

Checks if a branch name is treated as protected by the client.

Call:

client.is_protected_branch("main")

Parameters:

  • branch: Required. Branch name.

Commit operations

Create a commit

Creates a commit from the current working tree.

Call:

client.commit(message="feat: add search filters", all=False, no_verify=True)

Parameters:

  • message: Required. Commit message.
  • all: Optional. Include tracked modified files automatically.
  • no_verify: Optional. Skip Git hooks.

Create a commit for specific files

Creates a commit only for the files passed in the call.

Call:

client.commit_files(
    files=["src/search.py", "tests/test_search.py"],
    message="test: cover search filters",
    no_verify=True,
)

Parameters:

  • files: Required. Files to include in the commit.
  • message: Required. Commit message.
  • no_verify: Optional. Skip Git hooks.

Get the current commit SHA

Returns the SHA of HEAD.

Call:

client.get_current_commit()

Parameters:

  • No parameters.

Get the commit SHA for a ref

Resolves any Git ref to its commit SHA.

Call:

client.get_commit_sha("HEAD~1")

Parameters:

  • ref: Required. Any Git ref.

Get commits versus base

Returns commit messages from the base branch up to HEAD.

Call:

client.get_commits_vs_base()

Parameters:

  • No parameters.

Get commits in a branch compared to another branch

Returns the commits present in the head branch but not in the base branch.

Call:

client.get_branch_commits(base_branch="main", head_branch="feature/search")

Parameters:

  • base_branch: Required. Base branch.
  • head_branch: Required. Head branch.

Get commits between refs

Returns commits reachable from one ref but not another.

Call:

client.get_commits_between_refs(base_ref="origin/main", head_ref="HEAD")

Parameters:

  • base_ref: Required. Base ref.
  • head_ref: Optional. Head ref.

Count commits ahead of a base branch

Counts how many commits the current branch is ahead of another branch.

Call:

client.count_commits_ahead(base_branch="main")

Parameters:

  • base_branch: Optional. Base branch to compare against.

Count unpushed commits

Counts how many commits have not been pushed to the remote yet.

Call:

client.count_unpushed_commits(branch=None, remote="origin")

Parameters:

  • branch: Optional. Branch to inspect. Uses the current branch when omitted.
  • remote: Optional. Remote name.

Status operations

Get repository status

Returns a structured view of the current repository state.

Call:

client.get_status()

Parameters:

  • No parameters.

Check for uncommitted changes

Returns whether the repository has local changes not yet committed.

Call:

client.has_uncommitted_changes()

Parameters:

  • No parameters.

Diff operations

Get a diff between refs

Returns the diff between two refs.

Call:

client.get_diff(base_ref="origin/main", head_ref="HEAD")

Parameters:

  • base_ref: Required. Base ref.
  • head_ref: Optional. Head ref.

Get the full uncommitted diff

Returns the diff of all local changes.

Call:

client.get_uncommitted_diff()

Parameters:

  • No parameters.

Get the staged diff

Returns only the staged changes.

Call:

client.get_staged_diff()

Parameters:

  • No parameters.

Get the unstaged diff

Returns only the unstaged changes.

Call:

client.get_unstaged_diff()

Parameters:

  • No parameters.

Get the diff for one file

Returns the diff for a single file path.

Call:

client.get_file_diff("src/search.py")

Parameters:

  • file_path: Required. File path to inspect.

Get the diff between branches

Returns the diff between two branches, with configurable context lines.

Call:

client.get_branch_diff(
    base_branch="main",
    head_branch="feature/search",
    context_lines=3,
    use_remote=False,
)

Parameters:

  • base_branch: Required. Base branch.
  • head_branch: Required. Head branch.
  • context_lines: Optional. Number of diff context lines.
  • use_remote: Optional. Treat both branches as remote refs.

Get a diff stat between refs

Returns a summary of file-level changes between refs.

Call:

client.get_diff_stat(base_ref="origin/main", head_ref="HEAD")

Parameters:

  • base_ref: Required. Base ref.
  • head_ref: Optional. Head ref.

Get the diff stat for uncommitted changes

Returns a compact summary of local changes.

Call:

client.get_uncommitted_diff_stat()

Parameters:

  • No parameters.

Get the diff stat between branches

Returns a compact summary of changes between two branches.

Call:

client.get_branch_diff_stat(base_branch="main", head_branch="feature/search")

Parameters:

  • base_branch: Required. Base branch.
  • head_branch: Required. Head branch.

Remote operations

Push to a remote

Pushes commits to a remote branch.

Call:

client.push(remote="origin", branch="feature/search", set_upstream=True, tags=False)

Parameters:

  • remote: Optional. Remote name.
  • branch: Optional. Branch to push. Uses the current branch when omitted.
  • set_upstream: Optional. Set the upstream tracking branch.
  • tags: Optional. Push tags too.

Push a tag

Pushes a single tag to a remote.

Call:

client.push_tag(tag_name="v1.2.0", remote="origin")

Parameters:

  • tag_name: Required. Tag name.
  • remote: Optional. Remote name.

Pull from a remote

Pulls changes from a remote branch.

Call:

client.pull(remote="origin", branch="main")

Parameters:

  • remote: Optional. Remote name.
  • branch: Optional. Branch to pull.

Fetch from a remote

Fetches changes without merging them.

Call:

client.fetch(remote="origin", branch="main", all=False)

Parameters:

  • remote: Optional. Remote name.
  • branch: Optional. Branch to fetch.
  • all: Optional. Fetch all remotes.

Extract GitHub repository info

Parses the remote URL and returns the GitHub owner and repository name when available.

Call:

client.get_github_repo_info()

Parameters:

  • No parameters.

Stash operations

Create a stash

Stashes current local changes.

Call:

client.stash_push(message="temporary local changes")

Parameters:

  • message: Optional. Stash message.

Pop a stash

Applies and removes a stash.

Call:

client.stash_pop(stash_ref=None)

Parameters:

  • stash_ref: Optional. Specific stash reference.

Find a stash by message

Looks up a stash using its message.

Call:

client.find_stash_by_message("temporary local changes")

Parameters:

  • message: Required. Stash message to search for.

Restore a stash by message

Finds a stash by message and restores it.

Call:

client.restore_stash("temporary local changes")

Parameters:

  • message: Required. Stash message to restore.

Tag operations

Create a tag

Creates an annotated tag.

Call:

client.create_tag(tag_name="v1.2.0", message="Release 1.2.0", ref="HEAD")

Parameters:

  • tag_name: Required. Tag name.
  • message: Required. Tag annotation message.
  • ref: Optional. Ref to tag.

Delete a tag

Deletes a local tag.

Call:

client.delete_tag("v1.2.0")

Parameters:

  • tag_name: Required. Tag name.

Check whether a tag exists locally

Checks if a tag is present in the local repository.

Call:

client.tag_exists("v1.2.0")

Parameters:

  • tag_name: Required. Tag name.

Check whether a tag exists on remote

Checks if a tag exists in a remote repository.

Call:

client.remote_tag_exists(tag_name="v1.2.0", remote="origin")

Parameters:

  • tag_name: Required. Tag name.
  • remote: Optional. Remote name.

List tags

Returns the tags available in the repository.

Call:

client.list_tags()

Parameters:

  • No parameters.

Worktree operations

Create a worktree

Creates a new Git worktree.

Call:

client.create_worktree(
    path="../repo-search-worktree",
    branch="feature/search",
    create_branch=False,
    detached=False,
)

Parameters:

  • path: Required. Filesystem path for the worktree.
  • branch: Required. Branch to attach to the worktree.
  • create_branch: Optional. Create the branch if needed.
  • detached: Optional. Create the worktree in detached mode.

Remove a worktree

Removes an existing worktree.

Call:

client.remove_worktree(path="../repo-search-worktree", force=False)

Parameters:

  • path: Required. Worktree path.
  • force: Optional. Force removal.

List worktrees

Returns all worktrees for the repository.

Call:

client.list_worktrees()

Parameters:

  • No parameters.

Run a Git command in a worktree

Runs a Git command inside a specific worktree.

Call:

client.run_in_worktree(worktree_path="../repo-search-worktree", args=["status", "--short"])

Parameters:

  • worktree_path: Required. Worktree path.
  • args: Required. Git arguments to execute.

Get recent commits from a worktree

Returns recent commits from a specific worktree.

Call:

client.get_commits(worktree_path="../repo-search-worktree", limit=10)

Parameters:

  • worktree_path: Required. Worktree path.
  • limit: Optional. Maximum number of commits.

Get the worktree diff stat

Returns a diff summary for local changes in a worktree.

Call:

client.get_worktree_diff_stat(worktree_path="../repo-search-worktree")

Parameters:

  • worktree_path: Required. Worktree path.

Checkout a branch in a worktree

Checks out, or creates, a branch inside a specific worktree.

Call:

client.checkout_branch_in_worktree(
    worktree_path="../repo-search-worktree",
    branch_name="feature/search",
    force=False,
)

Parameters:

  • worktree_path: Required. Worktree path.
  • branch_name: Required. Branch name.
  • force: Optional. Force the checkout.

Commit changes in a worktree

Stages and commits changes inside a worktree.

Call:

client.commit_in_worktree(
    worktree_path="../repo-search-worktree",
    message="feat: add search filters",
    add_all=True,
    no_verify=False,
)

Parameters:

  • worktree_path: Required. Worktree path.
  • message: Required. Commit message.
  • add_all: Optional. Stage all tracked changes before committing.
  • no_verify: Optional. Skip Git hooks.

Push from a worktree

Pushes a branch from a specific worktree to a remote.

Call:

client.push_from_worktree(
    worktree_path="../repo-search-worktree",
    branch="feature/search",
    remote="origin",
)

Parameters:

  • worktree_path: Required. Worktree path.
  • branch: Required. Branch to push.
  • remote: Optional. Remote name.

The Git plugin ships with workflows that use these capabilities directly:

  • commit-ai: Checks repository status, shows a summary of local changes, generates a commit message with AI, creates the commit, and pushes it

These workflows can be used as-is or extended from .titan/workflows/.