Worktree'ler
Git worktree'ler, birden fazla çalışma dizininin tek bir depoyu paylaşmasını sağlar. Her worktree'nin kendi teslim alımı (HEAD, dizin, çalışma dosyaları) vardır; ancak nesne deposunu, yapılandırmayı ve paketlenmiş refs'leri ana depoyla paylaşır. Pitmaster bağlantılı worktree'ler oluşturabilir, listeleyebilir, kilitleyebilir ve kaldırabilir; ayrıca bunları depo olarak açabilir. Budama, taşıma ve worktree onarma işlemleri uygulanmamıştır.
Kavramlar
Normal bir git deposunun tek bir çalışma ağacı vardır:
project/
.git/ (directory)
src/
README.md
Çalışma ağaçlarıyla ek checkout'lar oluşturabilirsiniz:
project/ (main worktree)
.git/ (the actual git directory)
worktrees/
review/ (metadata for linked worktree)
HEAD
commondir
gitdir
/tmp/review/ (linked worktree)
.git (file, not directory)
src/
README.md
Bağlı çalışma ağacının .git dosyası, çalışma ağacına göreli bir yol içeren (dizin olmayan) bir dosyadır:
gitdir: ../../path/to/project/.git/worktrees/review
Çalışma ağacı oluşturma
$repo = Pitmaster::open('/path/to/project');
// Create a linked worktree on a new branch
$wt = $repo->addWorktree('/tmp/review', 'feature/review');
echo $wt->path; // '/tmp/review'
echo $wt->branch; // 'feature/review'
echo $wt->gitDir; // '/path/to/project/.git/worktrees/review'
var_dump($wt->isMain); // bool(false)
var_dump($wt->isDetached); // bool(false)
addWorktree() şunları yapar:
- Dal mevcut değilse oluşturur (HEAD'den veya belirtilen
$fromcommit'inden) - Üstveri dizinini
.git/worktrees/<name>/konumunda oluşturur - Çalışma ağacı dizininde
.gitdosyasını yazar HEAD,commondirvegitdirüstveri dosyalarını yazar- Dalın ağacını çalışma ağacı dizinine checkout eder
- Çalışma ağacı için indeksi yazar
Dal zaten varsa $from yok sayılır. git'den farklı olarak addWorktree(), başka bir çalışma ağacında zaten checkout edilmiş bir dalı reddetmez ve post-checkout hook'unu çalıştırmaz.
Açık bir üstveri adıyla
Birden fazla bağlı çalışma ağacı aynı checkout temel adını paylaşabiliyorsa isteğe bağlı name bağımsız değişkenini kullanın.
$wt = $repo->addWorktree(
'/tmp/sandboxes/app',
'feature/review',
name: 'sandbox-app',
);
Bu üstveri adı, basename($path) yerine .git/worktrees/<name>/ altında kullanılır.
Belirli bir commit'ten
$wt = $repo->addWorktree('/tmp/hotfix', 'hotfix/urgent', $repo->resolve('v1.0.0'));
Çalışma ağaçlarını listeleme
$worktrees = $repo->worktrees();
foreach ($worktrees as $wt) {
$type = $wt->isMain ? 'main' : 'linked';
$branch = $wt->branch ?? 'detached';
$locked = $wt->isLocked ? ' [locked]' : '';
echo "{$wt->path} ({$type}) [{$branch}]{$locked}\n";
}
Liste her zaman önce ana çalışma ağacını, ardından bağlı çalışma ağaçlarını içerir. Ana depo için bir tanıtıcıda worktrees() çağırın: bağlı bir çalışma ağacı tanıtıcısında ana girdi, şu anda bağlı çalışma ağacının kendi yolunu bildirir (#14).
Çalışma ağacını kaldırma
$repo->removeWorktree('review'); // by metadata name
$repo->removeWorktree('/tmp/review'); // or by worktree path
// Force remove (even if locked)
$repo->removeWorktree('review', force: true);
Bir çalışma ağacını kaldırma:
- Çalışma ağacının kilitli olup olmadığını denetler (
$forcetrue değilse başarısız olur) - Çalışma ağacı dizininden
.gitdosyasını kaldırır - Üstveri dizinini
.git/worktrees/konumundan kaldırır
Çalışma ağacı dosyaları otomatik olarak silinmez. Dal varlığını sürdürür.
Bağlı çalışma ağacını açma
Bağlı bir çalışma ağacını herhangi bir depo gibi açabilirsiniz:
$repo = Pitmaster::open('/tmp/review');
// Pitmaster detects the .git file and follows the gitdir reference
echo $repo->isLinkedWorktree(); // true
echo $repo->gitDir(); // '/path/to/project/.git/worktrees/review'
echo $repo->commonGitDir(); // '/path/to/project/.git'
echo $repo->workDir(); // '/tmp/review'
Depo işlemleri yolları şu şekilde çözümler:
- Nesneler: ortak git dizininden okunur ve bu dizine yazılır (
project/.git/objects/) - Yapılandırma: ortak git dizininden okunur (
project/.git/config) - Packed-refs: ortak git dizininden okunur
- HEAD: çalışma ağacı başınadır (her çalışma ağacı kendi dalını izler); ayrıca
ORIG_HEAD,MERGE_HEADve diğer işlem ref'leri de böyledir - İndeks: çalışma ağacı başınadır (her çalışma ağacının kendi hazırlama alanı vardır)
- Gevşek ref'ler: dallar ve etiketler ortak dizinde paylaşılır (
project/.git/refs/) - Hook'lar: çalışma ağacına özel git dizininden okunur; bu nedenle paylaşılan hook'lar çalıştırılmaz (#12)
Stash henüz bağlı çalışma ağaçlarını desteklemiyor: kimliği çalışma ağacına özel yapılandırma içermeyen dizinden okuyor ve reflog'unu oraya yazıyor (#14).
Worktree değer nesnesi
use Pitmaster\Worktree\Worktree;
$wt->name; // Metadata name (null for the main worktree)
$wt->path; // Working directory path
$wt->gitDir; // Per-worktree git dir
$wt->branch; // Branch name (null if detached)
$wt->head; // ObjectId of HEAD commit
$wt->isMain; // true for the main worktree
$wt->isDetached; // true if HEAD is detached
$wt->isLocked; // true if worktree is locked
$wt->lockReason; // Lock reason, or null when there is none (an empty reason is also null)
WorktreeManager
Düşük seviyeli çalışma ağacı yönetimi içindir. WorktreeManager::add() yalnızca üstveriyi ve .git dosyasını yazar; dal oluşturmaz, dosyaları checkout etmez veya indeks yazmaz. Kullanılabilir bir checkout için $repo->addWorktree() kullanın. Dal önceden var olmalıdır (veya HEAD'i ayıran refs/tags/v1.0.0 gibi tam bir ref adı olmalıdır).
use Pitmaster\Worktree\WorktreeManager;
$manager = new WorktreeManager($repo->commonGitDir(), $mainWorkDir);
// List
$worktrees = $manager->list();
// Add
$wt = $manager->add('/tmp/review', 'feature/review');
$wt = $manager->add('/tmp/review', 'feature/review', 'review-app');
// Remove
$manager->remove('review');
$manager->remove('review', force: true);
// Lock/unlock (metadata name only)
$manager->lock('review', 'Do not delete, code review in progress');
$manager->unlock('review');
Çalışma ağaçlarını kilitleme
// Lock (prevents removal)
$manager->lock('review', 'Code review in progress');
// Attempt to remove locked worktree
try {
$manager->remove('review');
} catch (\RuntimeException $e) {
// "Worktree is locked: review (Code review in progress)"
}
// Force remove ignores the lock
$manager->remove('review', force: true);
// Unlock
$manager->unlock('review');
Kilit, .git/worktrees/<name>/locked konumunda bir dosya olarak saklanır. Dosyanın içeriği kilit nedenidir (boş olabilir).
Çalışma ağaçlarını algılama
// Check if a path is a linked worktree
if (Pitmaster::isWorktree('/tmp/review')) {
echo "This is a linked worktree\n";
}
// Resolve the common git dir from any path
$common = Pitmaster::commonGitDir('/tmp/review');
// '/path/to/project/.git'
// Resolve a .git file to the actual git directory
$gitDir = WorktreeManager::resolveGitFile('/tmp/review');
// '/path/to/project/.git/worktrees/review'
Dosya düzeni
Bağlı çalışma ağaçları için ana çalışma ağacı üstverisi
.git/worktrees/<name>/
HEAD Per-worktree HEAD (symbolic ref or detached hash)
commondir Relative path to the shared git dir ("../..")
gitdir Path back to the worktree's .git file, as passed to addWorktree()
locked Present if locked (content = reason)
index Per-worktree index/staging area
Bağlı çalışma ağacının .git dosyası
gitdir: <relative path to>/project/.git/worktrees/<name>
Kaynak paylaşımı
| Kaynak | Konum | Paylaşılıyor mu? |
|---|---|---|
| Nesneler | $commonDir/objects/ |
Evet |
| Yapılandırma | $commonDir/config |
Evet |
| Packed-refs | $commonDir/packed-refs |
Evet |
| Hook'lar | $gitDir/hooks/ |
Hayır: Pitmaster bağlı çalışma ağaçlarında paylaşılan hook'ları çalıştırmaz |
| HEAD | $gitDir/HEAD |
Hayır (çalışma ağacı başına) |
| İndeks | $gitDir/index |
Hayır (çalışma ağacı başına) |
| Gevşek ref'ler | $commonDir/refs/ |
Evet (HEAD ve MERGE_HEAD gibi işlem ref'leri çalışma ağacı başınadır) |