İçeriğe geç

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:

Kod
project/
  .git/          (directory)
  src/
  README.md

Çalışma ağaçlarıyla ek checkout'lar oluşturabilirsiniz:

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

Kod
gitdir: ../../path/to/project/.git/worktrees/review

Çalışma ağacı oluşturma

PHP
$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:

  1. Dal mevcut değilse oluşturur (HEAD'den veya belirtilen $from commit'inden)
  2. Üstveri dizinini .git/worktrees/<name>/ konumunda oluşturur
  3. Çalışma ağacı dizininde .git dosyasını yazar
  4. HEAD, commondir ve gitdir üstveri dosyalarını yazar
  5. Dalın ağacını çalışma ağacı dizinine checkout eder
  6. Ç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.

PHP
$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

PHP
$wt = $repo->addWorktree('/tmp/hotfix', 'hotfix/urgent', $repo->resolve('v1.0.0'));

Çalışma ağaçlarını listeleme

PHP
$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

PHP
$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:

  1. Çalışma ağacının kilitli olup olmadığını denetler ($force true değilse başarısız olur)
  2. Çalışma ağacı dizininden .git dosyasını kaldırır
  3. Ü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:

PHP
$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_HEAD ve 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

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

PHP
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

PHP
// 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

PHP
// 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

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

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