
# Stash

Git stash, başka bir göreve geçip daha sonra geri yükleyebilmeniz için çalışma dizini ve dizin değişikliklerini kaydeder. Pitmaster, stash'i git depolama düzeninde `refs/stash` ve reflog kullanarak uygular. `Repository` üzerinde stash yöntemi yoktur; aşağıdaki `Stash` sınıfını kullanın.

Bilinen iki sorun vardır: birden fazla girdi varsa `drop()` (dolayısıyla `pop()`) girdiyi listede bırakır ([#10](https://github.com/inline0/pitmaster/issues/10)) ve `apply()`, stash'in dokunmadığı dosyalardaki commit edilmemiş değişikliklerin üzerine yazar ([#11](https://github.com/inline0/pitmaster/issues/11)). Stash'leri temiz bir çalışma ağacına uygulayın.

## Stash nasıl çalışır

Her stash girdisi iki üst öğesi olan bir commit'tir:
- **Üst öğe 0**: stash oluşturulduğu andaki HEAD commit'i (temel durum)
- **Üst öğe 1**: dizin durumunu (hazırlanmış değişiklikler) içeren bir commit

Stash commit'inin kendi ağacı, çalışma ağacının durumunu (hazırlanmamış değişiklikler dâhil) kaydeder.

Stash "yığını", `refs/stash` öğesinin reflog'udur. En yeni stash, doğrudan `refs/stash` öğesidir. Daha eski girdiler reflog girdileridir: `stash@{0}`, `stash@{1}` vb.

```
refs/stash -> stash commit (worktree state)
                parent[0] -> HEAD at time of stash
                parent[1] -> index state commit
                               parent[0] -> HEAD at time of stash
```

## Stash nesnesi oluşturma

```php
use Pitmaster\Stash\Stash;

$stash = new Stash(
    $repo->objectDatabase(),
    $repo->refDatabase(),
    $repo->gitDir(),
    $repo->workDir(),
);
```

## Push (değişiklikleri kaydetme)

```php
// public function push(string $message = '', bool $includeUntracked = false): ObjectId
$stashId = $stash->push('Work in progress on login');
echo "Saved: {$stashId->hex}\n";

// Also stash untracked files
$stashId = $stash->push('With new files', includeUntracked: true);
```

Push işlemi şunları yapar:
1. Geçerli HEAD commit'ini okur
2. Geçerli dizinden (hazırlanmış durum) bir ağaç oluşturur
3. Üst öğesi HEAD olan bir "dizin commit'i" oluşturur
4. Geçerli çalışma dizininden (hazırlanmamış değişiklikler dâhil) bir ağaç oluşturur
5. Stash commit'ini oluşturur (çalışma ağacı, üst öğeler = HEAD + dizin commit'i)
6. `refs/stash` öğesini stash commit'ini gösterecek şekilde günceller
7. Yığın için bir reflog girdisi ekler
8. Çalışma ağacını ve dizini HEAD durumuna sıfırlar

Push sonrasında izlenen dosyalar HEAD ile eşleşir. İzlenmeyen dosyalar `includeUntracked` ayarlanmadıkça kalır; ayarlanırsa kaldırılır ve stash commit'inin kendi ağacında saklanır (git bunları üçüncü bir üst öğede saklar; bu nedenle git bunları izlenen değişiklikler olarak görür). Hiçbir şey değişmemiş olsa bile `push()` bir girdi oluşturur; bu durumda git "Kaydedilecek yerel değişiklik yok" bildirimini verir.

### Varsayılan iletiyle

```php
$stashId = $stash->push();
// Message: "WIP on <branch>: <short hash> <HEAD subject>"
// With a message: "On <branch>: <message>"
```

Ayrılmış HEAD durumunda `<branch>`, `HEAD` olur.

## Pop (uygulama ve kaldırma)

```php
$stash->pop();
```

En üstteki stash girdisini çalışma dizinine uygular ve yığından kaldırır. `apply()` ve ardından `drop()` işlemlerine eşdeğerdir.

### Belirli bir girdiyi pop etme

```php
$stash->pop(1);  // Pop stash@{1}
```

## Apply (kaldırmadan geri yükleme)

```php
$stash->apply();      // Apply stash@{0}
$stash->apply(2);     // Apply stash@{2}
```

Apply, stash'i geçerli HEAD'e dosya dosya birleştirir (stash tabanı, geçerli HEAD, stash ağacı). Stash girdisi yığında kalır ve dizine dokunulmaz. Çakışmalar dosyalara `Updated upstream` ve `Stashed changes` etiketli işaretçiler bırakır ve `Pitmaster\Exceptions\MergeConflictException` hatasını fırlatır; `pop()` daha sonra girdiyi korur. Apply önce yerel değişiklikleri denetlemez (yukarıdaki nota bakın).

## Girdileri listeleme

```php
$entries = $stash->listEntries();

foreach ($entries as $entry) {
    echo "stash@{{$entry['index']}}: {$entry['message']}\n";
    // stash@{0}: On main: Work in progress on login
    // stash@{1}: WIP on main: f707601 Add login form
}
```

Her girdi şunları içerir:
- `index`: stash konumu (0 = en yeni)
- `message`: stash iletisi
- `hash`: stash commit özeti

## Drop (uygulamadan kaldırma)

```php
$stash->drop();       // Drop stash@{0}
$stash->drop(1);      // Drop stash@{1}
```

Tek girdi varsa bırakıldığında `refs/stash` ve reflog'u kaldırılır. Birden fazla girdi olduğunda `drop()` şu anda yalnızca `refs/stash` öğesini taşır ve reflog'u değiştirmez; bu nedenle girdi `listEntries()` içinde kalır ([#10](https://github.com/inline0/pitmaster/issues/10)).

## Depolama ayrıntıları

### Stash commit yapısı

```
commit <hash>
tree <worktree-tree-hash>
parent <HEAD-hash>
parent <index-commit-hash>
author <current identity>
committer <current identity>

<stash message>
```

### Dizin commit yapısı

```
commit <hash>
tree <index-tree-hash>
parent <HEAD-hash>
author <current identity>
committer <current identity>

index on <branch>: <short hash> <HEAD subject>
```

Kimlik önce `GIT_COMMITTER_NAME`, sonra `GIT_AUTHOR_NAME`, ardından depo yapılandırmasında `user.name` ve son olarak `Pitmaster` öğelerinden alınır (e-posta için de aynı sıra izlenir ve `pitmaster@example.invalid` ile biter). Tarih önce `GIT_COMMITTER_DATE`, sonra `GIT_AUTHOR_DATE`, ardından geçerli saatten alınır. Commit'lerden farklı olarak stash, `PITMASTER_*` sabitlerini okumaz.

### Reflog depolaması

Stash girdileri `.git/logs/refs/stash` içinde saklanır:

```
0000000000000000000000000000000000000000 abc123... Name <email> 1700000000 +0000	WIP on main: f707601 Add login form
abc123... def456... Name <email> 1700000001 +0000	On main: Work in progress on login
```

Reflog kronolojik sırayla okunur. Stash listesi bunu tersine çevirir (en yeni başta). Stash reflog'u, `core.logallrefupdates` değerinden bağımsız olarak yazılır.

## CLI kullanımı

```bash
# Save current changes
./vendor/bin/pitmaster stash
./vendor/bin/pitmaster stash push
./vendor/bin/pitmaster stash push "Work in progress on login"

# Apply and remove top entry
./vendor/bin/pitmaster stash pop

# Apply without removing
./vendor/bin/pitmaster stash apply

# List all entries
./vendor/bin/pitmaster stash list

# Remove top entry without applying
./vendor/bin/pitmaster stash drop
```

İleti, `push` (veya `save`) sonrasındaki bağımsız değişkendir; `-m` desteklenmez. `pop`, `apply` ve `drop` her zaman `stash@{0}` üzerinde çalışır; CLI öğesinin `--include-untracked` özelliği yoktur.

## Sınırlamalar

- Yalnızca tüm çalışma dizinini stash etme (`--keep-index` yok); izlenmeyen dosyalar yalnızca `push($message, includeUntracked: true)` üzerinden alınır
- `--patch` modu yoktur (etkileşimli parça seçimi)
- Pop/apply çalışma ağacının durumunu geri yükler; dizini geri yüklemez. Hazırlanmış düzenlemeler hazırlanmamış düzenlemeler olarak, yeni hazırlanmış dosyalar ise izlenmeyen dosyalar olarak geri gelir
- `stash@{n}`, `Repository::resolve()` tarafından kabul edilmez
- Bağlantılı bir worktree'deki stash yanlış yapılandırma ve reflog konumunu kullanır ([#14](https://github.com/inline0/pitmaster/issues/14))
