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

references.mddocs/

0

# References and Branches

1

2

Complete reference management including branches, tags, symbolic references, and packed refs with validation, atomic updates, and comprehensive locking support for safe concurrent operations.

3

4

## Capabilities

5

6

### Reference Container Classes

7

8

Container classes for managing Git references with different storage backends.

9

10

```python { .api }

11

class RefsContainer:

12

"""Abstract container for Git references."""

13

14

def __init__(self, logger=None):

15

"""Initialize refs container with optional logger."""

16

17

def __getitem__(self, name: bytes) -> bytes:

18

"""Get reference value by name, following symbolic refs."""

19

20

def __setitem__(self, name: bytes, value: bytes) -> None:

21

"""Set reference value by name unconditionally."""

22

23

def __delitem__(self, name: bytes) -> None:

24

"""Remove reference by name unconditionally."""

25

26

def __contains__(self, refname: bytes) -> bool:

27

"""Check if reference exists in container."""

28

29

def __iter__(self) -> Iterator[bytes]:

30

"""Iterate over all reference names."""

31

32

def allkeys(self) -> Iterator[bytes]:

33

"""All refs present in this container."""

34

35

def keys(self, base: Optional[bytes] = None) -> Iterator[bytes]:

36

"""Refs present in container, optionally under a base."""

37

38

def subkeys(self, base: bytes) -> Set[bytes]:

39

"""Refs under a base with base prefix stripped."""

40

41

def as_dict(self, base: Optional[bytes] = None) -> Dict[bytes, bytes]:

42

"""Return contents of container as dictionary."""

43

44

def get_symrefs(self) -> Dict[bytes, bytes]:

45

"""Get symbolic references mapping source to target."""

46

47

def get_peeled(self, name: bytes) -> Optional[bytes]:

48

"""Get cached peeled value of a ref if available."""

49

50

def get_packed_refs(self) -> Dict[bytes, bytes]:

51

"""Get contents of packed-refs file."""

52

53

def add_packed_refs(self, new_refs: Dict[bytes, Optional[bytes]]) -> None:

54

"""Add given refs as packed refs (None means remove)."""

55

56

def read_ref(self, refname: bytes) -> Optional[bytes]:

57

"""Read reference without following symbolic refs."""

58

59

def read_loose_ref(self, name: bytes) -> Optional[bytes]:

60

"""Read loose reference and return its contents."""

61

62

def follow(self, name: bytes) -> Tuple[List[bytes], bytes]:

63

"""Follow reference name and return chain of refs and final SHA."""

64

65

def set_if_equals(

66

self,

67

name: bytes,

68

old_ref: Optional[bytes],

69

new_ref: bytes,

70

committer: Optional[bytes] = None,

71

timestamp: Optional[float] = None,

72

timezone: Optional[int] = None,

73

message: Optional[bytes] = None

74

) -> bool:

75

"""Set refname to new_ref only if it currently equals old_ref."""

76

77

def add_if_new(

78

self,

79

name: bytes,

80

ref: bytes,

81

committer: Optional[bytes] = None,

82

timestamp: Optional[float] = None,

83

timezone: Optional[int] = None,

84

message: Optional[bytes] = None

85

) -> bool:

86

"""Add new reference only if it doesn't already exist."""

87

88

def remove_if_equals(

89

self,

90

name: bytes,

91

old_ref: Optional[bytes],

92

committer: Optional[bytes] = None,

93

timestamp: Optional[float] = None,

94

timezone: Optional[int] = None,

95

message: Optional[bytes] = None

96

) -> bool:

97

"""Remove refname only if it currently equals old_ref."""

98

99

def set_symbolic_ref(

100

self,

101

name: bytes,

102

other: bytes,

103

committer: Optional[bytes] = None,

104

timestamp: Optional[float] = None,

105

timezone: Optional[int] = None,

106

message: Optional[bytes] = None

107

) -> None:

108

"""Make a ref point at another ref."""

109

110

def import_refs(

111

self,

112

base: bytes,

113

other: Dict[bytes, bytes],

114

committer: Optional[bytes] = None,

115

timestamp: Optional[float] = None,

116

timezone: Optional[int] = None,

117

message: Optional[bytes] = None,

118

prune: bool = False

119

) -> None:

120

"""Import refs from another container under base."""

121

122

def pack_refs(self, all: bool = False) -> None:

123

"""Pack loose refs into packed-refs file."""

124

125

class DictRefsContainer(RefsContainer):

126

"""Dictionary-based reference container.

127

128

This container does not support symbolic or packed references

129

and is not threadsafe.

130

"""

131

132

def __init__(

133

self,

134

refs: Dict[bytes, bytes],

135

logger=None

136

):

137

"""

138

Initialize dict-based refs container.

139

140

Args:

141

refs: Dictionary mapping ref names to SHA-1 values

142

logger: Optional reflog logger

143

"""

144

145

class InfoRefsContainer(RefsContainer):

146

"""Reference container based on info/refs file.

147

148

Read-only container that parses Git's info/refs format.

149

"""

150

151

def __init__(self, f):

152

"""

153

Initialize info/refs container.

154

155

Args:

156

f: File-like object containing info/refs data

157

"""

158

159

class DiskRefsContainer(RefsContainer):

160

"""Filesystem-based reference container.

161

162

Stores references as files in the Git repository's refs directory

163

and supports packed-refs files for efficient storage.

164

"""

165

166

def __init__(

167

self,

168

path: str,

169

worktree_path: Optional[str] = None,

170

logger=None

171

):

172

"""

173

Initialize filesystem refs container.

174

175

Args:

176

path: Path to Git repository

177

worktree_path: Optional path to worktree (for worktree support)

178

logger: Optional reflog logger

179

"""

180

181

def refpath(self, name: bytes) -> str:

182

"""

183

Get filesystem path for reference name.

184

185

Args:

186

name: Reference name

187

188

Returns:

189

Full filesystem path to reference file

190

"""

191

192

def get_packed_refs(self) -> Dict[bytes, bytes]:

193

"""

194

Get contents of packed-refs file.

195

196

Returns:

197

Dictionary mapping ref names to SHA-1 values

198

"""

199

200

def get_peeled(self, name: bytes) -> Optional[bytes]:

201

"""

202

Get peeled value from packed-refs file.

203

204

Args:

205

name: Reference name

206

207

Returns:

208

Peeled SHA-1 value if available, None otherwise

209

"""

210

211

def _write_packed_refs(self) -> None:

212

"""Write current packed refs to disk."""

213

214

def _read_packed_refs(self) -> Tuple[Dict[bytes, bytes], Dict[bytes, bytes]]:

215

"""Read packed refs from disk.

216

217

Returns:

218

Tuple of (packed_refs_dict, peeled_refs_dict)

219

"""

220

```

