or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdclients.mdconfiguration.mddiff-merge.mdindex-management.mdindex.mdobject-storage.mdobjects.mdpack-files.mdporcelain.mdreferences.mdrepository.md

cli.mddocs/

0

# Command-Line Interface

1

2

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

3

4

## Capabilities

5

6

### Main Entry Point

7

8

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

9

10

```python { .api }

11

def main(argv: List[str] = None) -> int:

12

"""

13

Main entry point for dulwich CLI.

14

15

Args:

16

argv: Command line arguments (defaults to sys.argv)

17

18

Returns:

19

Exit code (0 for success, non-zero for error)

20

"""

21

22

def signal_int(signal, frame) -> None:

23

"""

24

Signal handler for SIGINT (Ctrl+C).

25

26

Args:

27

signal: Signal number

28

frame: Current stack frame

29

"""

30

31

def signal_quit(signal, frame) -> None:

32

"""

33

Signal handler for SIGQUIT.

34

35

Args:

36

signal: Signal number

37

frame: Current stack frame

38

"""

39

```

40

41

### Command Base Classes

42

43

Base classes for implementing individual Git commands and command groups.

44

45

```python { .api }

46

class Command:

47

"""Base class for dulwich CLI commands."""

48

49

common_options: List[Tuple[str, str]] # Common command-line options

50

51

def run(self, args: List[str]) -> int:

52

"""

53

Run the command with given arguments.

54

55

Args:

56

args: Command-line arguments

57

58

Returns:

59

Exit code

60

"""

61

62

def add_parser_arguments(self, parser) -> None:

63

"""Add command-specific arguments to argument parser."""

64

65

def setup_logging(self, args) -> None:

66

"""Setup logging based on verbosity arguments."""

67

68

class SuperCommand(Command):

69

"""

70

Base class for commands that group multiple subcommands.

71

72

Examples include 'git remote', 'git submodule', 'git stash', etc.

73

"""

74

75

subcommands: ClassVar[dict[str, type[Command]]]

76

77

def run_subcommand(self, subcommand: str, args: List[str]) -> int:

78

"""

79

Run a specific subcommand.

80

81

Args:

82

subcommand: Name of subcommand to run

83

args: Arguments for the subcommand

84

85

Returns:

86

Exit code

87

"""

88

```

89

90

### Utility Functions

91

92

Helper functions used throughout the CLI implementation.

93

94

```python { .api }

95

def parse_relative_time(time_str: str) -> int:

96

"""

97

Parse relative time string like '2 weeks ago' into seconds.

98

99

Args:

100

time_str: String like '2 weeks ago' or 'now'

101

102

Returns:

103

Number of seconds

104

105

Raises:

106

ValueError: If time string cannot be parsed

107

"""

108

109

def format_bytes(bytes: int) -> str:

110

"""

111

Format bytes as human-readable string.

112

113

Args:

114

bytes: Number of bytes

115

116

Returns:

117

Human-readable string like "1.5 MB"

118

"""

119

120

def launch_editor(template_content: bytes = b"") -> bytes:

121

"""

122

Launch editor for user to enter text.

123

124

Args:

125

template_content: Initial content for editor

126

127

Returns:

128

Edited content as bytes

129

"""

130

```

131

132

### Paging System

133

134

Classes for handling paged output in CLI commands.

135

136

```python { .api }

137

class Pager:

138

"""

139

Text output pager for long command output.

140

141

Automatically pipes output through system pager

142

(like 'less') when output is longer than terminal.

143

"""

144

145

def write(self, text: str) -> int:

146

"""

147

Write text to pager.

148

149

Args:

150

text: Text to write

151

152

Returns:

153

Number of characters written

154

"""

155

156

def flush(self) -> None:

157

"""Flush pager output."""

158

159

def close(self) -> None:

160

"""Close pager and wait for completion."""

161

162

class PagerBuffer:

163

"""

164

Binary buffer wrapper for Pager to mimic sys.stdout.buffer.

165

166

Allows CLI commands to write binary data through the pager

167

by converting to text with appropriate encoding.

168

"""

169

170

def __init__(self, pager: Pager) -> None:

171

"""

172

Initialize buffer wrapper.

173

174

Args:

175

pager: Pager instance to wrap

176

"""

177

178

def write(self, data: bytes) -> int:

179

"""

180

Write bytes to pager.

181

182

Args:

183

data: Bytes to write

184

185

Returns:

186

Number of bytes written

187

"""

188

189

def flush(self) -> None:

190

"""Flush pager output."""

191

192

def writelines(self, lines: list[bytes]) -> None:

193

"""

194

Write multiple lines to pager.

195

196

Args:

197

lines: List of byte lines to write

198

"""

199

200

def close(self) -> None:

201

"""Close pager."""

202

```

