Pereiti prie turinio

Darbiniai medžiai

Git darbiniai medžiai leidžia keliems darbiniams katalogams naudoti tą pačią saugyklą. Kiekvienas darbinis medis turi atskirą išsiėmimo kopiją (HEAD, indeksą, darbinius failus), bet bendrina objektų saugyklą, konfigūraciją ir packed-refs su pagrindine saugykla. Pitmaster gali kurti, išvardyti, užrakinti ir pašalinti susietus darbinius medžius bei atidaryti juos kaip saugyklas. Darbinių medžių valymas, perkėlimas ir taisymas nepalaikomi.

Sąvokos

Įprasta git saugykla turi vieną darbinį medį:

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

Naudodami darbinius medžius galite turėti papildomų išsiėmimo kopijų:

Kodas
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

Susieto darbinio medžio .git yra failas (ne katalogas), kuriame nurodytas santykinis kelias į darbinį medį:

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

Darbinio medžio kūrimas

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() atlieka šiuos veiksmus:

  1. Sukuria šaką, jei jos nėra (iš HEAD arba nurodyto $from pakeitimo)
  2. Sukuria metaduomenų katalogą adresu .git/worktrees/<name>/
  3. Darbinio medžio kataloge įrašo failą .git
  4. Įrašo metaduomenų failus HEAD, commondir ir gitdir
  5. Išsiima šakos medį į darbinio medžio katalogą
  6. Įrašo darbinio medžio indeksą

Jei šaka jau yra, $from ignoruojamas. Kitaip nei git, addWorktree() neatsisako naudoti šakos, kuri jau išsiimta kitame darbiniame medyje, ir nevykdo post-checkout kablio.

Su aiškiai nurodytu metaduomenų pavadinimu

Naudokite pasirenkamą argumentą name, jei keli susieti darbiniai medžiai gali turėti tą patį išsiėmimo katalogo pavadinimą.

PHP
$wt = $repo->addWorktree(
    '/tmp/sandboxes/app',
    'feature/review',
    name: 'sandbox-app',
);

Šis metaduomenų pavadinimas naudojamas .git/worktrees/<name>/ vietoje basename($path).

Iš konkretaus pakeitimo

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

Darbinių medžių sąrašas

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";
}

Sąraše visada pirmiausia pateikiamas pagrindinis darbinis medis, po jo – susieti darbiniai medžiai. Pagrindinei saugyklai skirtame objekte iškvieskite worktrees(): susieto darbinio medžio objekte pagrindinio įrašo kelias šiuo metu nurodo paties susieto darbinio medžio kelią (#14).

Darbinio medžio šalinimas

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

Šalinant darbinį medį:

  1. Tikrinama, ar darbinis medis užrakintas (šalinama tik jei $force yra true)
  2. Iš darbinio medžio katalogo pašalinamas failas .git
  3. Iš .git/worktrees/ pašalinamas metaduomenų katalogas

Darbinio medžio failai automatiškai neištrinami. Šaka išlieka.

Susieto darbinio medžio atidarymas

Susietą darbinį medį galite atidaryti kaip bet kurią kitą saugyklą:

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'

Saugyklos operacijų keliai nustatomi taip:

  • Objektai: skaitomi iš bendro git katalogo ir į jį įrašomi (project/.git/objects/)
  • Konfigūracija: skaitoma iš bendro git katalogo (project/.git/config)
  • Packed-refs: skaitomas iš bendro git katalogo
  • HEAD: atskiras kiekvienam darbiniam medžiui (kiekvienas seka savo šaką), taip pat ORIG_HEAD, MERGE_HEAD ir kitos operacijų nuorodos
  • Indeksas: atskiras kiekvienam darbiniam medžiui (kiekvienas turi savo parengimo sritį)
  • Laisvosios nuorodos: šakos ir žymos bendrinamos bendrame kataloge (project/.git/refs/)
  • Kablio scenarijai: skaitomi iš kiekvieno darbinio medžio git katalogo, todėl bendrinami kabliai nevykdomi (#12)

Stash kol kas nepalaiko susietų darbinių medžių: jis skaito tapatybę iš darbinio medžio katalogo, kuriame nėra konfigūracijos, ir ten įrašo savo reflog (#14).

Darbinio medžio reikšmės objektas

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

Žemo lygio darbinių medžių valdymui. WorktreeManager::add() įrašo tik metaduomenis ir failą .git: jis nesukuria šakos, neišsiima failų ir neįrašo indekso. Norėdami gauti paruoštą naudoti išsiėmimo kopiją, naudokite $repo->addWorktree(). Šaka jau turi egzistuoti (arba būti pilnas nuorodos pavadinimas, pvz., refs/tags/v1.0.0, kuris atjungia HEAD).

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');

Darbinių medžių užrakinimas

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');

Užraktas saugomas kaip failas adresu .git/worktrees/<name>/locked. Failo turinys yra užrakto priežastis (gali būti tuščias).

Darbinių medžių aptikimas

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'

Failų struktūra

Pagrindinio darbinio medžio susietų darbinių medžių metaduomenys

Kodas
.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

Susieto darbinio medžio .git failas

Kodas
gitdir: <relative path to>/project/.git/worktrees/<name>

Išteklių bendrinimas

Išteklius Vieta Bendrinamas?
Objektai $commonDir/objects/ Taip
Konfigūracija $commonDir/config Taip
Packed-refs $commonDir/packed-refs Taip
Kablio scenarijai $gitDir/hooks/ Ne: Pitmaster nevykdo susietuose darbiniuose medžiuose bendrinamų kablių
HEAD $gitDir/HEAD Ne (atskiras kiekvienam darbiniam medžiui)
Indeksas $gitDir/index Ne (atskiras kiekvienam darbiniam medžiui)
Laisvosios nuorodos $commonDir/refs/ Taip (HEAD ir tokios operacijų nuorodos kaip MERGE_HEAD yra atskiros kiekvienam darbiniam medžiui)