Quick start

This page walks through the most common tasks. Every example assumes you already have a git repository with git-bug set up.

Opening a repository

Point GitBugRepo at any git working tree or bare repository that contains git-bug data:

from ezgb import GitBugRepo

repo = GitBugRepo('/srv/git/myproject.git')

Listing bugs

Call list_bugs() to get every bug, or pass filters:

from ezgb import Status

# All bugs
all_bugs = repo.list_bugs()

# Only open bugs
open_bugs = repo.list_bugs(status=Status.OPEN)

# Only bugs with a specific label
net_bugs = repo.list_bugs(label='area/network')

# Only bugs modified after a given time
recent = repo.list_bugs(since='2024-11-01 00:00:00')

Each item in the list is a Bug dataclass.

The since parameter accepts a unix timestamp (int), a datetime, or a date string in ISO-8601 / YYYYMMDDHHMMSS format.

Iterating lazily

For large repositories, iter_bugs() yields bugs one at a time instead of loading them all into memory:

for bug in repo.iter_bugs(status=Status.OPEN):
    print(bug.title)

It accepts the same filters as list_bugs.

Reading a single bug

If you know the bug ID (or an unambiguous prefix), use get_bug():

bug = repo.get_bug('415b4497')

print(bug.title)          # 'Login page is broken'
print(bug.status)         # Status.OPEN
print(bug.creator.name)   # 'Alice'
print(bug.labels)         # {'area/web', 'priority/high'}

for comment in bug.comments:
    print(comment.author.name, comment.text)

Creating a bug

create_bug() returns the new bug as a Bug:

bug = repo.create_bug(
    title='Crash on startup',
    body='The application crashes when the config file is missing.',
)
print(bug.id)   # full 64-character hex ID

Note

Write operations need the git bug CLI on your $PATH.

Lightweight summaries for list views

For list views where you don’t need full comment data, use list_bug_summaries(). This is much faster than list_bugs because it uses the git-bug CLI cache when available (~100ms vs seconds for large repositories):

summaries = repo.list_bug_summaries(status=Status.OPEN)
for s in summaries:
    print(f'{s.id[:7]} {s.author_name} {s.title}')
    print(f'  {s.comment_count} comments, last changed {s.edited_at}')

Each item is a BugSummary dataclass with id, title, status, labels, created_at, edited_at, author_name, and comment_count.

Adding comments

comment = repo.add_comment(bug.id, 'I can reproduce this on Fedora 41.')
print(comment.count)  # 1 (the first comment after the description)

Editing comments

Use edit_comment() to replace a comment’s text. This is useful for tombstoning comments (data removal) while preserving the comment’s identity in the operation history:

# Replace a comment's text
repo.edit_comment(bug.id, comment.id, 'Updated text')

# Tombstone a comment (remove content but keep the ID)
repo.edit_comment(bug.id, comment.id, 'X-B4-Bug-Comment: removed')

Changing status

repo.set_status(bug.id, Status.CLOSED)

# Later, reopen it:
repo.set_status(bug.id, Status.OPEN)

Editing the title

repo.set_title(bug.id, 'Crash on startup when config is missing')

Working with labels

repo.add_label(bug.id, 'priority/high')
repo.remove_label(bug.id, 'priority/high')

Removing a bug

To permanently delete a bug (this is irreversible):

repo.remove_bug(bug.id)

Syncing with a remote

Push and pull git-bug data to/from a remote:

# Push bugs and identities
returncode, stdout, stderr = repo.push('origin')

# Pull and merge (caches are invalidated automatically)
returncode, stdout, stderr = repo.pull('origin')

Reading attachments

Comments can reference file attachments by blob hash. Use get_attachment() to read the raw bytes:

for comment in bug.comments:
    for blob_hash in comment.attachment_ids:
        data = repo.get_attachment(blob_hash)
        print(len(data), 'bytes')

Listing identities

Every person who has interacted with git-bug in the repository has an identity:

for identity in repo.list_identities():
    print(identity.name, identity.email)

Caching

ezgb caches bug snapshots in memory after the first read. If you know the repository has changed (for example after a git pull), clear the cache:

# Clear everything
repo.invalidate()

# Clear just one bug
repo.invalidate(bug.id)