203

204

### Available Commands

205

206

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

207

208

#### Repository Commands

209

210

```python { .api }

211

class cmd_init(Command):

212

"""Initialize a new Git repository."""

213

214

class cmd_clone(Command):

215

"""Clone a Git repository."""

216

217

class cmd_status(Command):

218

"""Show working tree status."""

219

220

class cmd_log(Command):

221

"""Show commit history."""

222

223

class cmd_show(Command):

224

"""Show object contents."""

225

226

class cmd_describe(Command):

227

"""Describe a commit using the most recent tag."""

228

229

class cmd_reflog(Command):

230

"""Show reference logs."""

231

232

class cmd_count_objects(Command):

233

"""Count unpacked objects and display statistics."""

234

```

235

236

#### File Operations

237

238

```python { .api }

239

class cmd_add(Command):

240

"""Add files to the staging area."""

241

242

class cmd_rm(Command):

243

"""Remove files from repository."""

244

245

class cmd_mv(Command):

246

"""Move/rename files."""

247

248

class cmd_commit(Command):

249

"""Create a new commit."""

250

251

class cmd_reset(Command):

252

"""Reset repository state."""

253

254

class cmd_checkout(Command):

255

"""Checkout branches or files."""

256

257

class cmd_ls_files(Command):

258

"""Show information about files in the index and working tree."""

259

260

class cmd_check_ignore(Command):

261

"""Check if files are ignored by .gitignore rules."""

262

263

class cmd_check_mailmap(Command):

264

"""Check names and email addresses against mailmap."""

265

```

266

267

#### Branch Operations

268

269

```python { .api }

270

class cmd_branch(Command):

271

"""List, create, or delete branches."""

272

273

class cmd_checkout(Command):

274

"""Switch branches or restore working tree files."""

275

276

class cmd_merge(Command):

277

"""Merge branches."""

278

279

class cmd_merge_tree(Command):

280

"""Show three-way merge without touching index."""

281

282

class cmd_cherry_pick(Command):

283

"""Apply changes from existing commits."""

284

285

class cmd_revert(Command):

286

"""Revert commits by creating new commits."""

287

288

class cmd_rebase(Command):

289

"""Reapply commits on top of another base tip."""

290

```

291

292

#### Remote Operations

293

294

```python { .api }

295

class cmd_fetch(Command):

296

"""Fetch from remote repository."""

297

298

class cmd_fetch_pack(Command):

299

"""Fetch pack from remote repository (low-level)."""

300

301

class cmd_pull(Command):

302

"""Pull changes from remote repository."""

303

304

class cmd_push(Command):

305

"""Push changes to remote repository."""

306

307

class cmd_remote(SuperCommand):

308

"""Manage remote repositories."""

309

310

class cmd_remote_add(Command):

311

"""Add remote repository."""

312

313

class cmd_ls_remote(Command):

314

"""List remote references."""

315

```

316

317

#### Tag Operations

318

319

```python { .api }

320

class cmd_tag(Command):

321

"""Create, list, or delete tags."""

322

323

class cmd_for_each_ref(Command):

324

"""Iterate over all references matching pattern."""

325

```

326

327

#### Diff Operations

328

329

```python { .api }

330

class cmd_diff(Command):

331

"""Show differences between commits, trees, or files."""

332

333

class cmd_diff_tree(Command):

334

"""Show differences between trees."""

335

336

class cmd_format_patch(Command):

337

"""Generate patches in mbox format."""

338

```

339

340

#### Advanced Commands

341

342

```python { .api }

343

class cmd_stash(SuperCommand):

344

"""Stash working directory changes."""

345

346

class cmd_stash_list(Command):

347

"""List stash entries."""

348

349

class cmd_stash_push(Command):

350

"""Save local modifications to new stash entry."""

351

352

class cmd_stash_pop(Command):

353

"""Apply stash and remove from stash list."""

354

355

class cmd_archive(Command):

356

"""Create archive from repository."""

357

358

class cmd_gc(Command):

359

"""Cleanup and optimize repository."""

360

361

class cmd_fsck(Command):

362

"""Verify repository integrity."""

363

364

class cmd_pack_refs(Command):

365

"""Pack references for efficiency."""

366

367

class cmd_update_server_info(Command):

368

"""Update auxiliary server information."""

369

370

class cmd_prune(Command):

371

"""Prune unreachable objects from object database."""

372

373

class cmd_repack(Command):

374

"""Repack objects in repository."""

375

376

class cmd_filter_branch(Command):

377

"""Rewrite branches by applying filters."""

378

379

class cmd_bisect(SuperCommand):

380

"""Use binary search to find commit that introduced bug."""

381

```