221

222

### Reference Validation Functions

223

224

Functions for validating and parsing Git references.

225

226

```python { .api }

227

def check_ref_format(refname: bytes) -> bool:

228

"""

229

Check if reference name follows Git naming rules.

230

231

Args:

232

refname: Reference name to validate

233

234

Returns:

235

True if valid reference name

236

"""

237

238

def parse_symref_value(contents: bytes) -> bytes:

239

"""

240

Parse symbolic reference value from file contents.

241

242

Args:

243

contents: Raw file contents

244

245

Returns:

246

Target reference name

247

"""

248

249

def parse_remote_ref(ref: bytes) -> Tuple[bytes, bytes]:

250

"""

251

Parse remote reference into remote name and branch.

252

253

Args:

254

ref: Remote reference (e.g., b'refs/remotes/origin/main')

255

256

Returns:

257

Tuple of (remote_name, branch_name)

258

"""

259

```

260

261

### Packed References

262

263

Functions for reading and writing packed-refs files for efficient reference storage.

264

265

```python { .api }

266

def read_packed_refs(f) -> Iterator[Tuple[bytes, bytes]]:

267

"""

268

Read packed references from file.

269

270

Args:

271

f: File-like object containing packed-refs data

272

273

Yields:

274

Tuples of (sha1, ref_name)

275

"""

276

277

def read_packed_refs_with_peeled(f) -> Iterator[Tuple[bytes, bytes, Optional[bytes]]]:

278

"""

279

Read packed refs file including peeled refs.

280

281

Assumes the "# pack-refs with: peeled" line was already read.

282

283

Args:

284

f: File-like object to read from, seek'ed to second line

285

286

Yields:

287

Tuples of (sha1, ref_name, peeled_sha1_or_none)

288

"""

289

290

def write_packed_refs(

291

f,

292

packed_refs: Dict[bytes, bytes],

293

peeled_refs: Optional[Dict[bytes, bytes]] = None

294

) -> None:

295

"""

296

Write packed references to file.

297

298

Args:

299

f: File-like object to write to

300

packed_refs: Dictionary of ref_name to SHA-1

301

peeled_refs: Optional dictionary of ref_name to peeled SHA-1

302

"""

303

```

