CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-dulwich

Pure Python implementation of the Git version control system providing comprehensive access to Git repositories without requiring the Git command-line tool

Pending
Overview
Eval results
Files

cli.mddocs/

Command-Line Interface

Complete CLI implementation providing Git command equivalents with argument parsing, progress reporting, and consistent behavior.

Capabilities

Main Entry Point

Primary entry point function for the dulwich command-line interface.

def main(argv: List[str] = None) -> int:
    """
    Main entry point for dulwich CLI.
    
    Args:
        argv: Command line arguments (defaults to sys.argv)
        
    Returns:
        Exit code (0 for success, non-zero for error)
    """

def signal_int(signal, frame) -> None:
    """
    Signal handler for SIGINT (Ctrl+C).
    
    Args:
        signal: Signal number
        frame: Current stack frame
    """

def signal_quit(signal, frame) -> None:
    """
    Signal handler for SIGQUIT.
    
    Args:
        signal: Signal number
        frame: Current stack frame
    """

Command Base Classes

Base classes for implementing individual Git commands and command groups.

class Command:
    """Base class for dulwich CLI commands."""
    
    common_options: List[Tuple[str, str]]  # Common command-line options
    
    def run(self, args: List[str]) -> int:
        """
        Run the command with given arguments.
        
        Args:
            args: Command-line arguments
            
        Returns:
            Exit code
        """
    
    def add_parser_arguments(self, parser) -> None:
        """Add command-specific arguments to argument parser."""
    
    def setup_logging(self, args) -> None:
        """Setup logging based on verbosity arguments."""

class SuperCommand(Command):
    """
    Base class for commands that group multiple subcommands.
    
    Examples include 'git remote', 'git submodule', 'git stash', etc.
    """
    
    subcommands: ClassVar[dict[str, type[Command]]]
    
    def run_subcommand(self, subcommand: str, args: List[str]) -> int:
        """
        Run a specific subcommand.
        
        Args:
            subcommand: Name of subcommand to run
            args: Arguments for the subcommand
            
        Returns:
            Exit code
        """

Utility Functions

Helper functions used throughout the CLI implementation.

def parse_relative_time(time_str: str) -> int:
    """
    Parse relative time string like '2 weeks ago' into seconds.
    
    Args:
        time_str: String like '2 weeks ago' or 'now'
        
    Returns:
        Number of seconds
        
    Raises:
        ValueError: If time string cannot be parsed
    """

def format_bytes(bytes: int) -> str:
    """
    Format bytes as human-readable string.
    
    Args:
        bytes: Number of bytes
        
    Returns:
        Human-readable string like "1.5 MB"
    """

def launch_editor(template_content: bytes = b"") -> bytes:
    """
    Launch editor for user to enter text.
    
    Args:
        template_content: Initial content for editor
        
    Returns:
        Edited content as bytes
    """

Paging System

Classes for handling paged output in CLI commands.

class Pager:
    """
    Text output pager for long command output.
    
    Automatically pipes output through system pager
    (like 'less') when output is longer than terminal.
    """
    
    def write(self, text: str) -> int:
        """
        Write text to pager.
        
        Args:
            text: Text to write
            
        Returns:
            Number of characters written
        """
    
    def flush(self) -> None:
        """Flush pager output."""
    
    def close(self) -> None:
        """Close pager and wait for completion."""

class PagerBuffer:
    """
    Binary buffer wrapper for Pager to mimic sys.stdout.buffer.
    
    Allows CLI commands to write binary data through the pager
    by converting to text with appropriate encoding.
    """
    
    def __init__(self, pager: Pager) -> None:
        """
        Initialize buffer wrapper.
        
        Args:
            pager: Pager instance to wrap
        """
    
    def write(self, data: bytes) -> int:
        """
        Write bytes to pager.
        
        Args:
            data: Bytes to write
            
        Returns:
            Number of bytes written
        """
    
    def flush(self) -> None:
        """Flush pager output."""
    
    def writelines(self, lines: list[bytes]) -> None:
        """
        Write multiple lines to pager.
        
        Args:
            lines: List of byte lines to write
        """
    
    def close(self) -> None:
        """Close pager."""

Available Commands

The dulwich CLI provides the following commands equivalent to Git operations:

Repository Commands

class cmd_init(Command):
    """Initialize a new Git repository."""

class cmd_clone(Command):
    """Clone a Git repository."""

class cmd_status(Command):
    """Show working tree status."""

class cmd_log(Command):
    """Show commit history."""

class cmd_show(Command):
    """Show object contents."""

class cmd_describe(Command):
    """Describe a commit using the most recent tag."""

class cmd_reflog(Command):
    """Show reference logs."""

class cmd_count_objects(Command):
    """Count unpacked objects and display statistics."""

File Operations

class cmd_add(Command):
    """Add files to the staging area."""

class cmd_rm(Command):
    """Remove files from repository."""

class cmd_mv(Command):
    """Move/rename files."""

