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.
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
use Pitmaster\Stash\Stash;
$stash = new Stash(
$repo->objectDatabase(),
$repo->refDatabase(),
$repo->gitDir(),
$repo->workDir(),
);
Push (değişiklikleri kaydetme)
// 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:
- Geçerli HEAD commit'ini okur
- Geçerli dizinden (hazırlanmış durum) bir ağaç oluşturur
- Üst öğesi HEAD olan bir "dizin commit'i" oluşturur
- Geçerli çalışma dizininden (hazırlanmamış değişiklikler dâhil) bir ağaç oluşturur
- Stash commit'ini oluşturur (çalışma ağacı, üst öğeler = HEAD + dizin commit'i)
refs/stashöğesini stash commit'ini gösterecek şekilde günceller- Yığın için bir reflog girdisi ekler
- Ç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
$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)
$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
$stash->pop(1); // Pop stash@{1}
Apply (kaldırmadan geri yükleme)
$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
$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 iletisihash: stash commit özeti
Drop (uygulamadan kaldırma)
$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ı
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ı
# 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-indexyok); izlenmeyen dosyalar yalnızcapush($message, includeUntracked: true)üzerinden alınır --patchmodu 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)