Refs
Refs (verwijzingen) zijn benoemde pointers naar commits. Branches, tags, HEAD en remote tracking refs zijn allemaal refs. Pitmaster leest refs uit losse bestanden, packed-refs en reftable, en schrijft losse bestanden en packed-refs.
RefDatabase
De RefDatabase is de samengestelde laag die eerst losse refs doorzoekt, daarna reftable (als de repository er een heeft) en vervolgens packed-refs.
use Pitmaster\Ref\RefDatabase;
$refs = new RefDatabase($gitDir, $commonDir);
// Resolve a ref to an ObjectId
$id = $refs->resolve('refs/heads/main');
// Resolve HEAD (follows symbolic refs)
$headId = $refs->resolveHead();
// Read HEAD as a symbolic ref (null when HEAD is detached)
$symref = $refs->readHead();
echo $symref?->target; // 'refs/heads/main'
// List all refs
foreach ($refs->list() as $name => $id) {
echo "{$id->hex} {$name}\n";
}
// Update a ref
$refs->update('refs/heads/main', $newCommitId);
// Delete a ref
$refs->delete('refs/heads/old-branch');
Voor gekoppelde worktrees bewaart de RefDatabase HEAD en de andere pseudo-refs per worktree (ORIG_HEAD, MERGE_HEAD, CHERRY_PICK_HEAD, REVERT_HEAD, REBASE_HEAD, BISECT_HEAD) in de git-map van de worktree. Branches, tags en andere refs/-items worden naar de gemeenschappelijke map geschreven, en packed-refs wordt altijd uit de gemeenschappelijke map gelezen.
Losse refs
Losse refs zijn afzonderlijke bestanden in .git/refs/. Elk bestand bevat de hex-hash van het doelobject (40 tekens, of 64 voor SHA-256), gevolgd door een nieuwe regel.
.git/refs/heads/main -> abc123def456...\n
.git/refs/tags/v1.0.0 -> 789012abc345...\n
.git/refs/remotes/origin/main -> abc123def456...\n
use Pitmaster\Ref\LooseRefStore;
$store = new LooseRefStore($gitDir, $commonDir); // $commonDir defaults to $gitDir
$id = $store->resolve('refs/heads/main');
$store->update('refs/heads/main', $commitId);
$store->delete('refs/heads/old');
HEAD
HEAD is een speciale ref die kan zijn:
Symbolisch: verwijst naar een andere ref (meestal wanneer je op een branch zit):
ref: refs/heads/main\n
Losgekoppeld: verwijst rechtstreeks naar een commit-hash:
abc123def456789012abc345def678901234abcd\n
use Pitmaster\Ref\SymbolicRef;
$symref = SymbolicRef::parse('HEAD', $headContent);
if ($symref !== null) {
echo "On branch: {$symref->target}\n";
// 'refs/heads/main'
} else {
echo "Detached HEAD\n";
}
Gepackte refs
Het bestand packed-refs combineert veel refs in één bestand voor meer efficiëntie. Git maakt het aan tijdens git pack-refs of git gc.
# pack-refs with: peeled fully-peeled sorted
abc123def456789012abc345def678901234abcd refs/heads/main
789012abc345def678901234abcdabc123def456 refs/tags/v1.0.0
^def456789012abc345def678901234abcdabc12
Regels die beginnen met ^ zijn uitgepelde waarden: de commit waar een geannoteerde tag uiteindelijk naar verwijst.
use Pitmaster\Ref\PackedRefStore;
$store = new PackedRefStore($commonDir);
$id = $store->resolve('refs/heads/main');
foreach ($store->list() as $name => $id) {
echo "{$id->hex} {$name}\n";
}
Uitgepelde waarden
Voor geannoteerde tags kan het packed-refs-bestand de uitgepelde (gedereferentieerde) waarde bevatten op de regel na de tag-ref. De uitgepelde waarde is de commit waar het tagobject uiteindelijk naar verwijst (mogelijk via meerdere tagobjecten).
$peeled = $store->peeled('refs/tags/v1.0.0');
// Returns the commit ObjectId, or null if not peeled
Ref-resolutievolgorde
Bij het oplossen van een ref controleert Pitmaster dit in deze volgorde:
- Losse ref (bestand in
.git/refs/) - Reftable, als
.git/reftable/tables.listbestaat - Gepackte ref (item in
.git/packed-refs)
Losse refs hebben voorrang. Wanneer een gepackte ref wordt bijgewerkt, wordt de nieuwe waarde als losse ref geschreven (het packed-refs-bestand wordt niet herschreven). Als je een ref verwijdert, worden zowel het losse bestand als het gepackte item verwijderd. $repo->packRefs() herschrijft packed-refs op basis van de huidige refs en verwijdert de losse bestanden.
SymbolicRef
Symbolische refs zijn verwijzingen naar andere verwijzingen, in plaats van rechtstreeks naar objecten.
use Pitmaster\Ref\SymbolicRef;
// Parse
$ref = SymbolicRef::parse('HEAD', "ref: refs/heads/main\n");
echo $ref->name; // 'HEAD'
echo $ref->target; // 'refs/heads/main'
// Update
$refs->updateSymbolic('HEAD', 'refs/heads/feature');
Reflog
De reflog registreert wanneer refs veranderen, zodat git reflog de geschiedenis van HEAD en branch-tips kan tonen.
Reflog-bestanden staan in .git/logs/:
.git/logs/HEAD
.git/logs/refs/heads/main
.git/logs/refs/stash
Elke regel legt vast:
<old-hash> <new-hash> <author> <timestamp> <tz>\t<message>
use Pitmaster\Ref\Reflog;
$reflog = Reflog::open($gitDir, 'HEAD');
// Read entries
$entries = $reflog->entries();
foreach ($entries as $entry) {
echo "{$entry['old']} -> {$entry['new']}: {$entry['message']}\n";
}
// Append an entry
$reflog->append(
$oldId,
$newId,
'Name <email> 1700000000 +0000',
'commit: Add feature',
);
De stash gebruikt de reflog van refs/stash als opslag voor de stapel.
Reftable
Reftable is een nieuwer binair formaat voor het opslaan van refs, ontworpen voor betere prestaties bij veel refs (duizenden branches). Het vervangt zowel losse refs als packed-refs.
Reftable-bestanden worden opgeslagen in .git/reftable/ en bevatten:
- Ref-records (gesorteerd op naam)
- Logrecords (reflog-items)
- Indexering op blokniveau voor snelle zoekopdrachten
Pitmaster leest de ref-records van reftable-bestanden als die aanwezig zijn; logrecords worden niet gelezen. Wanneer er een reftable bestaat, vervangt die packed-refs voor het weergeven van refs. Ref-updates worden altijd als losse bestanden geschreven, die git in een reftable-repository niet leest. Behandel reftable-repositories daarom als alleen-lezen.
Naamgevingsconventies voor refs
| Patroon | Betekenis |
|---|---|
refs/heads/<name> |
Lokale branch |
refs/tags/<name> |
Tag (lichtgewicht of geannoteerd) |
refs/remotes/<remote>/<name> |
Remote tracking branch |
refs/stash |
Stash-stapel |
refs/notes/<namespace> |
Notities van Git |
HEAD |
Huidige checkout (symbolisch of losgekoppeld) |
FETCH_HEAD |
Resultaat van de laatste fetch (geschreven door git; Pitmaster's fetch() schrijft dit niet) |
MERGE_HEAD |
Branch die wordt samengevoegd (tijdens een merge) |
ORIG_HEAD |
Vorige HEAD (vóór risicovolle bewerkingen) |
Werken met refs via Repository
// Read
$branch = $repo->branch(); // Current branch name
$branches = $repo->branches(); // All branch names
$tags = $repo->tags(); // All tag names
$refs = $repo->allRefs(); // All refs as name => hash
// Write
$repo->createBranch('feature'); // Create refs/heads/feature
$repo->deleteBranch('feature'); // Delete refs/heads/feature
$repo->createTag('v1.0', 'Release');// Create annotated tag
$repo->createLightweightTag('v1.0-lite'); // Create lightweight tag
$repo->updateRef('refs/heads/main', $id); // Direct ref update
// Resolve
$id = $repo->resolve('HEAD');
$id = $repo->resolve('main');
$id = $repo->resolve('v1.0.0');
$id = $repo->resolve('HEAD~3');