Klonēšana, izgūšana, nosūtīšana
Pitmaster atbalsta trīs pamatoperācijas git tīklā: clone (sākotnējā lejupielāde), fetch (papildu lejupielāde) un push (augšupielāde). SSH URL (ssh://..., user@host:path) izmanto SSH transportu; citi URL izmanto viedo HTTP, un clone un fetch izmanto vienkāršo HTTP kā rezerves variantu, ja viedā apmaiņa neizdodas (skatiet Protokoli).
Visas trīs operācijas sāk tīkla transporta darbību, tāpēc ar tām izsaukts RuntimeException izraisa kļūdu, ja rokturis atvērts ar ['processes' => false] vai Pitmaster::processFreeOptions().
Klonēšana
use Pitmaster\Pitmaster;
// public static function clone(string $url, string $path, ?int $depth = null, array $options = []): Repository
$repo = Pitmaster::clone('https://github.com/user/repo.git', '/path/to/destination');
$repo = Pitmaster::clone('https://github.com/user/repo.git', '/path/to/shallow', 1);
Jaunajā repozitorijā vienmēr tiek izmantots SHA-1. Ja klonēšana neizdodas un galamērķis iepriekš neeksistēja, daļēji izveidotā direktorija tiek dzēsta.
Klonēšanas darbplūsma
- Inicializācija: galamērķa ceļā izveido jaunu tukšu repozitoriju
- Attālā repozitorija konfigurēšana: saglabā URL kā
remote.origin.urlun iestata izgūšanas refspec - Refs atklāšana:
GET /info/refs?service=git-upload-pack, lai noskaidrotu, kas ir serverī - Saskaņošana: nosūta
wantrindas visiem attālajiem refiem (dublikāti pēc jaucējvērtības tiek izlaisti) - Pack saņemšana: lejupielādē pack failu ar visiem pieprasītajiem objektiem
- Pack ierakstīšana: saglabā pack failu mapē
.git/objects/pack/ - Pack indeksēšana: izveido
.idxfailu ātrai meklēšanai - Ref iestatīšana: izveido attālo izsekošanas atzaru (
refs/remotes/origin/*) un tagus - HEAD iestatīšana: norāda HEAD uz noklusējuma atzaru (no servera
symref=HEAD:...iespējas vairefs/heads/main, ja serveris to nenosūta), un iestatabranch.<name>.remoteunbranch.<name>.merge - Izgūšana: izgūst šo atzaru, ierakstot darba koku un indeksu
Kļūdas pēdējās izgūšanas laikā tiek uztvertas un ignorētas, tāpēc klonēšanas rezultātā darba koks var būt tukšs vai nepilnīgs (#19).
$repo = Pitmaster::clone($url, $path);
$head = $repo->head();
echo $head->message;
$branches = $repo->branches();
$files = $repo->status();
Darba koka izveide
Pēc pack saņemšanas Pitmaster izsauc $repo->checkout() noklusējuma atzaram. Tādējādi visi HEAD komita koka faili tiek ierakstīti darba direktorijā, bet indekss tiek veidots no koka ierakstiem, tāpēc status() uzrāda tīru darba koku.
Izgūšana
// public function fetch(string $remote = 'origin', ?int $depth = null): void
$repo->fetch(); // Fetch from 'origin'
$repo->fetch('upstream'); // Fetch from a named remote
$repo->fetch('origin', 1); // Shallow fetch
Izgūšanas darbplūsma
- Attālā URL nolasīšana: no
.git/config(remote.<name>.url) - Refs atklāšana: iegūst visu attālo refu pašreizējo stāvokli
- Vajadzīgo un esošo objektu saskaņošana:
- Vajadzīgie: attālie refi, kas atbilst
remote.<name>.fetchrefspeciem (pēc noklusējuma+refs/heads/*:refs/remotes/<name>/*) un kuru objektu lokāli trūkst (ja norādīts dziļums, tiek izgūti visi) - Esošie: katra lokālā refa galapunkta komits
- Vajadzīgie: attālie refi, kas atbilst
- Pack saņemšana: lejupielādē tikai jaunos objektus
- Pack ierakstīšana: saglabā mapē
.git/objects/pack/un izveido tā indeksu - Izsekošanas refu atjaunināšana: atjaunina
refs/remotes/<remote>/<branch>katram atbilstošajam attālajam atzaram un ieraksta ikvienu izziņoto taga refu. Taga objekti netiek pieprasīti atsevišķi, tāpēc jauns anotēts tags var tikt ierakstīts kā refs uz objektu, kas nav lejupielādēts (#24)
// Fetch is incremental: only downloads what's new
$repo->fetch();
// After fetching, merge or rebase to incorporate changes (use the full ref name)
$result = $repo->merge('refs/remotes/origin/main');
resolve() meklē nosaukumus kā refs/heads/<name>, refs/tags/<name> un pašu nosaukumu, tāpēc īsā forma origin/main netiek atrasta.
Pitmaster pieprasa plānos pack failus, kurus pagaidām nevar indeksēt (#16). Ja serveris atbild uz papildu izgūšanu ar plānu pack failu, fetch() izraisa PackParseException.
Jau atjaunināts
Ja visi objekti, uz kuriem norāda attālie refi, jau ir lokāli, pack netiek pieprasīts un fetch() atgriežas pēc refu atklāšanas. Šādā gadījumā netiek atjaunināti arī izsekošanas refi, pat ja attālie atzari pārvietoti uz komitiem, kas jums jau ir (#23).
Nosūtīšana
$repo->push(); // Push current branch to 'origin'
$repo->push('origin', 'main'); // Push a specific branch
$repo->push('upstream', 'feature'); // Push to a named remote
Nosūtīšanas darbplūsma
- Attālā URL nolasīšana: no
.git/config - Nosūtāmo izmaiņu noteikšana: atrisina lokālo atzaru līdz tā komita jaucējvērtībai
- Attālo refu atklāšana: iegūst attālā atzara pašreizējo stāvokli (lai aprēķinātu iepriekšējo jaucējvērtību)
- Pārbaude, vai atzars ir atvasināts: ja attālais atzars nav lokālā atzara priekštecis, pirms datu nosūtīšanas izraisa
RuntimeException("Push rejected: non-fast-forward update to <branch>") - Ref atjauninājuma nosūtīšana:
<old-hash> <new-hash> refs/heads/<branch> - Pack datu nosūtīšana: pack satur objektus, kas attālajam repozitorijam nepieciešami
- Rezultāta pārbaude: serveris katram refam atbild ar veiksmes vai kļūmes statusu
pre-push āķis tiek izpildīts pirms atjauninājuma nosūtīšanas, ja vien āķi nav atspējoti.
// Push the current branch
$repo->push();
// Push a specific branch to a specific remote
$repo->push('origin', 'feature/login');
Nosūtīšanas priekšnosacījumi
- Pašreizējam atzaram jābūt lokāli
- Attālajam repozitorijam jābūt konfigurētam ar URL
- Attālajam repozitorijam jāpieņem nosūtīšana (autentifikācija, atļaujas, nevirzīšanas uz priekšu politika)
Piespiedu nosūtīšana
Pitmaster nosūta veco jaucējvērtību no attālā repozitorija aktuālo refu paziņojuma, un push() lokāli noraida atjauninājumus, kas nav virzība uz priekšu. Lai pārrakstītu attālo atzaru, izmantojiet force-with-lease:
// Lease defaults to refs/remotes/<remote>/<branch>; pass an ObjectId to set it explicitly
$repo->pushForceWithLease('origin', 'main');
$repo->pushForceWithLease('origin', 'main', $repo->resolve('refs/remotes/origin/main'));
// Update several branches in one atomic request
$repo->pushAtomic('origin', ['main', 'release']);
// Make the remote mirror local refs (also deletes remote refs that no longer exist locally)
$repo->pushMirror('origin');
UploadPackClient (izgūšanas iekšējā darbība)
use Pitmaster\Protocol\UploadPackClient;
use Pitmaster\Protocol\SmartHttpClient;
$http = new SmartHttpClient();
$uploadPack = new UploadPackClient($http);
// Fetch with explicit wants and haves
$packData = $uploadPack->fetch($url, $wants, $haves);
Vajadzīgo un esošo objektu saskaņošana veido pkt-line pieprasījumu:
want <hash1> <capabilities>\n
want <hash2>\n
deepen <depth>\n (only when a depth is given)
0000
have <hash3>\n
have <hash4>\n
done\n
Serveris atbild ar apstiprinājumiem un pēc tam pack datiem (iespējams, side-band formātā).
ReceivePackClient (nosūtīšanas iekšējā darbība)
use Pitmaster\Protocol\ReceivePackClient;
use Pitmaster\Protocol\SmartHttpClient;
$http = new SmartHttpClient();
$receivePack = new ReceivePackClient($http);
$receivePack->push($url, [
[
'old' => $oldId, // Current remote hash (or zero hash for new branch)
'new' => $localId, // Local commit hash to push
'ref' => 'refs/heads/main',
],
], $packData);
Nosūtīšanas pieprasījuma formāts:
<old-hash> <new-hash> refs/heads/main\0<capabilities>\n
0000
PACK<pack data>
Kļūdu apstrāde
use Pitmaster\Exceptions\ProtocolException;
try {
$repo->fetch();
} catch (ProtocolException $e) {
// Network unreachable, auth failed, server error, etc.
echo $e->getMessage();
}
try {
$repo->push();
} catch (\RuntimeException $e) {
// Remote not configured, not on a branch, branch not found, non-fast-forward
echo $e->getMessage();
}
fetch() var izraisīt arī parastu RuntimeException (nezināms attālais repozitorijs, rokturis bez procesa) vai PackParseException (pack, ko nevar indeksēt). Gan ProtocolException, gan PackParseException manto no \RuntimeException, tāpēc, uztverot \RuntimeException, tiek aptverti visi šie gadījumi.
Attālā repozitorija konfigurācija
Attālie repozitoriji tiek glabāti mapē .git/config:
[remote "origin"]
url = https://github.com/user/repo.git
fetch = +refs/heads/*:refs/remotes/origin/*
Piekļuve, izmantojot konfigurācijas API:
$config = $repo->config();
$url = $config->get('remote.origin.url');
$config->set('remote.upstream.url', 'https://github.com/other/repo.git');
$config->set('remote.upstream.fetch', '+refs/heads/*:refs/remotes/upstream/*');
// set() changes the in-memory config only; write it to persist the change
$config->writeToFile($repo->commonGitDir() . '/config');
Pack dati nosūtīšanai
Pašlaik Pitmaster apkopo objektus, kas sasniedzami no nosūtāmajiem komitiem, bet nav sasniedzami no attālā repozitorija pašreizējiem refiem, un pack failā ieraksta tos kā bāzes objektus (bez delta saspiešanas). Funkcionāli tas ir pareizi, taču pack faili ir lielāki nekā git push. Delta saspiešanas pievienošana pack rakstīšanai ir plānots uzlabojums.