Klonuoti, gauti, siųsti
Pitmaster palaiko tris pagrindines git tinklo operacijas: klonavimą (pradinį atsisiuntimą), gavimą (papildomą atsisiuntimą) ir siuntimą (įkėlimą). SSH URL (ssh://..., user@host:path) naudoja SSH transportą; kiti URL naudoja išmanųjį HTTP, o klonuojant ir gaunant, nepavykus išmaniesiems mainams, pereinama prie paprastojo HTTP (žr. Protokolai).
Visos trys operacijos paleidžia tinklo transportus, todėl atidarius saugyklos nuorodą su ['processes' => false] arba Pitmaster::processFreeOptions(), jos sukelia RuntimeException.
Klonuoti
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);
Naujoje saugykloje visada naudojamas SHA-1. Jei klonuoti nepavyksta, o paskirties vieta anksčiau neegzistavo, iš dalies sukurtas katalogas pašalinamas.
Klonavimo eiga
- Inicijuoti: paskirties kelyje sukurti naują tuščią saugyklą
- Konfigūruoti nuotolinę saugyklą: išsaugoti URL kaip
remote.origin.urlir nustatyti gavimo refspec - Aptikti nuorodas: atlikti
GET /info/refs?service=git-upload-pack, kad sužinotumėte, ką turi serveris - Derėtis: siųsti
wanteilutes, skirtas visoms nuotolinėms nuorodoms (pašalinant pasikartojančias maišas) - Gauti paketą: atsisiųsti paketo failą su visais prašomais objektais
- Įrašyti paketą: išsaugoti paketo failą į
.git/objects/pack/ - Indeksuoti paketą: sugeneruoti
.idxfailą greitoms paieškoms - Nustatyti nuorodas: sukurti nuotolinio sekimo šakas (
refs/remotes/origin/*) ir žymas - Nustatyti HEAD: nukreipti HEAD į numatytąją šaką (iš serverio galimybės
symref=HEAD:...arba įrefs/heads/main, jei serveris jos nenurodo) ir nustatytibranch.<name>.remotebeibranch.<name>.merge - Išimti: išimti šią šaką; taip įrašomas darbinis medis ir indeksas
Galutinio išėmimo klaidos pagaunamos ir ignoruojamos, todėl klonavimas gali baigtis tuščiu arba daliniu darbiniu medžiu (#19).
$repo = Pitmaster::clone($url, $path);
$head = $repo->head();
echo $head->message;
$branches = $repo->branches();
$files = $repo->status();
Darbinio medžio sukūrimas
Gavusi paketą, Pitmaster iškviečia $repo->checkout() numatytajai šakai. Taip visi HEAD įrašo medžio failai įrašomi į darbinį katalogą, o indeksas sudaromas iš medžio įrašų, todėl status() nurodo, kad darbinis medis švarus.
Gauti
// 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
Gavimo eiga
- Skaityti nuotolinės saugyklos URL: iš
.git/config(remote.<name>.url) - Aptikti nuorodas: gauti dabartinę visų nuotolinių nuorodų būseną
- Derėtis dėl norimų ir turimų objektų:
- Norimi: nuotolinės nuorodos, atitinkančios
remote.<name>.fetchrefspec'us (pagal numatytuosius nustatymus+refs/heads/*:refs/remotes/<name>/*), kurių objektų nėra vietoje (jei nurodytas gylis, įtraukiamos visos) - Turimi: visų vietinių nuorodų viršūnės
- Norimi: nuotolinės nuorodos, atitinkančios
- Gauti paketą: atsisiųsti tik naujus objektus
- Įrašyti paketą: išsaugoti į
.git/objects/pack/ir sudaryti jo indeksą - Atnaujinti sekimo nuorodas: atnaujinti kiekvieną atitinkančios nuotolinės šakos
refs/remotes/<remote>/<branch>nuorodą ir įrašyti kiekvieną paskelbtą žymos nuorodą. Žymų objektų atskirai neprašoma, todėl nauja anotuota žyma gali būti įrašyta kaip nuoroda į neatsisiųstą objektą (#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() pavadinimų ieško kaip refs/heads/<name>, refs/tags/<name> ir kaip paties pavadinimo, todėl trumpasis variantas origin/main nerandamas.
Pitmaster prašo plonų paketų, kurių kol kas negali indeksuoti (#16). Jei serveris atsako į papildomą gavimo užklausą plonu paketu, fetch() sukelia PackParseException.
Jau atnaujinta
Jei visi objektai, į kuriuos nurodo nuotolinės nuorodos, jau yra vietoje, paketo neprašoma, o fetch() baigia darbą aptikusi nuorodas. Tokiu atveju sekimo nuorodos taip pat neatnaujinamos, net jei nuotolinės šakos pasikeitė į jau turimus įrašus (#23).
Siųsti
$repo->push(); // Push current branch to 'origin'
$repo->push('origin', 'main'); // Push a specific branch
$repo->push('upstream', 'feature'); // Push to a named remote
Siuntimo eiga
- Skaityti nuotolinės saugyklos URL: iš
.git/config - Nustatyti, ką siųsti: išspręsti vietinę šaką iki jos įrašo maišos
- Aptikti nuotolines nuorodas: gauti dabartinę nuotolinės šakos būseną (senajai maišai apskaičiuoti)
- Patikrinti, ar galima perkelti pirmyn: jei nuotolinė šaka nėra vietinės šakos protėvis, prieš siunčiant ką nors sukeliama
RuntimeException("Push rejected: non-fast-forward update to <branch>") - Siųsti nuorodos atnaujinimą:
<old-hash> <new-hash> refs/heads/<branch> - Siųsti paketo duomenis: paketas su objektais, kurių reikia nuotolinei saugyklai
- Patikrinti rezultatą: serveris pateikia kiekvienos nuorodos sėkmės arba klaidos būseną
pre-push hook vykdomas prieš siunčiant atnaujinimą, nebent hook išjungti.
// Push the current branch
$repo->push();
// Push a specific branch to a specific remote
$repo->push('origin', 'feature/login');
Siuntimo reikalavimai
- Dabartinė šaka turi egzistuoti vietoje
- Nuotolinei saugyklai turi būti sukonfigūruotas URL
- Nuotolinė saugykla turi priimti siuntimą (autentifikavimas, leidimai, politika dėl neperkeliamų pirmyn pakeitimų)
Priverstinis siuntimas
Pitmaster siunčia senąją maišą iš tuo metu pateikiamos nuotolinės nuorodos reklamos, o push() vietoje atmeta neperkeliamus pirmyn atnaujinimus. Norėdami perrašyti nuotolinę šaką, naudokite 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 (gavimo vidinė veikimo dalis)
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);
Norimų ir turimų objektų derinimo metu sudaroma pkt-line užklausa:
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 atsako patvirtinimais, o tada pateikia paketo duomenis (galbūt įvyniotus į side-band).
ReceivePackClient (siuntimo vidinė veikimo dalis)
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);
Siuntimo užklausos formatas:
<old-hash> <new-hash> refs/heads/main\0<capabilities>\n
0000
PACK<pack data>
Klaidų tvarkymas
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() taip pat gali sukelti paprastą RuntimeException (nežinoma nuotolinė saugykla, nuoroda be procesų) arba PackParseException (paketas, kurio negalima indeksuoti). Tiek ProtocolException, tiek PackParseException išplečia \RuntimeException, todėl pagavę \RuntimeException apimsite visas šias klaidas.
Nuotolinės saugyklos konfigūracija
Nuotolinės saugyklos įrašomos į .git/config:
[remote "origin"]
url = https://github.com/user/repo.git
fetch = +refs/heads/*:refs/remotes/origin/*
Pasiekiama per konfigūracijos 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');
Paketo duomenys siuntimui
Šiuo metu Pitmaster surenka objektus, pasiekiamus iš siunčiamų įrašų, kurių nepasiekia dabartinės nuotolinės nuorodos, ir įrašo juos į paketą kaip bazinius objektus (be deltų glaudinimo). Tai veikia teisingai, tačiau paketai būna didesni nei naudojant git push. Deltų glaudinimas rašant paketus numatytas kaip būsimas optimizavimas.