class cmd_commit(Command):
    """Create a new commit."""

class cmd_reset(Command):
    """Reset repository state."""

class cmd_checkout(Command):
    """Checkout branches or files."""

class cmd_ls_files(Command):
    """Show information about files in the index and working tree."""

class cmd_check_ignore(Command):
    """Check if files are ignored by .gitignore rules."""

class cmd_check_mailmap(Command):
    """Check names and email addresses against mailmap."""

Branch Operations

class cmd_branch(Command):
    """List, create, or delete branches."""

class cmd_checkout(Command):
    """Switch branches or restore working tree files."""

class cmd_merge(Command):
    """Merge branches."""

class cmd_merge_tree(Command):
    """Show three-way merge without touching index."""

class cmd_cherry_pick(Command):
    """Apply changes from existing commits."""

class cmd_revert(Command):
    """Revert commits by creating new commits."""

class cmd_rebase(Command):
    """Reapply commits on top of another base tip."""

Remote Operations

class cmd_fetch(Command):
    """Fetch from remote repository."""

class cmd_fetch_pack(Command):
    """Fetch pack from remote repository (low-level)."""

class cmd_pull(Command):
    """Pull changes from remote repository."""

class cmd_push(Command):
    """Push changes to remote repository."""

class cmd_remote(SuperCommand):
    """Manage remote repositories."""

class cmd_remote_add(Command):
    """Add remote repository."""

class cmd_ls_remote(Command):
    """List remote references."""

Tag Operations

class cmd_tag(Command):
    """Create, list, or delete tags."""

class cmd_for_each_ref(Command):
    """Iterate over all references matching pattern."""

Diff Operations

class cmd_diff(Command):
    """Show differences between commits, trees, or files."""

class cmd_diff_tree(Command):
    """Show differences between trees."""

class cmd_format_patch(Command):
    """Generate patches in mbox format."""

Advanced Commands

class cmd_stash(SuperCommand):
    """Stash working directory changes."""

class cmd_stash_list(Command):
    """List stash entries."""

class cmd_stash_push(Command):
    """Save local modifications to new stash entry."""

class cmd_stash_pop(Command):
    """Apply stash and remove from stash list."""

class cmd_archive(Command):
    """Create archive from repository."""

class cmd_gc(Command):
    """Cleanup and optimize repository."""

class cmd_fsck(Command):
    """Verify repository integrity."""

class cmd_pack_refs(Command):
    """Pack references for efficiency."""

class cmd_update_server_info(Command):
    """Update auxiliary server information."""

class cmd_prune(Command):
    """Prune unreachable objects from object database."""

class cmd_repack(Command):
    """Repack objects in repository."""

class cmd_filter_branch(Command):
    """Rewrite branches by applying filters."""

class cmd_bisect(SuperCommand):
    """Use binary search to find commit that introduced bug."""

Low-level Commands

class cmd_rev_list(Command):
    """List commit objects in reverse chronological order."""

class cmd_ls_tree(Command):
    """List tree contents."""

class cmd_hash_object(Command):
    """Compute object ID and optionally store object."""

class cmd_symbolic_ref(Command):
    """Read and modify symbolic references."""

class cmd_write_tree(Command):
    """Create tree object from current index."""

class cmd_commit_tree(Command):
    """Create commit object."""

class cmd_pack_objects(Command):
    """Create packed archive of objects."""

class cmd_unpack_objects(Command):
    """Unpack objects from packed archive."""

class cmd_dump_pack(Command):
    """Dump contents of pack file."""

class cmd_dump_index(Command):
    """Dump contents of index file."""

Server Commands

class cmd_daemon(Command):
    """Run Git protocol daemon."""

class cmd_web_daemon(Command):
    """Run web-based Git repository browser."""

class cmd_upload_pack(Command):
    """Send packed objects for fetch operations."""

class cmd_receive_pack(Command):
    """Receive packed objects for push operations."""

Submodule Commands

class cmd_submodule(SuperCommand):
    """Initialize, update, or inspect submodules."""

class cmd_submodule_list(Command):
    """List submodules."""

class cmd_submodule_init(Command):
    """Initialize submodules."""

class cmd_submodule_add(Command):
    """Add new submodule."""

class cmd_submodule_update(Command):
    """Update existing submodules."""

Notes Commands

class cmd_notes(SuperCommand):
    """Add, show, or manipulate object notes."""

class cmd_notes_add(Command):
    """Add notes to objects."""

class cmd_notes_show(Command):
    """Show notes for objects."""

class cmd_notes_remove(Command):
    """Remove notes from objects."""

class cmd_notes_list(Command):
    """List notes objects."""

Worktree Commands

class cmd_worktree(SuperCommand):
    """Manage multiple working trees."""

class cmd_worktree_add(Command):
    """Add new working tree."""

class cmd_worktree_list(Command):
    """List working trees."""

class cmd_worktree_remove(Command):
    """Remove working tree."""

