
# Paket Dosyaları

Paket dosyaları, git'in verimli depolama ve aktarım mekanizmasıdır. Her nesneyi ayrı bir zlib sıkıştırmalı dosyada saklamak yerine, paket dosyaları birçok nesneyi isteğe bağlı delta sıkıştırmasıyla tek bir dosyada birleştirir. Klonlanan depoların neredeyse tamamı paket dosyalarını kullanır.

## Paket dosyası yapısı

Bir paket dosyası (`.git/objects/pack/pack-{hash}.pack`) şunları içerir:

```
Header:   PACK (4 bytes) + version (4 bytes, big-endian) + count (4 bytes, big-endian)
Entries:  [type+size varint] [delta-base] [zlib-compressed data] ...
Trailer:  checksum of the pack (20 bytes SHA-1, 32 bytes SHA-256)
```

### Nesne türü kodlaması

Her girdi, tür ve boyut bilgilerinin iç içe kodlandığı değişken uzunluklu bir tamsayıyla başlar:

```
First byte: 1TTTSSSS
  TTT  = object type (1-4 for base objects, 6 for OFS_DELTA, 7 for REF_DELTA)
  SSSS = first 4 bits of uncompressed size
  MSB  = 1 means more size bytes follow
```

Tür değerleri:
| Değer | Tür |
|-------|------|
| 1 | Commit |
| 2 | Tree |
| 3 | Blob |
| 4 | Tag |
| 6 | OFS_DELTA (ofset tabanlı delta) |
| 7 | REF_DELTA (özet tabanlı delta) |

## Paket dosyalarını okuma

```php
use Pitmaster\Pack\PackFile;

$pack = PackFile::open(
    '/path/to/.git/objects/pack/pack-abc123.pack',
    '/path/to/.git/objects/pack/pack-abc123.idx',
);

$pack->has($hex);               // Is the object in this pack?
$object = $pack->read($hex);    // Resolved GitObject, or null
$object = $pack->readAtOffset($offset);
$hashes = $pack->allHashes();
```

`PackFile` sınıfı:
1. `PACK` başlığını ve sürüm numarasını doğrular
2. `.idx` dosyası üzerinden ofseti bulur ve girdinin tür/boyut değişken uzunluklu tamsayısını ayrıştırır
3. zlib ile sıkıştırılmış veriyi açar
4. Taban nesneleri için içeriği doğrudan döndürür
5. Delta nesneleri için tabanı çözümler (zincirleri izleyerek) ve deltayı uygular; çözümlenmiş nesneleri önbelleğe alır

## Paket dizin dosyaları

Her `.pack` dosyasının hızlı aramalar için karşılık gelen bir `.idx` dosyası vardır. Dizin olmadan bir nesneyi bulmak için tüm paketi taramak gerekir.

### v2 dizin biçimi

```
Magic:    FF 74 4F 63 (identifies v2)
Version:  00 00 00 02
Fanout:   256 x 4-byte big-endian counts (cumulative)
Names:    N x 20-byte SHA-1 hashes, sorted (32 bytes for SHA-256)
CRC32s:   N x 4-byte CRC32 checksums
Offsets:  N x 4-byte pack offsets (MSB=1 means large offset table)
Large:    M x 8-byte offsets (for packs > 2GB)
Checksums: pack checksum + index checksum (20 bytes each for SHA-1)
```

```php
use Pitmaster\Pack\PackIndex;

$index = PackIndex::open('/path/to/pack-abc123.idx');

// Look up an object
$offset = $index->findOffset($hex);  // Pack file offset, or null

// List all objects in the pack
$hashes = $index->allHashes();
$count = $index->objectCount();
```

Fanout tablosu, O(log n) ikili arama yapılmasını sağlar: 256 girdileri, olası her ilk baytla başlayan kaç özet bulunduğunu belirtir.

### v1 dizin biçimi

CRC32 sağlama toplamları olmayan eski biçim. Pitmaster her iki biçimi de destekler: `PackIndex::open()`, v2 sihirli değeri yoksa bir v1 dosyasını okur; böylece aynı kod her ikisiyle de çalışır.

