Munkafák
Git A munkafák lehetővé teszik, hogy több munkakönyvtár osztozzon egyetlen tárolón. Minden munkafának saját checkoutja van (HEAD, index, munkafájlok), miközben megosztja a fő tároló objektumtárolóját, konfigurációját és packed-refs állományát. A Pitmaster létrehozhatja, listázhatja, zárolhatja és eltávolíthatja az összekapcsolt munkafákat, és tárolóként is megnyithatja őket. A munkafák ritkázása, áthelyezése és javítása nincs megvalósítva.
Fogalmak
Egy szokásos git tárolónak egyetlen munkafája van:
project/
.git/ (directory)
src/
README.md
Munkafákkal további checkoutokat is használhat:
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
Az összekapcsolt munkafa .git fájl, nem könyvtár; a munkafához viszonyított elérési utat tartalmazza:
gitdir: ../../path/to/project/.git/worktrees/review
Munkafa létrehozása
$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)
A addWorktree() a következőket végzi:
- Létrehozza az ágat, ha még nem létezik (a HEAD-ből vagy a megadott
$fromcommitból) - Létrehozza a metaadatkönyvtárat itt:
.git/worktrees/<name>/ - Megírja a munkakönyvtárban a
.gitfájlt - Megírja a
HEAD, acommondirés agitdirmetaadatfájlt - Checkoutolja az ág fáját a munkakönyvtárba
- Megírja a munkafa indexét
Ha az ág már létezik, a $from figyelmen kívül marad. A gittel ellentétben a addWorktree() nem utasítja el azt az ágat, amelyet egy másik munkafában már checkoutoltak, és nem futtatja a post-checkout hookot.
Explicit metaadatnévvel
Használja az opcionális name argumentumot, ha több összekapcsolt munkafa azonos checkout-alapnevet használhat.
$wt = $repo->addWorktree(
'/tmp/sandboxes/app',
'feature/review',
name: 'sandbox-app',
);
Ez a metaadatnév a .git/worktrees/<name>/ alatt szerepel a basename($path) helyett.
Adott commitból
$wt = $repo->addWorktree('/tmp/hotfix', 'hotfix/urgent', $repo->resolve('v1.0.0'));
Munkafák listázása
$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";
}
A lista mindig először a fő munkafát tartalmazza, majd az összekapcsolt munkafákat. A fő tároló fogantyúján hívja meg a worktrees() metódust: összekapcsolt munkafa fogantyúján a fő bejegyzés jelenleg az összekapcsolt munkafa saját elérési útját jelzi (#14).
Munkafa eltávolítása
$repo->removeWorktree('review'); // by metadata name
$repo->removeWorktree('/tmp/review'); // or by worktree path
// Force remove (even if locked)
$repo->removeWorktree('review', force: true);
Munkafa eltávolításakor:
- Ellenőrzi, hogy a munkafa zárolva van-e (sikertelen, hacsak a
$forceértéke nem true) - Eltávolítja a munkakönyvtárból a
.gitfájlt - Eltávolítja a metaadatkönyvtárat innen:
.git/worktrees/
A munkafa fájljait nem törli automatikusan. Az ág továbbra is megmarad.
Összekapcsolt munkafa megnyitása
Az összekapcsolt munkafát ugyanúgy megnyithatja, mint bármely tárolót:
$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'
A tárolóműveletek az alábbiak szerint oldják fel az elérési utakat:
- Objektumok: a közös git könyvtárból olvas (
project/.git/objects/), és oda ír - Konfiguráció: a közös git könyvtárból olvas (
project/.git/config) - Packed-refs: a közös git könyvtárból olvas
- HEAD: munkafánkénti (minden munkafa a saját ágát követi), a
ORIG_HEAD, aMERGE_HEADés a többi műveleti ref mellett - Index: munkafánkénti (minden munkafának saját staging területe van)
- Laza refek: az ágak és címkék a közös könyvtárban vannak megosztva (
project/.git/refs/) - Hookok: a munkafánkénti git könyvtárból olvasódnak, ezért a megosztott hookok nem futnak (#12)
A Stash még nem kezeli az összekapcsolt munkafákat: a munkafánkénti könyvtárból olvassa az identitást, ahol nincs konfiguráció, és oda írja a reflogot (#14).
Munkafa értékobjektum
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
Alacsony szintű munkafakezeléshez. A WorktreeManager::add() csak a metaadatokat és a .git fájlt írja meg: nem hozza létre az ágat, nem checkoutolja a fájlokat, és nem ír indexet. Használja a $repo->addWorktree() elemet használható checkouthoz. Az ágnak már léteznie kell (vagy teljes refnévnek kell lennie, például refs/tags/v1.0.0, ami leválasztja a HEAD-et).
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');
Munkafák zárolása
// 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');
A zárolás fájlként itt tárolódik: .git/worktrees/<name>/locked. A fájl tartalma a zárolás oka (üres is lehet).
Munkafák felismerése
// 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'
Fájlelrendezés
A fő munkafa metaadatai az összekapcsolt munkafákhoz
.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
Az összekapcsolt munkafa .git fájlja
gitdir: <relative path to>/project/.git/worktrees/<name>
Erőforrások megosztása
| Erőforrás | Hely | Megosztva? |
|---|---|---|
| Objektumok | $commonDir/objects/ |
Igen |
| Konfiguráció | $commonDir/config |
Igen |
| Packed-refs | $commonDir/packed-refs |
Igen |
| Hookok | $gitDir/hooks/ |
Nem: a Pitmaster nem futtatja a megosztott hookokat az összekapcsolt munkafákban |
| HEAD | $gitDir/HEAD |
Nem (munkafánkénti) |
| Index | $gitDir/index |
Nem (munkafánkénti) |
| Laza refek | $commonDir/refs/ |
Igen (a HEAD és a műveleti refek, például a MERGE_HEAD, munkafánkéntiek) |