class cmd_worktree_prune(Command):
    """Prune working tree information."""

class cmd_worktree_lock(Command):
    """Lock working tree."""

class cmd_worktree_unlock(Command):
    """Unlock working tree."""

class cmd_worktree_move(Command):
    """Move working tree."""

LFS Commands

class cmd_lfs(Command):
    """Git Large File Storage operations."""

Bundle Commands

class cmd_bundle(Command):
    """Create, verify, list, and unbundle Git bundles."""

Utility Commands

class cmd_help(Command):
    """Show help information."""

class cmd_config(Command):
    """Get and set repository or global options."""

class cmd_annotate(Command):
    """Annotate file lines with commit information."""

class cmd_blame(Command):
    """Show what revision and author last modified each line."""

Exception Classes

class CommitMessageError(Exception):
    """Raised when there's an issue with commit message."""

Usage Examples

Running Commands Programmatically

from dulwich.cli import main, parse_relative_time, format_bytes
import sys

# Run dulwich commands programmatically
exit_code = main(['status'])
if exit_code != 0:
    print("Command failed", file=sys.stderr)

# Clone a repository
exit_code = main(['clone', 'https://github.com/user/repo.git', 'local-dir'])

# Show commit log with time filtering
since_time = parse_relative_time("2 weeks ago")
exit_code = main(['log', f'--since={since_time}', '--oneline'])

# Format repository size information
repo_size = 1073741824  # 1GB in bytes
print(f"Repository size: {format_bytes(repo_size)}")

Custom Command Implementation

from dulwich.cli import Command, SuperCommand, launch_editor
from dulwich.repo import Repo
import argparse

class CustomCommand(Command):
    """Example custom command."""
    
    def add_parser_arguments(self, parser):
        parser.add_argument('--verbose', '-v', action='store_true',
                          help='Enable verbose output')
        parser.add_argument('--edit', action='store_true',
                          help='Launch editor for input')
        parser.add_argument('path', help='Repository path')
    
    def run(self, args):
        repo = Repo(args.path)
        
        if args.verbose:
            print(f"Repository at: {repo.path}")
            
        if args.edit:
            content = launch_editor(b"Enter your text here:\n")
            print(f"You entered: {content.decode()}")
            
        # Perform custom operation
        refs = list(repo.refs.keys())
        print(f"Found {len(refs)} references")
        
        return 0

class CustomSuperCommand(SuperCommand):
    """Example super command with subcommands."""
    
    subcommands = {
        'list': CustomCommand,
        'show': CustomCommand,
    }
    
    def run(self, args):
        if not args or args[0] not in self.subcommands:
            print("Available subcommands:", list(self.subcommands.keys()))
            return 1
            
        return self.run_subcommand(args[0], args[1:])

Command-Line Interface Usage

# Basic repository operations
dulwich init my-repo
dulwich clone https://github.com/user/repo.git
dulwich status
dulwich add file.txt
dulwich commit -m "Add file"

# Branch operations  
dulwich branch feature-branch
dulwich checkout feature-branch
dulwich merge main
dulwich cherry-pick abc123
dulwich revert def456

# Remote operations
dulwich remote add origin https://github.com/user/repo.git
dulwich push origin main
dulwich pull origin main
dulwich fetch origin
dulwich ls-remote origin

# Stashing operations
dulwich stash push -m "Save work"
dulwich stash list
dulwich stash pop

# Information commands
dulwich log --oneline -10
dulwich show HEAD
dulwich diff HEAD~1..HEAD
dulwich describe HEAD
dulwich blame file.txt

# Submodule operations
dulwich submodule add https://github.com/user/lib.git lib
dulwich submodule update
dulwich submodule list

# Notes operations
dulwich notes add -m "Important note" abc123
dulwich notes show abc123
dulwich notes list

# Worktree operations
dulwich worktree add ../feature-work feature-branch
dulwich worktree list
dulwich worktree remove ../feature-work

# Advanced operations
dulwich archive HEAD --format=tar.gz
dulwich gc --aggressive
dulwich fsck --full
dulwich filter-branch --tree-filter 'rm -f passwords.txt'
dulwich bisect start
dulwich bundle create backup.bundle HEAD

# Low-level operations
dulwich hash-object file.txt
dulwich ls-tree HEAD
dulwich pack-objects .git/objects/pack/pack
dulwich unpack-objects < pack-file

Error Handling

from dulwich.cli import main
from dulwich.errors import NotGitRepository

try:
    exit_code = main(['status'])
    if exit_code != 0:
        print("Command completed with errors")
except NotGitRepository:
    print("Not in a Git repository")
except Exception as e:
    print(f"Unexpected error: {e}")

Install with Tessl CLI

npx tessl i tessl/pypi-dulwich

docs

cli.md

clients.md

configuration.md

diff-merge.md

index-management.md

index.md

object-storage.md

objects.md

pack-files.md

porcelain.md

references.md

repository.md

tile.json