
# Depolara Yazma

Pitmaster, git depolarını kanonik `git` ikilisiyle aynı ikili biçimleri kullanarak yazar. Nesneler gevşek nesne deposuna (zlib ile sıkıştırılmış) yazılır, dizin v2 biçiminde (girdiler için genişletilmiş işaretler gerektiğinde v3 biçiminde; mevcut bir dizin kendi sürümünü korur) yazılır ve başvurular gevşek dosyalar olarak yazılır. Yazılan veriler `git fsck --strict` ile doğrulanabilir.

## Depo başlatma

```php
use Pitmaster\Pitmaster;

$repo = Pitmaster::init('/path/to/new-project');
```

Şunları oluşturur:
- `.git/objects/` (boş nesne deposu)
- `.git/refs/heads/` ve `.git/refs/tags/` (boş başvuru dizinleri)
- `.git/HEAD`; içinde `ref: refs/heads/main` bulunur
- `.git/hooks/`, `.git/info/exclude` ve `.git/description`
- Varsayılan ayarlara sahip `.git/config`

Bir SHA-256 deposu oluşturmak için ikinci bağımsız değişken olarak `'sha256'` değerini iletin: `Pitmaster::init($path, 'sha256')`.

Varsayılan yapılandırma `core.logallrefupdates` değerini ayarlamaz; bu nedenle Pitmaster, oluşturduğu depoda bu anahtarı `true` olarak ayarlayana kadar reflog girdisi kaydetmez ([#8](https://github.com/inline0/pitmaster/issues/8)). `git init` tarafından oluşturulan depolarda bu değer zaten ayarlanmıştır.

## Dosyaları hazırlama

### add

```php
$repo->add('src/Feature.php');
$repo->add('src/Feature.php', 'tests/FeatureTest.php', 'README.md');
```

Her bağımsız değişken, çalışma ağacı köküne göreli bir dosya yoludur. Dizinler ve glob'lar genişletilmez; eksik bir dosya `RuntimeException` hatasına yol açar. Her dosya için Pitmaster:
1. Dosya içeriğini çalışma ağacından okur
2. Bir `Blob` nesnesi oluşturur ve karmasını hesaplar
3. Blob'u `.git/objects/` konumuna yazar (zlib ile sıkıştırılmış)
4. Bu yolun dizin girdisini yeni karma ve dosya meta verileriyle günceller

### remove

```php
$repo->remove('old-file.txt');
$repo->remove('-r', 'src');
$repo->remove('--cached', 'old-file.txt');
```

İzlenen yolları dizinden ve çalışma ağacından kaldırır. Yalnızca dizinden kaldırmak için `--cached`, izlenen dizinler için `-r` / `--recursive` kullanın.

### mv

```php
$repo->mv('old-name.php', 'new-name.php');
```

Dosyayı çalışma ağacında yeniden adlandırır, eski dizin girdisini kaldırır ve yenisini ekler.

## Commit oluşturma

```php
$commitId = $repo->commit('Fix null pointer bug');
echo $commitId->hex;
```

Commit süreci:

1. **Dizinden ağaç oluşturma**: dizin girdilerinin düz listesi bir ağaç hiyerarşisi hâlinde düzenlenir (dizinler ağaç nesnelerine, dosyalar blob başvurularına dönüşür). Her ağaç nesne deposuna yazılır.
2. **Üst öğeyi belirleme**: geçerli HEAD commit'i üst öğe olur. Kök commit'lerin (depodaki ilk commit) üst öğesi yoktur.
3. **Yazarı belirleme**: önce `PITMASTER_AUTHOR_*` ve `GIT_AUTHOR_*` ortam değişkenlerinden, sonra `PITMASTER_AUTHOR_NAME`/`PITMASTER_AUTHOR_EMAIL` sabitlerinden, ardından `.git/config` (`user.name`/`user.email`) ve son olarak `Pitmaster <pitmaster@localhost>` değerinden alınır. Commiter da aynı şekilde belirlenir.
4. **Commit nesnesini yazma**: commit içeriği (`tree`, `parent`, `author`, `committer`, mesaj) serileştirilir, karması hesaplanır ve yazılır.
5. **HEAD'i güncelleme**: HEAD'in işaret ettiği dal başvurusu yeni commit karmasına güncellenir.

Tanıtıcı `['hooks' => false]` ile açılmadıysa bu adımların öncesinde ve sonrasında kancalar çalışır (`pre-commit`, `prepare-commit-msg`, `commit-msg`, `post-commit`). Mesaj eksikse, ağaç HEAD'den farklı değilse veya dizinde birleştirilmemiş yollar varsa `commit()` hata verir.

### Özel yazar

```php
$author = 'Jane Smith <jane@example.com> 1700000000 +0000';
$commitId = $repo->commit('Add feature', $author);
```

## git fsck ile doğrulama

Pitmaster entegrasyon testleri, yazılan nesneleri `git fsck --strict` ile denetler; aynı doğrulamayı elle de yapabilirsiniz:

```bash
cd /path/to/repo
git fsck --strict
```

Pitmaster geçersiz bir nesne yazarsa `git fsck` hatayı hemen bildirir.

## Dalları yönetme

### Dal oluşturma

```php
// Branch from HEAD
$repo->createBranch('feature/new-thing');

// Branch from a specific commit
$repo->createBranch('hotfix', $repo->resolve('v1.0.0'));
```

Hedef commit karmasını içeren bir başvuru dosyasını `.git/refs/heads/<name>` konumunda oluşturur.

### Dalı silme

```php
$repo->deleteBranch('feature/old');
```

### Dalları değiştirme

```php
$repo->checkout('feature/login');
```

HEAD'i dala işaret eden sembolik bir başvuruya günceller, dizini dal ucunun ağacıyla eşleşecek şekilde sıfırlar ve çalışma ağacını günceller.

İki ağaç arasında farklılık gösteren yollardaki yerel değişiklikler, `RuntimeException` hatasıyla ödeme işlemini durdurur. İzlenen diğer tüm dosyalardaki commit edilmemiş değişiklikler dalın içeriğiyle değiştirilir; git bu değişiklikleri korurdu ([#2](https://github.com/inline0/pitmaster/issues/2)). Dal değiştirmeden önce bunları commit edin veya stash'e alın.

### Birleştirilmiş mi denetleme

```php
if ($repo->isBranchMerged('feature/done')) {
    $repo->deleteBranch('feature/done');
}
```

## Etiketleri yönetme

### Hafif etiket

```php
$repo->createLightweightTag('v1.0.0');                          // At HEAD
$repo->createLightweightTag('v0.9.0', $repo->resolve('HEAD~5'));
```

Hafif etiket, doğrudan bir commit'i gösteren bir başvurudan ibarettir.

### Açıklamalı etiket

```php
$tagId = $repo->createTag('v2.0.0', 'Release version 2.0.0');
```

Açıklamalı etiket, bir etiket nesnesi (etiketleyen, mesaj ve hedef bilgileriyle) oluşturur ve bu nesneyi gösteren bir başvuru ekler. Etiketleyen, commit yazarıyla aynı şekilde belirlenen geçerli committer kimliğidir.

### Özel etiketleyen

```php
$tagId = $repo->createTag(
    'v2.0.0',
    'Release version 2.0.0',
    $repo->resolve('HEAD'),
    'Jane Smith <jane@example.com> 1700000000 +0000',
);
```

## Başvuruları doğrudan güncelleme

```php
$repo->updateRef('refs/heads/main', $commitId);
$repo->updateRef('refs/tags/latest', $commitId);
```

## Nesneleri doğrudan yazma

Gelişmiş kullanım senaryolarında nesneleri üst düzey API sürecinden geçmeden yazabilirsiniz.

### Blob yazma

```php
use Pitmaster\Object\Blob;

$blob = Blob::fromContent('Hello, world!');
$id = $repo->writeObject($blob);
echo $id->hex;  // SHA-1 of "blob 13\0Hello, world!"
```

Bir SHA-256 deposunda algoritmayı iletin: `Blob::fromContent('Hello, world!', 'sha256')`.

### Ağaç yazma

```php
use Pitmaster\Object\Tree;
use Pitmaster\Object\TreeEntry;
use Pitmaster\Object\ObjectId;

$entries = [
    new TreeEntry('100644', 'README.md', $blobId),
    new TreeEntry('40000', 'src', $subtreeId),
];

$tree = Tree::fromEntries($entries);
$id = $repo->writeObject($tree);
```

`Tree::fromEntries()`, girdileri verilen sırayla, mod dizelerini de belirtildiği gibi yazar. Bunları git ağaç sırasıyla iletin (ada göre; dizinler, adları `/` ile bitiyormuş gibi karşılaştırılır) ve dizin modlarını `40000` olarak yazın: git, baştaki sıfır olmadan ağaç modlarını saklar ve `git fsck --strict`, `040000` değerini reddeder.

### Commit yazma

```php
use Pitmaster\Object\Commit;
use Pitmaster\Object\ObjectId;
use Pitmaster\Object\ObjectType;

$content = Commit::buildContent(
    tree: $treeId,
    parents: [$parentId],
    author: 'Name <email> 1700000000 +0000',
    committer: 'Name <email> 1700000000 +0000',
    message: "Commit message\n",
);

$commitId = ObjectId::compute(ObjectType::Commit, $content);
$commit = Commit::parse($content, $commitId);
$repo->writeObject($commit);
```

## Sıfırlama

```php
// Soft: move HEAD only
$repo->reset('HEAD~1', 'soft');

// Mixed: move HEAD + reset index (default)
$repo->reset('HEAD~1');

// Hard: move HEAD + reset index + reset working tree
$repo->reset('HEAD~3', 'hard');
```

## Geri yükleme

```php
// Restore a file from the index into the worktree
$repo->restore('src/File.php');

// Restore the index version from HEAD (the worktree is left alone)
$repo->restore('src/File.php', staged: true);

// Restore from a specific commit
$repo->restore('src/File.php', 'HEAD~1');

// Restore both index and worktree from a specific commit
$repo->restore('src/File.php', 'HEAD~1', staged: true, worktree: true);
```

## Cherry-pick ve geri alma

```php
// Apply a commit on the current branch
$newId = $repo->cherryPick('feature~1');

// Undo a commit
$revertId = $repo->revert('HEAD~2');
```

Her ikisi de `resolve()` tarafından kabul edilen herhangi bir revizyonu alır. Tam karmalar çalışır; kısaltılmış karmalar çalışmaz.