304

305

### Reference Type Checking

306

307

Functions for identifying different types of references.

308

309

```python { .api }

310

def is_local_branch(ref: bytes) -> bool:

311

"""

312

Check if reference is a local branch.

313

314

Args:

315

ref: Reference name

316

317

Returns:

318

True if local branch reference (starts with refs/heads/)

319

"""

320

321

def strip_peeled_refs(refs: Dict[bytes, bytes]) -> Dict[bytes, bytes]:

322

"""

323

Remove peeled reference entries from refs dictionary.

324

325

Args:

326

refs: Dictionary of references

327

328

Returns:

329

Dictionary with peeled refs (ending with ^{}) removed

330

"""

331

332

def split_peeled_refs(refs: Dict[bytes, bytes]) -> Tuple[Dict[bytes, bytes], Dict[bytes, bytes]]:

333

"""

334

Split peeled refs from regular refs.

335

336

Args:

337

refs: Dictionary of references

338

339

Returns:

340

Tuple of (regular_refs, peeled_refs) dictionaries

341

"""

342

343

def serialize_refs(

344

store: ObjectContainer,

345

refs: Dict[bytes, bytes]

346

) -> Iterator[bytes]:

347

"""

348

Serialize references to info/refs format.

349

350

Args:

351

store: Object store for peeling tags

352

refs: Dictionary of references

353

354

Yields:

355

Lines in info/refs format

356

"""

357

358

def read_info_refs(f) -> Dict[bytes, bytes]:

359

"""

360

Read info/refs file format.

361

362

Args:

363

f: File-like object containing info/refs data

364

365

Returns:

366

Dictionary mapping ref names to SHA-1 values

367

"""

368

369

def write_info_refs(

370

refs: Dict[bytes, bytes],

371

store: ObjectContainer

372

) -> Iterator[bytes]:

373

"""

374

Generate info/refs format with peeled values.

375

376

Args:

377

refs: Dictionary of references

378

store: Object store for peeling tags

379

380

Yields:

381

Lines in info/refs format including peeled values

382

"""

383

```

384

385

### Reference Locking

386

387

Context manager for atomic reference updates.

388

389

```python { .api }

390

class locked_ref:

391

"""

392

Lock a ref while making modifications.

393

394

Works as a context manager to ensure atomic reference updates.

395

Locks the reference file to prevent concurrent modifications.

396

"""

397

398

def __init__(self, refs_container: DiskRefsContainer, refname: bytes):

399

"""

400

Initialize locked reference.

401

402

Args:

403

refs_container: DiskRefsContainer to operate on

404

refname: Name of reference to lock

405

"""

406

407

def __enter__(self) -> "locked_ref":

408

"""Enter context and acquire lock."""

409

410

def __exit__(self, exc_type, exc_value, traceback) -> None:

411

"""Exit context and release lock."""

412

413

def get(self) -> Optional[bytes]:

414

"""

415

Get current value of the ref.

416

417

Returns:

418

Current SHA-1 or symbolic ref value, None if not found

419

"""

420

421

def ensure_equals(self, expected_value: Optional[bytes]) -> bool:

422

"""

423

Ensure ref currently equals expected value.

424

425

Args:

426

expected_value: Expected current value

427

428

Returns:

429

True if ref equals expected value

430

"""

431

432

def set(self, new_ref: bytes) -> None:

433

"""

434

Set ref to new value.

435

436

Args:

437

new_ref: New SHA-1 or symbolic ref value

438

"""

439

440

def set_symbolic_ref(self, target: bytes) -> None:

441

"""

442

Make this ref point at another ref.

443

444

Args:

445

target: Name of ref to point at

446

"""

447

448

def delete(self) -> None:

449

"""Delete the ref file while holding the lock."""

450

```

