0
# Git Objects
1
2
Access to Git's core object model including commits, trees, blobs, and tags. Provides complete metadata access, object traversal capabilities, and serialization support for repository analysis and manipulation.
3
4
## Capabilities
5
6
### Base Object Interface
7
8
Foundation class for all Git objects providing common functionality for object identification, serialization, and repository access.
9
10
```python { .api }
11
class Object:
12
def __init__(self, repo: "Repo", binsha: bytes):
13
"""
14
Initialize a git object.
15
16
Args:
17
repo: Repository containing the object
18
binsha: Binary SHA-1 hash of the object
19
"""
20
21
@property
22
def hexsha(self) -> str:
23
"""Hexadecimal SHA-1 hash string."""
24
25
@property
26
def binsha(self) -> bytes:
27
"""Binary SHA-1 hash."""
28
29
@property
30
def type(self) -> str:
31
"""Object type string ('commit', 'tree', 'blob', 'tag')."""
32
33
@property
34
def size(self) -> int:
35
"""Size of object data in bytes."""
36
37
@property
38
def repo(self) -> "Repo":
39
"""Repository containing this object."""
40
41
def __eq__(self, other: Any) -> bool:
42
"""Compare objects by SHA-1 hash."""
43
44
def __hash__(self) -> int:
45
"""Hash based on SHA-1."""
46
47
class IndexObject(Object):
48
"""Base for objects that can be part of an index (trees, blobs, submodules)."""
49
50
def __init__(self, repo: "Repo", binsha: bytes, mode: int = None, path: str = None):
51
"""
52
Initialize index object.
53
54
Args:
55
repo: Repository containing object
56
binsha: Binary SHA-1 hash
57
mode: Unix file mode
58
path: Path within repository
59
"""
60
61
@property
62
def mode(self) -> int:
63
"""Unix file mode."""
64
65
@property
66
def path(self) -> str:
67
"""Path within repository."""
68
69
@property
70
def name(self) -> str:
71
"""Object name (basename of path)."""
72
```
73
74
### Commit Objects
75
76
Represent Git commits with full metadata including author, committer, message, and parent relationships.
77
78
```python { .api }
79
class Commit(Object):
80
def __init__(
81
self,
82
repo: "Repo",
83
binsha: bytes,
84
tree: "Tree" = None,
85
author: "Actor" = None,
86
authored_date: int = None,
87
author_tz_offset: int = None,
88
committer: "Actor" = None,
89
committed_date: int = None,
90
committer_tz_offset: int = None,
91
message: str = None,
92
parents: list["Commit"] = None,
93
encoding: str = None
94
):
95
"""
96
Initialize commit object.
97
98
Args:
99
repo: Repository containing commit
100
binsha: Binary SHA-1 hash
101
tree: Tree object for this commit
102
author: Author information
103
authored_date: Author timestamp
104
author_tz_offset: Author timezone offset
105
committer: Committer information
106
committed_date: Commit timestamp
107
committer_tz_offset: Committer timezone offset
108
message: Commit message
109
parents: Parent commits
110
encoding: Text encoding
111
"""
112
113
@property
114
def message(self) -> str:
115
"""Commit message."""
116
117
@property
118
def author(self) -> "Actor":
119
"""Author information."""
120
121
@property
122
def committer(self) -> "Actor":
123
"""Committer information."""
124
125
@property
126
def authored_date(self) -> int:
127
"""Author timestamp as seconds since epoch."""
128
129
@property
130
def committed_date(self) -> int:
131
"""Commit timestamp as seconds since epoch."""
132
133
@property
134
def authored_datetime(self) -> datetime:
135
"""Author timestamp as datetime object."""
136
137
@property
138
def committed_datetime(self) -> datetime:
139
"""Commit timestamp as datetime object."""
140
141
@property
142
def author_tz_offset(self) -> int:
143
"""Author timezone offset in seconds."""
144
145
@property
146
def committer_tz_offset(self) -> int:
147
"""Committer timezone offset in seconds."""
148
149
@property
150
def tree(self) -> "Tree":
151
"""Tree object for this commit."""
152
153
@property
154
def parents(self) -> tuple["Commit", ...]:
155
"""Parent commits."""
156
157
@property
158
def stats(self) -> "Stats":
159
"""Commit statistics (files changed, insertions, deletions)."""
160
161
def iter_parents(self, paths: list[str] = None, **kwargs) -> Iterator["Commit"]:
162
"""
163
Iterate parent commits.
164
165
Args:
166
paths: Limit to commits affecting these paths
167
**kwargs: Additional git log options
168
169
Returns:
170
Iterator of parent commits
171
"""
172
173
def iter_items(
174
self,
175
repo: "Repo",
176
*args,
177
**kwargs
178
) -> Iterator["Commit"]:
179
"""
180
Iterate commits.
181
182
Args:
183
repo: Repository to search
184
*args: Positional arguments
185
**kwargs: Keyword arguments
186
187
Returns:
188
Iterator of commits
189
"""
190
```
191
192
### Tree Objects
193
194
Represent Git tree objects (directories) with support for traversal and content access.
195
196
```python { .api }
197
class Tree(IndexObject):
198
def __init__(self, repo: "Repo", binsha: bytes, mode: int = None, path: str = None):
199
"""
200
Initialize tree object.
201
202
Args:
203
repo: Repository containing tree
204
binsha: Binary SHA-1 hash
205
mode: Unix file mode
206
path: Path within repository
207
"""
208
209
def __getitem__(self, item: Union[int, str]) -> IndexObject:
210
"""Get tree item by index or name."""
211
212
def __contains__(self, item: str) -> bool:
213
"""Check if tree contains item."""
214
215
def __len__(self) -> int:
216
"""Number of items in tree."""
217
218
def __iter__(self) -> Iterator[IndexObject]:
219
"""Iterate over tree items."""
220
221
@property
222
def trees(self) -> list["Tree"]:
223
"""Subdirectories in this tree."""
224
225
@property
226
def blobs(self) -> list["Blob"]:
227
"""Files in this tree."""
228
229
def traverse(
230
self,
231
predicate: Callable[[IndexObject, int], bool] = None,
232
prune: Callable[[IndexObject, int], bool] = None,
233
depth: int = -1,
234
branch_first: bool = True,
235
visit_once: bool = False,
236
ignore_self: int = 1
237
) -> Iterator[IndexObject]:
238
"""
239
Traverse tree recursively.
240
241
Args:
242
predicate: Filter function for items
243
prune: Function to skip subtrees
244
depth: Maximum depth (-1 for unlimited)
245
branch_first: Traverse breadth-first vs depth-first
246
visit_once: Visit each object only once
247
ignore_self: Skip self in traversal
248
249
Returns:
250
Iterator of tree objects
251
"""
252
253
class TreeModifier:
254
"""Helper for modifying tree objects."""
255
256
def __init__(self, cache: list = None):
257
"""
258
Initialize tree modifier.
259
260
Args:
261
cache: Initial cache entries
262
"""
263
264
def add(self, sha: Union[str, bytes], mode: int, name: str, force: bool = False) -> "TreeModifier":
265
"""
266
Add entry to tree.
267
268
Args:
269
sha: Object SHA-1 hash
270
mode: Unix file mode
271
name: Entry name
272
force: Overwrite existing entries
273
274
Returns:
275
Self for chaining
276
"""
277
278
def write(self, repo: "Repo") -> "Tree":
279
"""
280
Write modified tree to repository.
281
282
Args:
283
repo: Repository to write to
284
285
Returns:
286
New tree object
287
"""
288
```
289
290
### Blob Objects
291
292
Represent Git blob objects (files) with content access and metadata.
293
294
```python { .api }
295
class Blob(IndexObject):
296
def __init__(self, repo: "Repo", binsha: bytes, mode: int = None, path: str = None):
297
"""
298
Initialize blob object.
299
300
Args:
301
repo: Repository containing blob
302
binsha: Binary SHA-1 hash
303
mode: Unix file mode
304
path: Path within repository
305
"""
306
307
@property
308
def data_stream(self) -> "OStream":
309
"""Stream for reading blob data."""
310
311
@property
312
def mime_type(self) -> str:
313
"""MIME type of blob content."""
314
315
@property
316
def encoding(self) -> Optional[str]:
317
"""Text encoding of blob (if text)."""
318
319
def __str__(self) -> str:
320
"""Blob content as string."""
321
322
@property
323
def executable(self) -> bool:
324
"""True if blob has executable mode."""
325
```
326
327
### Tag Objects
328
329
Represent Git annotated tag objects with metadata and target object references.
330
331
```python { .api }
332
class TagObject(Object):
333
def __init__(
334
self,
335
repo: "Repo",
336
binsha: bytes,
337
object: Object = None,
338
tag: str = None,
339
tagger: "Actor" = None,
340
tagged_date: int = None,
341
tagger_tz_offset: int = None,
342
message: str = None
343
):
344
"""
345
Initialize tag object.
346
347
Args:
348
repo: Repository containing tag
349
binsha: Binary SHA-1 hash
350
object: Tagged object
351
tag: Tag name
352
tagger: Tagger information
353
tagged_date: Tag timestamp
354
tagger_tz_offset: Tagger timezone offset
355
message: Tag message
356
"""
357
358
@property
359
def object(self) -> Object:
360
"""Tagged object."""
361
362
@property
363
def tag(self) -> str:
364
"""Tag name."""
365
366
@property
367
def tagger(self) -> "Actor":
368
"""Tagger information."""
369
370
@property
371
def tagged_date(self) -> int:
372
"""Tag timestamp as seconds since epoch."""
373
374
@property
375
def tagged_datetime(self) -> datetime:
376
"""Tag timestamp as datetime object."""
377
378
@property
379
def tagger_tz_offset(self) -> int:
380
"""Tagger timezone offset in seconds."""
381
382
@property
383
def message(self) -> str:
384
"""Tag message."""
385
```
386
387
### Submodule Objects
388
389
Manage Git submodules with update and traversal capabilities.
390
391
```python { .api }
392
class Submodule(IndexObject):
393
def __init__(self, repo: "Repo", binsha: bytes, mode: int = None, path: str = None, name: str = None, parent_commit: "Commit" = None, url: str = None, branch_path: str = None):
394
"""
395
Initialize submodule.
396
397
Args:
398
repo: Parent repository
399
binsha: Submodule commit SHA
400
mode: File mode
401
path: Submodule path
402
name: Submodule name
403
parent_commit: Parent commit
404
url: Submodule URL
405
branch_path: Branch path
406
"""
407
408
def update(
409
self,
410
recursive: bool = False,
411
init: bool = True,
412
to_latest_revision: bool = False,
413
progress: "UpdateProgress" = None,
414
dry_run: bool = False,
415
force: bool = False,
416
keep_going: bool = False
417
) -> "Submodule":
418
"""
419
Update submodule.
420
421
Args:
422
recursive: Update recursively
423
init: Initialize if needed
424
to_latest_revision: Update to latest
425
progress: Progress reporter
426
dry_run: Don't make changes
427
force: Force update
428
keep_going: Continue on errors
429
430
Returns:
431
Updated submodule
432
"""
433
434
@property
435
def module(self) -> "Repo":
436
"""Submodule repository."""
437
438
@property
439
def url(self) -> str:
440
"""Submodule URL."""
441
442
class UpdateProgress:
443
"""Progress reporter for submodule updates."""
444
445
def update(
446
self,
447
op_code: int,
448
cur_count: Union[str, float],
449
max_count: Union[str, float] = None,
450
message: str = ""
451
) -> None:
452
"""
453
Update progress.
454
455
Args:
456
op_code: Operation code
457
cur_count: Current progress
458
max_count: Maximum progress
459
message: Progress message
460
"""
461
462
class RootModule(Submodule):
463
"""Virtual root of all submodules in repository for easier traversal."""
464
465
def __init__(self, repo: "Repo"): ...
466
467
def update(
468
self,
469
previous_commit: "Commit" = None,
470
recursive: bool = True,
471
force_remove: bool = False,
472
init: bool = True,
473
to_latest_revision: bool = False,
474
progress: "RootUpdateProgress" = None,
475
dry_run: bool = False,
476
force_reset: bool = False,
477
keep_going: bool = False
478
) -> "RootModule": ...
479
480
class RootUpdateProgress(UpdateProgress):
481
"""Extended progress reporter for root module operations with additional opcodes."""
482
483
# Additional operation codes beyond UpdateProgress
484
REMOVE: int
485
PATHCHANGE: int
486
BRANCHCHANGE: int
487
URLCHANGE: int
488
```
489
490
## Usage Examples
491
492
### Working with Commits
493
494
```python
495
from git import Repo
496
497
repo = Repo('/path/to/repo')
498
499
# Get latest commit
500
commit = repo.head.commit
501
502
# Access commit metadata
503
print(f"SHA: {commit.hexsha}")
504
print(f"Author: {commit.author.name} <{commit.author.email}>")
505
print(f"Date: {commit.authored_datetime}")
506
print(f"Message: {commit.message}")
507
508
# Access commit tree and parents
509
tree = commit.tree
510
parents = commit.parents
511
512
# Get commit statistics
513
stats = commit.stats
514
print(f"Files changed: {stats.total['files']}")
515
print(f"Insertions: {stats.total['insertions']}")
516
print(f"Deletions: {stats.total['deletions']}")
517
```
518
519
### Traversing Trees
520
521
```python
522
# Get tree from commit
523
tree = commit.tree
524
525
# Access tree items
526
for item in tree:
527
if item.type == 'tree':
528
print(f"Directory: {item.path}")
529
elif item.type == 'blob':
530
print(f"File: {item.path} ({item.size} bytes)")
531
532
# Recursive traversal
533
for item in tree.traverse():
534
print(f"{item.type}: {item.path}")
535
536
# Filter traversal
537
python_files = [item for item in tree.traverse()
538
if item.type == 'blob' and item.path.endswith('.py')]
539
```
540
541
### Working with Blobs
542
543
```python
544
# Get blob object
545
blob = tree['README.md']
546
547
# Access blob content
548
content = blob.data_stream.read().decode('utf-8')
549
print(content)
550
551
# Check if executable
552
if blob.executable:
553
print("File is executable")
554
555
# Get MIME type
556
print(f"MIME type: {blob.mime_type}")
557
```
558
559
### Working with Tags
560
561
```python
562
# Access annotated tag
563
tag = repo.tags['v1.0.0']
564
if hasattr(tag, 'tag'): # Annotated tag
565
tag_obj = tag.tag
566
print(f"Tag: {tag_obj.tag}")
567
print(f"Tagger: {tag_obj.tagger}")
568
print(f"Date: {tag_obj.tagged_datetime}")
569
print(f"Message: {tag_obj.message}")
570
print(f"Tagged object: {tag_obj.object.type}")
571
```
572
573
### Creating Objects
574
575
```python
576
from git import Actor
577
import time
578
579
# Create new commit
580
author = Actor("John Doe", "john@example.com")
581
committer = author
582
583
# Create tree modifier
584
from git.objects import TreeModifier
585
modifier = TreeModifier()
586
587
# Add files to tree
588
with open('new_file.txt', 'rb') as f:
589
blob_data = f.read()
590
591
# Create blob and add to tree
592
blob = repo.odb.store(IStream('blob', len(blob_data), BytesIO(blob_data)))
593
modifier.add(blob.binsha, 0o100644, 'new_file.txt')
594
595
# Write new tree
596
new_tree = modifier.write(repo)
597
598
# Create new commit
599
new_commit = Commit.create_from_tree(
600
repo,
601
new_tree,
602
message="Added new file",
603
parent_commits=[repo.head.commit],
604
author=author,
605
committer=committer
606
)
607
```