
# Työhakemistot

Git-työhakemistot mahdollistavat useiden työhakemistojen käytön yhden arkiston kanssa. Jokaisella työhakemistolla on oma uloskirjaus (HEAD, indeksi ja tiedostot), mutta ne jakavat pääarkiston kanssa oliotallennustilan, asetukset ja pakatut viitteet. Pitmaster voi luoda, luetteloida, lukita ja poistaa linkitettyjä työhakemistoja sekä avata ne arkistoina. Karsimista, siirtämistä ja korjaamista ei ole toteutettu.

## Käsitteet

Tavallisessa git-arkistossa on yksi työhakemisto:

```
project/
  .git/          (directory)
  src/
  README.md
```

Työhakemistojen avulla voit tehdä lisäuloskirjauksia:

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

Linkitetyn työhakemiston `.git` on tiedosto (ei hakemisto), joka sisältää suhteellisen polun työhakemistoon:
```
gitdir: ../../path/to/project/.git/worktrees/review
```

## Työhakemiston luominen

```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()` tekee seuraavaa:
1. Luo haaran, jos sitä ei ole (HEADistä tai määritetystä `$from`-commitista)
2. Luo metatietohakemiston kohteeseen `.git/worktrees/<name>/`
3. Kirjoittaa `.git`-tiedoston työhakemiston hakemistoon
4. Kirjoittaa metatietotiedostot `HEAD`, `commondir` ja `gitdir`
5. Ottaa haaran puun käyttöön työhakemiston hakemistossa
6. Kirjoittaa työhakemiston indeksin

Jos haara on jo olemassa, `$from` ohitetaan. Toisin kuin git, `addWorktree()` ei kieltäydy luomasta haaraa, joka on jo otettu käyttöön toisessa työhakemistossa, eikä suorita `post-checkout`-koukkua.

### Määritetyllä metatietonimellä

Käytä valinnaista `name`-argumenttia, kun useat linkitetyt työhakemistot voivat jakaa saman uloskirjauksen perusnimen.

```php
$wt = $repo->addWorktree(
    '/tmp/sandboxes/app',
    'feature/review',
    name: 'sandbox-app',
);
```

Metatietonimeä käytetään kohteessa `.git/worktrees/<name>/` kohteen `basename($path)` sijaan.

### Tietystä commitista

```php
$wt = $repo->addWorktree('/tmp/hotfix', 'hotfix/urgent', $repo->resolve('v1.0.0'));
```

## Työhakemistojen luettelointi

```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";
}
```

Luettelo sisältää aina ensin päätyöhakemiston, jota seuraavat linkitetyt työhakemistot. Kutsu `worktrees()`-metodia pääarkiston kahvalla: linkitetyn työhakemiston kahvalla päämerkintä ilmoittaa tällä hetkellä linkitetyn työhakemiston oman polun ([#14](https://github.com/inline0/pitmaster/issues/14)).

## Työhakemiston poistaminen

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

Työhakemiston poistaminen:
1. Tarkistaa, onko työhakemisto lukittu (epäonnistuu, ellei `$force` ole true)
2. Poistaa työhakemiston hakemistosta `.git`-tiedoston
3. Poistaa metatietohakemiston kohteesta `.git/worktrees/`

Työhakemiston tiedostoja ei poisteta automaattisesti. Haara säilyy.

## Linkitetyn työhakemiston avaaminen

Voit avata linkitetyn työhakemiston kuten minkä tahansa arkiston:

```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'
```

Arkistotoiminnot ratkaisevat polut seuraavasti:
- **Oliot**: luetaan yhteisestä git-hakemistosta ja kirjoitetaan siihen (`project/.git/objects/`)
- **Asetukset**: luetaan yhteisestä git-hakemistosta (`project/.git/config`)
- **Pakatut viitteet**: luetaan yhteisestä git-hakemistosta
- **HEAD**: työhakemistokohtainen (jokainen työhakemisto seuraa omaa haaraansa), samoin kuin `ORIG_HEAD`, `MERGE_HEAD` ja muut toimintaviitteet
- **Indeksi**: työhakemistokohtainen (jokaisella työhakemistolla on oma valmistelualue)
- **Löysät viitteet**: haarat ja tunnisteet jaetaan yhteisessä hakemistossa (`project/.git/refs/`)
- **Koukut**: luetaan työhakemistokohtaisesta git-hakemistosta, joten jaetut koukut eivät toimi ([#12](https://github.com/inline0/pitmaster/issues/12))

Stash ei vielä tue linkitettyjä työhakemistoja: se lukee identiteetin työhakemistokohtaisesta hakemistosta, jossa ei ole asetuksia, ja kirjoittaa reflogin sinne ([#14](https://github.com/inline0/pitmaster/issues/14)).

## Työhakemiston arvokohde

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

Matalan tason työhakemistojen hallintaan. `WorktreeManager::add()` kirjoittaa vain metatiedot ja `.git`-tiedoston: se ei luo haaraa, ota tiedostoja käyttöön eikä kirjoita indeksiä. Käytä `$repo->addWorktree()`-toimintoa käyttökelpoisen uloskirjauksen luomiseen. Haaran on oltava olemassa (tai sen on oltava täydellinen viitenimi, kuten `refs/tags/v1.0.0`, jolloin HEAD irrotetaan).

```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');
```

## Työhakemistojen lukitseminen

```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');
```

Lukitus tallennetaan tiedostoon kohteessa `.git/worktrees/<name>/locked`. Tiedosto sisältää lukituksen syyn (voi olla tyhjä).

## Työhakemistojen tunnistaminen

```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'
```

## Tiedostorakenne

### Linkitettyjen työhakemistojen päätyöhakemiston metatiedot

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

### Linkitetyn työhakemiston .git-tiedosto

```
gitdir: <relative path to>/project/.git/worktrees/<name>
```

### Jaetut resurssit

| Resurssi | Sijainti | Jaettu? |
|----------|----------|---------|
| Oliot | `$commonDir/objects/` | Kyllä |
| Asetukset | `$commonDir/config` | Kyllä |
| Pakatut viitteet | `$commonDir/packed-refs` | Kyllä |
| Koukut | `$gitDir/hooks/` | Ei: Pitmaster ei suorita linkitettyjen työhakemistojen jaettuja koukkuja |
| HEAD | `$gitDir/HEAD` | Ei (työhakemistokohtainen) |
| Indeksi | `$gitDir/index` | Ei (työhakemistokohtainen) |
| Löysät viitteet | `$commonDir/refs/` | Kyllä (HEAD ja toimintaviitteet, kuten `MERGE_HEAD`, ovat työhakemistokohtaisia) |
