Pracovné stromy
Git pracovné stromy umožňujú viacerým pracovným adresárom zdieľať jedno úložisko. Každý pracovný strom má vlastný checkout (HEAD, index, pracovné súbory), ale s hlavným úložiskom zdieľa úložisko objektov, konfiguráciu a súbor packed-refs. Pitmaster dokáže vytvárať, vypisovať, zamykať a odstraňovať prepojené pracovné stromy a otvárať ich ako úložiská. Orezávanie, presúvanie a oprava pracovných stromov nie sú implementované.
Základné pojmy
Bežné úložisko git má jeden pracovný strom:
project/
.git/ (directory)
src/
README.md
S pracovnými stromami môžete mať ďalšie checkouty:
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
Súbor .git prepojeného pracovného stromu je súbor (nie adresár), ktorý obsahuje cestu relatívnu k pracovnému stromu:
gitdir: ../../path/to/project/.git/worktrees/review
Vytvorenie pracovného stromu
$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() vykoná tieto kroky:
- Vytvorí vetvu, ak ešte neexistuje (z HEAD alebo zo zadaného commitu
$from) - Vytvorí adresár metadát v
.git/worktrees/<name>/ - Zapíše súbor
.gitdo adresára pracovného stromu - Zapíše súbory metadát
HEAD,commondiragitdir - Vykoná checkout stromu vetvy do adresára pracovného stromu
- Zapíše index pracovného stromu
Ak vetva už existuje, $from sa ignoruje. Na rozdiel od git addWorktree() neodmietne vetvu, ktorá už má checkout v inom pracovnom strome, a nespustí hook post-checkout.
S explicitným názvom metadát
Ak môže viacero prepojených pracovných stromov zdieľať rovnaký základný názov checkoutu, použite voliteľný argument name.
$wt = $repo->addWorktree(
'/tmp/sandboxes/app',
'feature/review',
name: 'sandbox-app',
);
Tento názov metadát sa použije v .git/worktrees/<name>/ namiesto basename($path).
Z konkrétneho commitu
$wt = $repo->addWorktree('/tmp/hotfix', 'hotfix/urgent', $repo->resolve('v1.0.0'));
Zobrazenie pracovných stromov
$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";
}
Zoznam vždy obsahuje najprv hlavný pracovný strom a za ním prepojené pracovné stromy. Zavolajte worktrees() na inštancii hlavného úložiska: pri inštancii prepojeného pracovného stromu aktuálne hlavná položka uvádza vlastnú cestu prepojeného pracovného stromu (#14).
Odstránenie pracovného stromu
$repo->removeWorktree('review'); // by metadata name
$repo->removeWorktree('/tmp/review'); // or by worktree path
// Force remove (even if locked)
$repo->removeWorktree('review', force: true);
Pri odstraňovaní pracovného stromu:
- Skontroluje, či je pracovný strom uzamknutý (zlyhá, ak
$forcenie je true) - Odstráni súbor
.gitz adresára pracovného stromu - Odstráni adresár metadát z
.git/worktrees/
Súbory pracovného stromu sa neodstránia automaticky. Vetva zostáva zachovaná.
Otvorenie prepojeného pracovného stromu
Prepojený pracovný strom môžete otvoriť rovnako ako akékoľvek úložisko:
$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'
Operácie s úložiskom rozpoznávajú cesty takto:
- Objekty: čítajú sa zo spoločného adresára git a zapisujú sa doň (
project/.git/objects/) - Konfigurácia: číta sa zo spoločného adresára git (
project/.git/config) - Packed-refs: číta sa zo spoločného adresára git
- HEAD: pre každý pracovný strom samostatne (každý sleduje vlastnú vetvu), rovnako ako
ORIG_HEAD,MERGE_HEADa ostatné operačné odkazy - Index: pre každý pracovný strom samostatne (každý má vlastnú oblasť prípravy)
- Voľné odkazy: vetvy a značky sa zdieľajú v spoločnom adresári (
project/.git/refs/) - Hooky: čítajú sa z adresára git konkrétneho pracovného stromu, takže zdieľané hooky sa nespustia (#12)
Stash zatiaľ nepodporuje prepojené pracovné stromy: číta identitu z adresára konkrétneho pracovného stromu, ktorý nemá konfiguráciu, a zapisuje tam jeho reflog (#14).
Objekt hodnoty Worktree
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
Na nízkoúrovňovú správu pracovných stromov. WorktreeManager::add() zapisuje iba metadáta a súbor .git: nevytvára vetvu, nevykonáva checkout súborov ani nezapisuje index. Na použiteľný checkout použite $repo->addWorktree(). Vetva už musí existovať (alebo musí ísť o úplný názov odkazu, napríklad refs/tags/v1.0.0, ktorý odpojí 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');
Uzamykanie pracovných stromov
// 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');
Zámok sa ukladá ako súbor v .git/worktrees/<name>/locked. Obsah súboru predstavuje dôvod uzamknutia (môže byť prázdny).
Detekcia pracovných stromov
// 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'
Rozloženie súborov
Metadáta hlavného pracovného stromu pre prepojené pracovné stromy
.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
Súbor .git prepojeného pracovného stromu
gitdir: <relative path to>/project/.git/worktrees/<name>
Zdieľanie zdrojov
| Zdroj | Umiestnenie | Zdieľaný? |
|---|---|---|
| Objekty | $commonDir/objects/ |
Áno |
| Konfigurácia | $commonDir/config |
Áno |
| Packed-refs | $commonDir/packed-refs |
Áno |
| Hooky | $gitDir/hooks/ |
Nie: Pitmaster nespúšťa zdieľané hooky v prepojených pracovných stromoch |
| HEAD | $gitDir/HEAD |
Nie (pre každý pracovný strom samostatne) |
| Index | $gitDir/index |
Nie (pre každý pracovný strom samostatne) |
| Voľné odkazy | $commonDir/refs/ |
Áno (HEAD a operačné odkazy, ako napríklad MERGE_HEAD, sú pre každý pracovný strom samostatné) |