## Delta çözümleme

Delta biçimli nesneler, içeriğin tamamını saklamak yerine içeriği bir taban nesneden yeniden oluşturmak için gereken talimatları saklar. Bu, benzer nesnelerde (e.g, aynı dosyanın ardışık sürümlerinde) önemli ölçüde sıkıştırma sağlar.

### Delta türleri

**OFS_DELTA** (tür 6): taban nesne, aynı paket dosyasındaki negatif bir ofsetle tanımlanır. Taban nesnenin özetini bilmeyi gerektirmediği için daha yaygındır.

**REF_DELTA** (tür 7): temel nesne, hash değeriyle tanımlanır. git içinde temel nesne paketin dışında bulunabilir (ince paketler). Pitmaster, REF_DELTA temel nesnelerini yalnızca aynı paketin içinde arar; bu nedenle ince paketler desteklenmez ([#16](https://github.com/inline0/pitmaster/issues/16)).

### Delta talimatları

Delta içeriği, kopyalama ve ekleme talimatları dizisidir:

```
Copy:   1XXXXXXX [offset bytes] [size bytes]   (copy from base)
Insert: 0LLLLLLL <L bytes of literal data>       (insert new data)
```

Kopyalama talimatları: 7 X biti, hangi ofset ve boyut baytlarının bulunduğunu gösterir. Ofset en fazla 4 bayt, boyut en fazla 3 bayttır. Boyut sıfırsa 0x10000 (65536) bayt anlamına gelir.

Ekleme talimatları: 7 L biti, değişmez veri uzunluğunu (1-127 bayt) verir. L=0 ayrılmıştır/geçersizdir.

### DeltaApplier

```php
use Pitmaster\Pack\DeltaApplier;

$result = DeltaApplier::apply($baseContent, $deltaInstructions);
```

`DeltaApplier`:
1. Delta başlığından beklenen taban boyutunu ve sonuç boyutunu okur (LEB128 kodlu)
2. Talimatlar arasında ilerler:
   - Kopyala: ofseti ve boyutu çıkarır, taban içeriğinden baytları kopyalar
   - Ekle: uzunluğu çıkarır, değişmez baytları delta verisinden kopyalar
3. Sonuç boyutunun beklenen boyutla eşleştiğini doğrular

### Delta zincirleri

Delta biçimli bir nesnenin tabanı da delta biçimli olabilir. `PackFile::read()` ve `readAtOffset()` zinciri izler:

1. Girdiyi oku. Taban türündeyse (commit, tree, blob, tag) döndür.
2. OFS_DELTA ise taban ofsetini hesapla (geçerli ofset eksi kodlanmış negatif ofset), taban girdisini oku ve özyinelemeli olarak devam et.
3. REF_DELTA ise aynı paketin dizininde tabanı özetiyle ara ve özyinelemeli olarak devam et.
4. Çözümlenmiş tabana delta talimatlarını uygula.
5. Zincirlerin denetimsiz büyümesini önlemek için `PITMASTER_MAX_DELTA_CHAIN` sınırını uygula (varsayılan 50).

```php
// Configure max chain depth (integer)
define('PITMASTER_MAX_DELTA_CHAIN', 50);

// Read the effective limit
$max = \Pitmaster\Pack\DeltaResolver::maxChainDepth();
```

## PackWriter

Pitmaster, ağ işlemleri (push) için paket dosyaları yazabilir.

```php
use Pitmaster\Pack\PackWriter;
use Pitmaster\Pack\PackIndexer;

$packData = PackWriter::encode($objects);           // GitObject[] to pack bytes
$paths = PackWriter::write($packDir, $objects);     // ['packPath' => ..., 'idxPath' => ..., 'hash' => ...]

$idxPath = PackIndexer::writeIndex($packPath);      // Build the .idx for a received pack
```

`PackWriter`:
1. Pakete eklenecek nesneleri toplar
2. Her nesneyi tür/boyut değişken uzunluklu başlığıyla serileştirir
3. İçeriği zlib ile sıkıştırır
4. PACK başlığını, girdileri ve SHA-1 son ekini yazar

Şu anda yalnızca taban nesnelerini yazar (delta sıkıştırması yoktur). Delta sıkıştırması daha sonra eklenebilecek bir iyileştirmedir; depolama verimliliği için yeniden paketleme işini `git gc`'e bırakın.

## PackEnumerator

Bir paketteki tüm nesneleri dizin sırasıyla dolaşın:

```php
use Pitmaster\Pack\PackEnumerator;

$enumerator = new PackEnumerator($packFile); // a PackFile opened with its .idx

foreach ($enumerator->enumerate() as $object) {
    echo "{$object->type->value} {$object->id->hex} {$object->size()}\n";
}
```

Her öğe çözümlenmiş bir `GitObject`'dir.

## MultiPackIndex

Çok sayıda paket dosyası olan depolarda çoklu paket dizini (MIDX), tüm paketlerde tek bir arama olanağı sağlar.

```php
use Pitmaster\Pack\MultiPackIndex;
```

MIDX dosyası (`.git/objects/pack/multi-pack-index`) şunları içerir:
- Bir fanout tablosu (paket dizini v2 gibi)
- Tüm paketler genelinde sıralanmış nesne kimlikleri
- Paket dosyası adları ve nesne başına paket atamaları
- Tek tek paket dosyalarındaki ofsetler

`MultiPackIndex::open($path)`, bir MIDX dosyasını ayrıştırır ve `findObject($hex)` ile `packNames()` sunar. Depodaki nesne aramaları bunu kullanmaz: nesne veritabanı her zaman tek tek `.idx` dosyalarını okur.

## CommitGraph

Commit grafiği dosyası, commit geçmişinde gezinmeyi ve birleştirme tabanı hesaplamasını hızlandırır.

```php
use Pitmaster\Pack\CommitGraph;
```

`.git/objects/info/commit-graph` konumunda bulunur ve şunları içerir:
- Sıralanmış commit OID'leri
- Üst öğe bilgileri (dizinlenmiştir; nesnelerin okunması gerekmez)
- Daha hızlı erişilebilirlik sorguları için nesil numaraları
- Commit zaman damgaları

Mevcut olduğunda, `Repository::merge()`, `mergeBase()` ve `isBranchMerged()` arkasındaki birleştirme tabanı hesaplaması ile push hızlı ileri kontrolü, tek tek commit nesnelerini okumak yerine üst öğe bağlantılarını commit grafiğinden okur. `CommitWalker` (log) bunu kullanmaz.

## Değişken uzunluklu tamsayılar

Paket dosyaları birden fazla değişken uzunluklu tamsayı kodlaması kullanır:

### Git varint (tür/boyut başlıkları)

En anlamlı bitin daha fazla bayt olduğunu belirttiği MSB-devam kodlaması:

```php
use Pitmaster\Encoding\VarInt;

$size = VarInt::decodePackSize($reader, $initialBits);  // continues the size from the first header byte
$offset = VarInt::decodeOfsOffset($reader);             // OFS_DELTA base distance
$header = VarInt::encodePackSize($type, $size);
```

### LEB128 (delta başlıkları)

Taban boyutu ve sonuç boyutu için delta talimatı başlıklarında kullanılır:

```php
use Pitmaster\Encoding\Leb128;

$value = Leb128::decodeUnsigned($reader);   // a BinaryReader
$bytes = Leb128::encodeUnsigned($value);
```

### BinaryReader

Konum takibi olan düşük seviyeli bayt akışı:

```php
use Pitmaster\Encoding\BinaryReader;

$reader = new BinaryReader($data);
$byte = $reader->readByte();
$int = $reader->readUint32();   // big-endian
$bytes = $reader->read(20);
$hash = $reader->readHash(20);
$reader->position();  // Current offset
$reader->seek(0);
```