382

383

#### Low-level Commands

384

385

```python { .api }

386

class cmd_rev_list(Command):

387

"""List commit objects in reverse chronological order."""

388

389

class cmd_ls_tree(Command):

390

"""List tree contents."""

391

392

class cmd_hash_object(Command):

393

"""Compute object ID and optionally store object."""

394

395

class cmd_symbolic_ref(Command):

396

"""Read and modify symbolic references."""

397

398

class cmd_write_tree(Command):

399

"""Create tree object from current index."""

400

401

class cmd_commit_tree(Command):

402

"""Create commit object."""

403

404

class cmd_pack_objects(Command):

405

"""Create packed archive of objects."""

406

407

class cmd_unpack_objects(Command):

408

"""Unpack objects from packed archive."""

409

410

class cmd_dump_pack(Command):

411

"""Dump contents of pack file."""

412

413

class cmd_dump_index(Command):

414

"""Dump contents of index file."""

415

```

416

417

#### Server Commands

418

419

```python { .api }

420

class cmd_daemon(Command):

421

"""Run Git protocol daemon."""

422

423

class cmd_web_daemon(Command):

424

"""Run web-based Git repository browser."""

425

426

class cmd_upload_pack(Command):

427

"""Send packed objects for fetch operations."""

428

429

class cmd_receive_pack(Command):

430

"""Receive packed objects for push operations."""

431

```

432

433

#### Submodule Commands

434

435

```python { .api }

436

class cmd_submodule(SuperCommand):

437

"""Initialize, update, or inspect submodules."""

438

439

class cmd_submodule_list(Command):

440

"""List submodules."""

441

442

class cmd_submodule_init(Command):

443

"""Initialize submodules."""

444

445

class cmd_submodule_add(Command):

446

"""Add new submodule."""

447

448

class cmd_submodule_update(Command):

449

"""Update existing submodules."""

450

```

451

452

#### Notes Commands

453

454

```python { .api }

455

class cmd_notes(SuperCommand):

456

"""Add, show, or manipulate object notes."""

457

458

class cmd_notes_add(Command):

459

"""Add notes to objects."""

460

461

class cmd_notes_show(Command):

462

"""Show notes for objects."""

463

464

class cmd_notes_remove(Command):

465

"""Remove notes from objects."""

466

467

class cmd_notes_list(Command):

468

"""List notes objects."""

469

```

470

471

#### Worktree Commands

472

473

```python { .api }

474

class cmd_worktree(SuperCommand):

475

"""Manage multiple working trees."""

476

477

class cmd_worktree_add(Command):

478

"""Add new working tree."""

479

480

class cmd_worktree_list(Command):

481

"""List working trees."""

482

483

class cmd_worktree_remove(Command):

484

"""Remove working tree."""

485

486

class cmd_worktree_prune(Command):

487

"""Prune working tree information."""

488

489

class cmd_worktree_lock(Command):

490

"""Lock working tree."""

491

492

class cmd_worktree_unlock(Command):

493

"""Unlock working tree."""

494

495

class cmd_worktree_move(Command):

496

"""Move working tree."""

497

```

498

499

#### LFS Commands

500

501

```python { .api }

502

class cmd_lfs(Command):

503

"""Git Large File Storage operations."""

504

```

505

506

#### Bundle Commands

507

508

```python { .api }

509

class cmd_bundle(Command):

510

"""Create, verify, list, and unbundle Git bundles."""

511

```

512

513

#### Utility Commands

514

515

```python { .api }

516

class cmd_help(Command):

517

"""Show help information."""

518

519

class cmd_config(Command):

520

"""Get and set repository or global options."""

521

522

class cmd_annotate(Command):

523

"""Annotate file lines with commit information."""

524

525

class cmd_blame(Command):

526

"""Show what revision and author last modified each line."""

527

```

528

529

#### Exception Classes

530

531

```python { .api }

532

class CommitMessageError(Exception):

533

"""Raised when there's an issue with commit message."""

534

```

