
# Stash

Git stash saglabā izmaiņas darba direktorijā un indeksā, lai jūs varētu pārslēgties uz citu uzdevumu un vēlāk tās atjaunot. Pitmaster īsteno stash, izmantojot `refs/stash` un reflog git krātuves izkārtojumā. Klasē `Repository` nav stash metodes; izmantojiet tālāk norādīto klasi `Stash`.

Divas zināmas problēmas: ja ir vairāk nekā viens ieraksts, `drop()` (un līdz ar to arī `pop()`) atstāj ierakstu sarakstā ([#10](https://github.com/inline0/pitmaster/issues/10)), bet `apply()` pārraksta neapstiprinātās izmaiņas failos, kurus stash neskar ([#11](https://github.com/inline0/pitmaster/issues/11)). Lietojiet stash tikai ar tīru darba koku.

## Kā darbojas stash

Katrs stash ieraksts ir komits ar diviem vecākiem:
- **Vecāks 0**: HEAD komits stash izveides brīdī (bāzes stāvoklis)
- **Vecāks 1**: komits, kurā fiksēts indeksa stāvoklis (sagatavotās izmaiņas)

Paša stash komita koks fiksē darba koka stāvokli (tostarp nesagatavotās izmaiņas).

Stash „steks” ir `refs/stash` reflog. Jaunākais stash ir pats `refs/stash`. Vecākie ieraksti ir reflog ieraksti: `stash@{0}`, `stash@{1}` utt.

```
refs/stash -> stash commit (worktree state)
                parent[0] -> HEAD at time of stash
                parent[1] -> index state commit
                               parent[0] -> HEAD at time of stash
```

## Stash objekta izveide

```php
use Pitmaster\Stash\Stash;

$stash = new Stash(
    $repo->objectDatabase(),
    $repo->refDatabase(),
    $repo->gitDir(),
    $repo->workDir(),
);
```

## Push (saglabāt izmaiņas)

```php
// public function push(string $message = '', bool $includeUntracked = false): ObjectId
$stashId = $stash->push('Work in progress on login');
echo "Saved: {$stashId->hex}\n";

// Also stash untracked files
$stashId = $stash->push('With new files', includeUntracked: true);
```

Push veic tālāk norādīto:
1. Nolasa pašreizējo HEAD komitu
2. Izveido koku no pašreizējā indeksa (sagatavotais stāvoklis)
3. Izveido „indeksa komitu”, kura vecāks ir HEAD
4. Izveido koku no pašreizējās darba direktorijas (tostarp nesagatavotajām izmaiņām)
5. Izveido stash komitu (darba koka koks, vecāki = HEAD + indeksa komits)
6. Atjaunina `refs/stash`, lai tas norādītu uz stash komitu
7. Pievieno stekam reflog ierakstu
8. Atiestata darba koku un indeksu uz HEAD

Pēc push izsekojamie faili atbilst HEAD. Neizsekotie faili paliek, ja vien nav iestatīts `includeUntracked`; tad tie tiek noņemti un saglabāti pašā stash komita kokā (git tos glabā trešajā vecākā, tāpēc git tos uzskata par izsekotām izmaiņām). `push()` izveido ierakstu arī tad, ja nekas nav mainījies; šādā gadījumā git ziņo: „No local changes to save”.

### Ar noklusējuma ziņojumu

```php
$stashId = $stash->push();
// Message: "WIP on <branch>: <short hash> <HEAD subject>"
// With a message: "On <branch>: <message>"
```

Ja HEAD ir atdalīts, `<branch>` ir `HEAD`.

## Pop (lietot un noņemt)

```php
$stash->pop();
```

Lieto steka augšējo stash ierakstu darba direktorijai un noņem to no steka. Atbilst `apply()`, kam seko `drop()`.

### Izņemt konkrētu ierakstu

```php
$stash->pop(1);  // Pop stash@{1}
```

## Apply (atjaunot, nenoņemot)

```php
$stash->apply();      // Apply stash@{0}
$stash->apply(2);     // Apply stash@{2}
```

Apply failu pa failam apvieno stash ar pašreizējo HEAD (stash bāze, pašreizējais HEAD, stash koks). Stash ieraksts paliek stekā, un indekss netiek skarts. Konfliktu marķieri `Updated upstream` un `Stashed changes` tiek ierakstīti failos, un tiek izraisīts `Pitmaster\Exceptions\MergeConflictException`; pēc tam `pop()` ierakstu saglabā. Apply vispirms nepārbauda, vai nav lokālu izmaiņu (skatiet piezīmi augšā).

## Ierakstu saraksts

```php
$entries = $stash->listEntries();

foreach ($entries as $entry) {
    echo "stash@{{$entry['index']}}: {$entry['message']}\n";
    // stash@{0}: On main: Work in progress on login
    // stash@{1}: WIP on main: f707601 Add login form
}
```

Katrā ierakstā ir:
- `index`: stash pozīcija (0 = jaunākais)
- `message`: stash ziņojums
- `hash`: stash komita jaucējvērtība

## Drop (noņemt, nelietojot)

```php
$stash->drop();       // Drop stash@{0}
$stash->drop(1);      // Drop stash@{1}
```

Ja tiek dzēsts vienīgais ieraksts, `refs/stash` un tā reflog tiek noņemti. Ja ir vairāki ieraksti, `drop()` pašlaik tikai pārvieto `refs/stash`, bet reflog nemaina, tāpēc ieraksts paliek `listEntries()` ([#10](https://github.com/inline0/pitmaster/issues/10)).

## Glabāšanas informācija

### Stash komita struktūra

```
commit <hash>
tree <worktree-tree-hash>
parent <HEAD-hash>
parent <index-commit-hash>
author <current identity>
committer <current identity>

<stash message>
```

### Indeksa komita struktūra

```
commit <hash>
tree <index-tree-hash>
parent <HEAD-hash>
author <current identity>
committer <current identity>

index on <branch>: <short hash> <HEAD subject>
```

Identitāte tiek iegūta šādā secībā: `GIT_COMMITTER_NAME`, `GIT_AUTHOR_NAME`, `user.name` repozitorija konfigurācijā, pēc tam `Pitmaster` (tāda pati secība tiek izmantota e-pasta adresei, noslēdzoties ar `pitmaster@example.invalid`). Datums tiek iegūts no `GIT_COMMITTER_DATE`, pēc tam `GIT_AUTHOR_DATE` un visbeidzot no pašreizējā laika. Atšķirībā no komitiem stash nelasa `PITMASTER_*` konstantes.

### Reflog glabāšana

Stash ieraksti tiek glabāti šeit: `.git/logs/refs/stash`

```
0000000000000000000000000000000000000000 abc123... Name <email> 1700000000 +0000	WIP on main: f707601 Add login form
abc123... def456... Name <email> 1700000001 +0000	On main: Work in progress on login
```

Reflog tiek nolasīts hronoloģiskā secībā. Stash sarakstā tas tiek apgriezts (jaunākais vispirms). Stash reflog tiek ierakstīts neatkarīgi no `core.logallrefupdates`.

## CLI lietojums

```bash
# Save current changes
./vendor/bin/pitmaster stash
./vendor/bin/pitmaster stash push
./vendor/bin/pitmaster stash push "Work in progress on login"

# Apply and remove top entry
./vendor/bin/pitmaster stash pop

# Apply without removing
./vendor/bin/pitmaster stash apply

# List all entries
./vendor/bin/pitmaster stash list

# Remove top entry without applying
./vendor/bin/pitmaster stash drop
```

Ziņojums ir arguments aiz `push` (vai `save`); `-m` netiek atbalstīts. `pop`, `apply` un `drop` vienmēr darbojas ar `stash@{0}`; CLI nav `--include-untracked`.

## Ierobežojumi

- Tiek saglabāts tikai viss darba direktorijas stash (bez `--keep-index`); neizsekotie faili — tikai ar `push($message, includeUntracked: true)`
- Nav `--patch` režīma (interaktīva fragmentu atlase)
- Pop/apply atjauno darba koka stāvokli; indekss netiek atjaunots. Sagatavotie labojumi atgriežas kā nesagatavoti labojumi, bet tikko sagatavotie faili — kā neizsekoti faili
- `stash@{n}` netiek pieņemts `Repository::resolve()`
- Stash saistītā darba kokā izmanto nepareizo konfigurāciju un reflog atrašanās vietu ([#14](https://github.com/inline0/pitmaster/issues/14))
