Arbetsträd
Git-arbetsträd gör det möjligt att dela ett arkiv mellan flera arbetskataloger. Varje arbetsträd har sin egen utcheckning (HEAD, index och arbetsfiler), men delar objektlagret, konfigurationen och packed-refs med huvudarkivet. Pitmaster kan skapa, lista, låsa och ta bort länkade arbetsträd samt öppna dem som arkiv. Rensning, flytt och reparation av arbetsträd är inte implementerat.
Begrepp
Ett vanligt git-arkiv har ett enda arbetsträd:
project/
.git/ (directory)
src/
README.md
Med worktrees kan du ha ytterligare utcheckningar:
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
Den länkade worktreens .git är en fil (inte en katalog) som innehåller en sökväg relativ till worktreen:
gitdir: ../../path/to/project/.git/worktrees/review
Skapa en worktree
$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() gör följande:
- Skapar grenen om den inte finns (från HEAD eller den angivna incheckningen
$from) - Skapar metadatakatalogen på
.git/worktrees/<name>/ - Skriver filen
.giti worktreens katalog - Skriver metadatafilerna
HEAD,commondirochgitdir - Checkar ut grenens träd till worktreens katalog
- Skriver worktreens index
Om grenen redan finns ignoreras $from. Till skillnad från git vägrar addWorktree() inte att använda en gren som redan är utcheckad i en annan worktree, och kör inte hooken post-checkout.
Med ett uttryckligt metadatanamn
Använd det valfria argumentet name när flera länkade worktrees kan ha samma basnamn för utcheckningen.
$wt = $repo->addWorktree(
'/tmp/sandboxes/app',
'feature/review',
name: 'sandbox-app',
);
Metadatanamnet används under .git/worktrees/<name>/ i stället för basename($path).
Från en specifik incheckning
$wt = $repo->addWorktree('/tmp/hotfix', 'hotfix/urgent', $repo->resolve('v1.0.0'));
Lista worktrees
$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";
}
Listan innehåller alltid huvud-worktreen först, följd av länkade worktrees. Anropa worktrees() på ett handtag för huvudarkivet: på ett handtag för en länkad worktree rapporterar huvudentrén för närvarande den länkade worktreens egen sökväg (#14).
Ta bort en worktree
$repo->removeWorktree('review'); // by metadata name
$repo->removeWorktree('/tmp/review'); // or by worktree path
// Force remove (even if locked)
$repo->removeWorktree('review', force: true);
När en worktree tas bort:
- Kontrolleras om worktreen är låst (misslyckas om inte
$forceär true) - Tas filen
.gitbort från worktreens katalog - Tas metadatakatalogen bort från
.git/worktrees/
Filerna i arbetskatalogen tas inte bort automatiskt. Grenen finns kvar.
Öppna en länkad worktree
Du kan öppna en länkad worktree precis som vilket arkiv som helst:
$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'
Sökvägar för arkivåtgärder hanteras så här:
- Objekt: läses från och skrivs till den gemensamma katalogen git (
project/.git/objects/) - Konfiguration: läses från den gemensamma katalogen git (
project/.git/config) - Packed-refs: läses från den gemensamma katalogen git
- HEAD: per worktree (varje worktree håller reda på sin egen gren), tillsammans med
ORIG_HEAD,MERGE_HEADoch övriga åtgärdsreferenser - Index: per worktree (varje worktree har sitt eget stagingområde)
- Lösa referenser: grenar och taggar delas i den gemensamma katalogen (
project/.git/refs/) - Hooks: läses från worktreens egen katalog git, så de delade hookarna körs inte (#12)
Stash hanterar ännu inte länkade worktrees: det läser identiteten från worktreens egen katalog, som saknar konfiguration, och skriver refloggen där (#14).
Worktree-värdeobjekt
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
För hantering av worktrees på låg nivå. WorktreeManager::add() skriver bara metadata och filen .git: den skapar inte grenen, checkar inte ut filer och skriver inget index. Använd $repo->addWorktree() för en användbar utcheckning. Grenen måste redan finnas (eller vara ett fullständigt referensnamn, till exempel refs/tags/v1.0.0, vilket kopplar loss 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');
Låsa worktrees
// 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');
Låset lagras som en fil på .git/worktrees/<name>/locked. Filinnehållet är låsorsaken (kan vara tomt).
Identifiera worktrees
// 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'
Filstruktur
Metadata för huvud-worktreen vid länkade worktrees
.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
Den länkade worktreens .git-fil
gitdir: <relative path to>/project/.git/worktrees/<name>
Delade resurser
| Resurs | Plats | Delad? |
|---|---|---|
| Objekt | $commonDir/objects/ |
Ja |
| Konfiguration | $commonDir/config |
Ja |
| Packed-refs | $commonDir/packed-refs |
Ja |
| Hooks | $gitDir/hooks/ |
Nej: Pitmaster kör inte de delade hookarna i länkade worktrees |
| HEAD | $gitDir/HEAD |
Nej (per worktree) |
| Index | $gitDir/index |
Nej (per worktree) |
| Lösa referenser | $commonDir/refs/ |
Ja (HEAD och åtgärdsreferenser som MERGE_HEAD är per worktree) |