451

452

## Exception Classes

453

454

```python { .api }

455

class SymrefLoop(Exception):

456

"""Exception raised when symbolic reference creates a loop."""

457

458

def __init__(self, ref: bytes, depth: int):

459

"""

460

Initialize symref loop exception.

461

462

Args:

463

ref: Reference that caused the loop

464

depth: Depth at which loop was detected

465

"""

466

467

## Usage Examples

468

469

### Basic Reference Operations

470

471

```python

472

from dulwich.repo import Repo

473

from dulwich.refs import check_ref_format, parse_remote_ref

474

475

# Open repository and access references

476

repo = Repo('.')

477

refs = repo.refs

478

479

# List all references

480

for ref_name in refs.keys():

481

print(f"{ref_name.decode()}: {refs[ref_name].hex()}")

482

483

# Follow symbolic references

484

head_chain, head_sha = refs.follow(b'HEAD')

485

print(f"HEAD chain: {[r.decode() for r in head_chain]}")

486

print(f"HEAD SHA: {head_sha.decode()}")

487

488

# Get current branch safely

489

try:

490

head_target = refs[b'HEAD']

491

if b'refs/heads/' in head_chain[0]:

492

current_branch = head_chain[0][11:] # Remove 'refs/heads/' prefix

493

print(f"Current branch: {current_branch.decode()}")

494

except (KeyError, IndexError):

495

print("HEAD is detached")

496

497

# Create a new branch reference with validation

498

new_ref = b'refs/heads/feature-branch'

499

if check_ref_format(new_ref[5:]): # Remove 'refs/' prefix for validation

500

refs[new_ref] = repo.head()

501

502

# Parse remote references

503

remote_ref = b'refs/remotes/origin/main'

504

remote_name, branch_name = parse_remote_ref(remote_ref)

505

print(f"Remote: {remote_name.decode()}, Branch: {branch_name.decode()}")

506

```

507

508

### Working with Symbolic References

509

510

```python

511

from dulwich.refs import parse_symref_value, locked_ref

512

513

# Check if HEAD is a symbolic reference

514

with open('.git/HEAD', 'rb') as f:

515

head_contents = f.read()

516

if head_contents.startswith(b'ref: '):

517

target_ref = parse_symref_value(head_contents)

518

print(f"HEAD points to: {target_ref.decode()}")

519

520

# Atomically update a reference

521

with locked_ref(repo.refs, b'refs/heads/feature') as ref_lock:

522

current_value = ref_lock.get()

523

if ref_lock.ensure_equals(current_value):

524

ref_lock.set(new_commit_sha)

525

print("Reference updated successfully")

526

```

527

528

### Working with Packed References

529

530

```python

531

from dulwich.refs import read_packed_refs, write_packed_refs

532

533

# Read packed references

534

with open('.git/packed-refs', 'rb') as f:

535

for sha, ref_name in read_packed_refs(f):

536

print(f"{ref_name.decode()}: {sha.decode()}")

537

538

# Write packed references

539

packed_refs = {

540

b'refs/heads/main': b'abc123...',

541

b'refs/tags/v1.0': b'def456...'

542

}

543

544

with open('.git/packed-refs', 'wb') as f:

545

write_packed_refs(f, packed_refs)

546

```

547

548

### Advanced Reference Operations

549

550

```python

551

from dulwich.refs import DiskRefsContainer, is_local_branch, strip_peeled_refs

552

553

# Work with disk-based references

554

refs_container = DiskRefsContainer('/path/to/repo')

555

556

# Filter for local branches only

557

all_refs = refs_container.as_dict()

558

local_branches = {

559

name: sha for name, sha in all_refs.items()

560

if is_local_branch(name)

561

}

562

563

# Remove peeled refs from dictionary

564

clean_refs = strip_peeled_refs(all_refs)

565

566

# Import refs from another repository

567

remote_refs = {'main': b'abc123...', 'develop': b'def456...'}

568

refs_container.import_refs(

569

b'refs/remotes/origin',

570

remote_refs,

571

message=b'fetch from origin'

572

)

573

```