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į:
project/
.git/ (directory)
src/
README.md
Naudodami darbinius medžius galite turėti papildomų išsiėmimo kopijų:
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į:
gitdir: ../../path/to/project/.git/worktrees/review
Darbinio medžio kūrimas
$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:
- Sukuria šaką, jei jos nėra (iš HEAD arba nurodyto
$frompakeitimo) - Sukuria metaduomenų katalogą adresu
.git/worktrees/<name>/ - Darbinio medžio kataloge įrašo failą
.git - Įrašo metaduomenų failus
HEAD,commondirirgitdir - Išsiima šakos medį į darbinio medžio katalogą
- Į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ą.
$wt = $repo->addWorktree(
'/tmp/sandboxes/app',
'feature/review',
name: 'sandbox-app',
);
Šis metaduomenų pavadinimas naudojamas .git/worktrees/<name>/ vietoje basename($path).
Iš konkretaus pakeitimo
$wt = $repo->addWorktree('/tmp/hotfix', 'hotfix/urgent', $repo->resolve('v1.0.0'));
Darbinių medžių sąrašas
$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
$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į:
- Tikrinama, ar darbinis medis užrakintas (šalinama tik jei
$forceyra true) - Iš darbinio medžio katalogo pašalinamas failas
.git - 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ą:
$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_HEADir 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
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).
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
// 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
// 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
.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
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) |