
# 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

```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](https://github.com/inline0/pitmaster/issues/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](https://github.com/inline0/pitmaster/issues/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](https://github.com/inline0/pitmaster/issues/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

```
.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) |
