Preskoči na vsebino

Shramba

Git shramba shrani spremembe delovnega imenika in indeksa, da lahko preklopite na drugo opravilo in jih pozneje obnovite. Pitmaster izvaja shrambo z uporabo refs/stash in refloga, v skladu s postavitvijo shrambe za git. Na Repository ni metode za shrambo; uporabite spodnji razred Stash.

Znani sta dve težavi: če je vnosov več kot eden, drop() (in zato tudi pop()) pusti vnos na seznamu (#10), apply() pa prepiše nepotrjene spremembe v datotekah, ki se jih shramba ne dotika (#11). Shrambe uveljavljajte v čistem delovnem drevesu.

Delovanje shrambe

Vsak vnos shrambe je potrditev z dvema nadrejenima potrditvama:

  • Nadrejena potrditev 0: potrditev HEAD v času shranjevanja (osnovno stanje)
  • Nadrejena potrditev 1: potrditev, ki zajame stanje indeksa (pripravljene spremembe)

Lastno drevo potrditve shrambe zajame stanje delovnega drevesa (vključno z nepripravljenimi spremembami).

»Sklad« shrambe je reflog za refs/stash. Najnovejša shramba je kar refs/stash. Starejši vnosi so vnosi refloga: stash@{0}, stash@{1} itd.

Koda
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

Ustvarjanje predmeta Stash

PHP
use Pitmaster\Stash\Stash;

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

Potisni (shrani spremembe)

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

Potisni izvede naslednje:

  1. Prebere trenutno potrditev HEAD
  2. Zgradi drevo iz trenutnega indeksa (pripravljeno stanje)
  3. Ustvari »potrditev indeksa« z nadrejeno potrditvijo HEAD
  4. Zgradi drevo iz trenutnega delovnega imenika (vključno z nepripravljenimi spremembami)
  5. Ustvari potrditev shrambe (drevo delovnega drevesa, nadrejeni potrditvi = HEAD + potrditev indeksa)
  6. Posodobi refs/stash, da kaže na potrditev shrambe
  7. Doda vnos refloga za sklad
  8. Ponastavi delovno drevo in indeks na HEAD

Po potisku se sledene datoteke ujemajo s HEAD. Nesledene datoteke ostanejo, razen če je nastavljen includeUntracked; v tem primeru se odstranijo in shranijo v lastno drevo potrditve shrambe (git jih namesto tega shrani v tretjo nadrejeno potrditev, zato jih git vidi kot sledene spremembe). push() ustvari vnos tudi, če ni bilo sprememb; v tem primeru git sporoči »Ni lokalnih sprememb za shranjevanje«.

S privzetim sporočilom

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

Pri odpetem HEAD je <branch> enak HEAD.

Izprazni (uveljavi in odstrani)

PHP
$stash->pop();

Uveljavi vrhnji vnos shrambe v delovnem imeniku in ga odstrani iz sklada. Enakovredno je apply(), ki mu sledi drop().

Izprazni določen vnos

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

Uveljavi (obnovi brez odstranitve)

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

Uveljavi združi shrambo s trenutno datoteko HEAD po datotekah (osnova shrambe, trenutni HEAD, drevo shrambe). Vnos shrambe ostane v skladu, indeks pa se ne spremeni. Ob sporih v datotekah ostanejo označevalniki Updated upstream in Stashed changes, sproži pa se Pitmaster\Exceptions\MergeConflictException; pop() nato vnos ohrani. Uveljavi predhodno ne preveri lokalnih sprememb (glejte opombo na vrhu).

Seznam vnosov

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
}

Vsak vnos vsebuje:

  • index: položaj shrambe (0 = najnovejša)
  • message: sporočilo shrambe
  • hash: zgoščena vrednost potrditve shrambe

Izbriši (odstrani brez uveljavitve)

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

Če izbrišete edini vnos, se odstranita refs/stash in njegov reflog. Če je vnosov več, drop() trenutno samo premakne refs/stash in refloga ne spremeni, zato vnos ostane v listEntries() (#10).

Podrobnosti shranjevanja

Struktura potrditve shrambe

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

<stash message>

Struktura potrditve indeksa

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

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

Identiteta izhaja iz GIT_COMMITTER_NAME, nato GIT_AUTHOR_NAME, nato user.name v konfiguraciji repozitorija, nato Pitmaster (enak vrstni red velja za e-pošto, ki se konča z pitmaster@example.invalid). Datum izhaja iz GIT_COMMITTER_DATE, nato GIT_AUTHOR_DATE, nato iz trenutnega časa. Za razliko od potrditev shramba ne bere konstant PITMASTER_*.

Shranjevanje Reflog

Vnosi shrambe so shranjeni v .git/logs/refs/stash:

Koda
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 se bere v kronološkem vrstnem redu. Seznam shrambe ga obrne (najnovejše najprej). Reflog shrambe se zapiše ne glede na core.logallrefupdates.

Uporaba CLI

Lupina
# 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

Sporočilo je argument za push (ali save); -m ni podprt. pop, apply in drop vedno delujejo na stash@{0}; CLI nima --include-untracked.

Omejitve

  • Samo shramba celotnega delovnega imenika (brez --keep-index); nesledene datoteke so podprte samo prek push($message, includeUntracked: true)
  • Ni načina --patch (interaktivni izbor kosov)
  • Izprazni/uveljavi obnovi stanje delovnega drevesa; indeksa ne obnovi. Pripravljene spremembe se vrnejo kot nepripravljene, na novo pripravljene datoteke pa kot nesledene
  • stash@{n} ne sprejema Repository::resolve()
  • Shramba v povezanem delovnem drevesu uporablja napačno mesto konfiguracije in refloga (#14)