Kloonaa, nouda, lähetä
Pitmaster tukee kolmea keskeistä git-verkkotoimintoa: kloonausta (ensimmäinen lataus), noutoa (lisälataus) ja lähetystä (lataus palvelimelle). SSH URL-osoitteissa (ssh://..., user@host:path) käytetään SSH-siirtoa; muissa URL-osoitteissa käytetään älykästä HTTP-protokollaa, ja kloonaus ja nouto siirtyvät tarvittaessa yksinkertaiseen HTTP-protokollaan, jos älykäs tiedonsiirto epäonnistuu (katso Protokollat).
Kaikki kolme käynnistävät verkkosiirron, joten ne aiheuttavat virheen RuntimeException, jos kahva on avattu valitsimella ['processes' => false] tai Pitmaster::processFreeOptions().
Kloonaus
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);
Uusi tietovarasto käyttää aina SHA-1. Jos kloonaus epäonnistuu eikä kohdetta ollut ennestään, osittain luotu hakemisto poistetaan.
Kloonauksen kulku
- Alusta: luo tyhjä tietovarasto kohdepolkuun
- Määritä etävarasto: tallenna URL muodossa
remote.origin.urlja määritä noudon refspec - Selvitä viitteet:
GET /info/refs?service=git-upload-packselvittääksesi, mitä palvelimella on - Neuvottele: lähetä
want-rivit kaikista etäviitteistä (hashin mukaan deduplikoituna) - Vastaanota paketti: lataa pakettitiedosto, joka sisältää kaikki pyydetyt objektit
- Kirjoita paketti: tallenna pakettitiedosto kohteeseen
.git/objects/pack/ - Indeksoi paketti: luo
.idx-tiedosto nopeita hakuja varten - Määritä viitteet: luo etähaaroja seuraavat haarat (
refs/remotes/origin/*) ja tunnisteet - Aseta HEAD: kohdista HEAD oletushaaraan (palvelimen
symref=HEAD:...-ominaisuuden mukaan tai arvoonrefs/heads/main, jos palvelin ei ilmoita sitä) ja asetabranch.<name>.remotejabranch.<name>.merge - Ota käyttöön: ota haara käyttöön, jolloin työhakemisto ja indeksi kirjoitetaan
Viimeisen käyttöönoton virheet ohitetaan, joten kloonaus voi palauttaa tyhjän tai osittaisen työhakemiston (#19).
$repo = Pitmaster::clone($url, $path);
$head = $repo->head();
echo $head->message;
$branches = $repo->branches();
$files = $repo->status();
Työhakemiston luonti
Pakettitiedoston vastaanottamisen jälkeen Pitmaster kutsuu toimintoa $repo->checkout() oletushaaralle. Se kirjoittaa HEAD-commitin puun kaikki tiedostot työhakemistoon ja muodostaa indeksin puun merkinnöistä, joten status() ilmoittaa työhakemiston olevan puhdas.
Nouto
// 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
Noudon kulku
- Lue etävaraston URL: kohteesta
.git/config(remote.<name>.url) - Selvitä viitteet: hae kaikkien etäviitteiden nykytila
- Neuvottele halutuista ja olemassa olevista objekteista:
- Halutut: etäviitteet, jotka vastaavat
remote.<name>.fetch-refspec-määrityksiä (oletuksena+refs/heads/*:refs/remotes/<name>/*) ja joiden objekteja ei ole paikallisesti (kaikki, jos syvyys on määritetty) - Olemassa olevat: jokaisen paikallisen viitteen kärki
- Halutut: etäviitteet, jotka vastaavat
- Vastaanota paketti: lataa vain uudet objektit
- Kirjoita paketti: tallenna kohteeseen
.git/objects/pack/ja luo sen indeksi - Päivitä seurantaviitteet: päivitä
refs/remotes/<remote>/<branch>jokaista vastaavaa etähaaraa varten ja kirjoita jokainen ilmoitettu tunnisteviite. Tunnisteobjekteja ei pyydetä erikseen, joten uusi selitetty tunniste voidaan kirjoittaa viitteeksi objektiin, jota ei ladattu (#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() etsii nimiä muodoissa refs/heads/<name>, refs/tags/<name> ja nimi sellaisenaan, joten lyhyttä muotoa origin/main ei löydy.
Pitmaster pyytää ohuita paketteja, joita se ei vielä osaa indeksoida (#16). Jos palvelin vastaa lisänoutoon ohuella paketilla, fetch() aiheuttaa virheen PackParseException.
Ajantasalla
Jos kaikki etäviitteiden osoittamat objektit ovat jo paikallisesti, pakettia ei pyydetä ja fetch() palautuu viitteiden selvittämisen jälkeen. Tällöin seurantaviitteitä ei myöskään päivitetä, vaikka etähaarat olisivat siirtyneet committeihin, jotka sinulla jo on (#23).
Lähetys
$repo->push(); // Push current branch to 'origin'
$repo->push('origin', 'main'); // Push a specific branch
$repo->push('upstream', 'feature'); // Push to a named remote
Lähetyksen kulku
- Lue etävaraston URL: kohteesta
.git/config - Määritä lähetettävät tiedot: selvitä paikallisen haaran commit-hash
- Selvitä etäviitteet: hae etähaaran nykytila (vanhan hashin laskemista varten)
- Tarkista pikasiirto: jos etähaara ei ole paikallisen haaran edeltäjä, aiheuta virhe
RuntimeException("Push rejected: non-fast-forward update to <branch>")ennen lähetystä - Lähetä viitepäivitys:
<old-hash> <new-hash> refs/heads/<branch> - Lähetä pakettitiedot: paketti, joka sisältää etävaraston tarvitsemat objektit
- Tarkista tulos: palvelin ilmoittaa onnistumisesta tai epäonnistumisesta viitekohtaisesti
pre-push-koukku suoritetaan ennen päivityksen lähettämistä, ellei koukkuja ole poistettu käytöstä.
// Push the current branch
$repo->push();
// Push a specific branch to a specific remote
$repo->push('origin', 'feature/login');
Lähetyksen vaatimukset
- Nykyisen haaran on oltava olemassa paikallisesti
- Etävarasto on määritettävä valitsimella URL
- Etävaraston on hyväksyttävä lähetys (todennus, käyttöoikeudet, pikasiirron estävät käytännöt)
Pakotettu lähetys
Pitmaster lähettää etävaraston aktiivisten viitteiden ilmoituksesta saadun vanhan hashin, ja push() estää paikallisesti muut kuin pikasiirrot. Voit korvata etähaaran käyttämällä force-with-lease-toimintoa:
// 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 (noudon sisäinen toteutus)
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);
Haluttujen ja olemassa olevien objektien neuvottelussa muodostetaan pkt-line-pyyntö:
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
Palvelin vastaa kuittauksilla ja lähettää sitten pakettitiedot (mahdollisesti side-band-käärittyinä).
ReceivePackClient (lähetyksen sisäinen toteutus)
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);
Lähetyspyynnön muoto:
<old-hash> <new-hash> refs/heads/main\0<capabilities>\n
0000
PACK<pack data>
Virheenkäsittely
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() voi aiheuttaa myös tavallisen RuntimeException-virheen (tuntematon etävarasto, kahva ei käynnistä prosesseja) tai PackParseException-virheen (pakettia ei voi indeksoida). Sekä ProtocolException että PackParseException laajentavat \RuntimeException-luokkaa, joten \RuntimeException kattaa ne kaikki.
Etävaraston määritys
Etävarastot tallennetaan kohteeseen .git/config:
[remote "origin"]
url = https://github.com/user/repo.git
fetch = +refs/heads/*:refs/remotes/origin/*
Määritykseen pääsee API-asetuksen kautta:
$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');
Lähetyksen pakettitiedot
Tällä hetkellä Pitmaster kerää lähetettävien commitien kautta saavutettavat objektit, jotka eivät ole saavutettavissa etävaraston nykyisistä viitteistä, ja kirjoittaa ne pakettiin perusobjekteina (ilman delta-pakkausta). Tämä toimii oikein, mutta tuottaa suurempia paketteja kuin git push. Delta-pakkaus paketteja kirjoitettaessa on suunnitteilla oleva optimointi.