535

536

## Usage Examples

537

538

### Running Commands Programmatically

539

540

```python

541

from dulwich.cli import main, parse_relative_time, format_bytes

542

import sys

543

544

# Run dulwich commands programmatically

545

exit_code = main(['status'])

546

if exit_code != 0:

547

print("Command failed", file=sys.stderr)

548

549

# Clone a repository

550

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

551

552

# Show commit log with time filtering

553

since_time = parse_relative_time("2 weeks ago")

554

exit_code = main(['log', f'--since={since_time}', '--oneline'])

555

556

# Format repository size information

557

repo_size = 1073741824 # 1GB in bytes

558

print(f"Repository size: {format_bytes(repo_size)}")

559

```

560

561

### Custom Command Implementation

562

563

```python

564

from dulwich.cli import Command, SuperCommand, launch_editor

565

from dulwich.repo import Repo

566

import argparse

567

568

class CustomCommand(Command):

569

"""Example custom command."""

570

571

def add_parser_arguments(self, parser):

572

parser.add_argument('--verbose', '-v', action='store_true',

573

help='Enable verbose output')

574

parser.add_argument('--edit', action='store_true',

575

help='Launch editor for input')

576

parser.add_argument('path', help='Repository path')

577

578

def run(self, args):

579

repo = Repo(args.path)

580

581

if args.verbose:

582

print(f"Repository at: {repo.path}")

583

584

if args.edit:

585

content = launch_editor(b"Enter your text here:\n")

586

print(f"You entered: {content.decode()}")

587

588

# Perform custom operation

589

refs = list(repo.refs.keys())

590

print(f"Found {len(refs)} references")

591

592

return 0

593

594

class CustomSuperCommand(SuperCommand):

595

"""Example super command with subcommands."""

596

597

subcommands = {

598

'list': CustomCommand,

599

'show': CustomCommand,

600

}

601

602

def run(self, args):

603

if not args or args[0] not in self.subcommands:

604

print("Available subcommands:", list(self.subcommands.keys()))

605

return 1

606

607

return self.run_subcommand(args[0], args[1:])

608

```

609

610

### Command-Line Interface Usage

611

612

```bash

613

# Basic repository operations

614

dulwich init my-repo

615

dulwich clone https://github.com/user/repo.git

616

dulwich status

617

dulwich add file.txt

618

dulwich commit -m "Add file"

619

620

# Branch operations

621

dulwich branch feature-branch

622

dulwich checkout feature-branch

623

dulwich merge main

624

dulwich cherry-pick abc123

625

dulwich revert def456

626

627

# Remote operations

628

dulwich remote add origin https://github.com/user/repo.git

629

dulwich push origin main

630

dulwich pull origin main

631

dulwich fetch origin

632

dulwich ls-remote origin

633

634

# Stashing operations

635

dulwich stash push -m "Save work"

636

dulwich stash list

637

dulwich stash pop

638

639

# Information commands

640

dulwich log --oneline -10

641

dulwich show HEAD

642

dulwich diff HEAD~1..HEAD

643

dulwich describe HEAD

644

dulwich blame file.txt

645

646

# Submodule operations

647

dulwich submodule add https://github.com/user/lib.git lib

648

dulwich submodule update

649

dulwich submodule list

650

651

# Notes operations

652

dulwich notes add -m "Important note" abc123

653

dulwich notes show abc123

654

dulwich notes list

655

656

# Worktree operations

657

dulwich worktree add ../feature-work feature-branch

658

dulwich worktree list

659

dulwich worktree remove ../feature-work

660

661

# Advanced operations

662

dulwich archive HEAD --format=tar.gz

663

dulwich gc --aggressive

664

dulwich fsck --full

665

dulwich filter-branch --tree-filter 'rm -f passwords.txt'

666

dulwich bisect start

667

dulwich bundle create backup.bundle HEAD

668

669

# Low-level operations

670

dulwich hash-object file.txt

671

dulwich ls-tree HEAD

672

dulwich pack-objects .git/objects/pack/pack

673

dulwich unpack-objects < pack-file

674

```

675

676

### Error Handling

677

678

```python

679

from dulwich.cli import main

680

from dulwich.errors import NotGitRepository

681

682

try:

683

exit_code = main(['status'])

684

if exit_code != 0:

685

print("Command completed with errors")

686

except NotGitRepository:

687

print("Not in a Git repository")

688

except Exception as e:

689

print(f"Unexpected error: {e}")

690

```