İçeriğe geç

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) ve apply(), stash'in dokunmadığı dosyalardaki commit edilmemiş değişikliklerin üzerine yazar (#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.

Kod
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).

Depolama ayrıntıları

Stash commit yapısı

Kod
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ı

Kod
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:

Kod
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ı

Kabuk
# 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)