Git
Chapters ▾ 2nd Edition

A2.3 Appendix B: Pag-embed ng Git sa iyong Mga Aplikasyon - JGit

JGit

Kung nais mong gamitin ang Git mula sa loob ng isang programa ng Java, mayroong isang ganap na itinatampok na library ng Git na tinatawag na JGit. Ang JGit ay isang ganap na buong-tampok na pagsasagawa ng Git na natibong nakasulat sa Java, at malawakang ginagamit sa komunidad ng Java. Ang proyektong JGit ay nasa ilalim ng Eclipse umbrella, at ang pinanggalingan nito ay matatagpuan sa http://www.eclipse.org/jgit.

Pagkuha ng Set Up

Mayroong ilang mga paraan upang ikonekta ang iyong proyekto sa JGit at simulan ang pagsulat ng code laban dito. Marahil ang pinakamadali ay ang paggamit ng Maven - ang pagsasama ay gagawin sa pamamagitan ng pagdaragdag ng sumusunod na snippet sa <dependencies> na tag sa iyong pom.xml na file:

<dependency>
    <groupId>org.eclipse.jgit</groupId>
    <artifactId>org.eclipse.jgit</artifactId>
    <version>3.5.0.201409260305-r</version>
</dependency>

Ang bersyon ay malamang mas pinahusay sa oras na nabasa mo ito; suriin ang http://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit para sa na-update na impormasyon ng repositoryo. Kapag ang hakbang na ito ay tapos na, ang Maven ay awtomatikong makuha at gamitin ang mga JGit library na kakailanganin mo.

Kung mas gugustuhin mong pamahalaan ang mga binary na kinakailangan nang ikaw lang, ang mga pre-built JGit binary ay makukuha mula sa http://www.eclipse.org/jgit/download. Maaari kang bumuo ng mga ito sa iyong proyekto sa pamamagitan ng pagpapatakbo ng isang command tulad nito:

javac -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App.java
java -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App

Plumbing

Ang JGit ay may dalawang pangunahing antas ng API: plumbing at porcelain. Ang terminolohiya ng mga ito ay nagmula sa Git mismo, at ang JGit ay nahahati sa halos parehong mga uri ng mga lugar: ang mga porcelain API ay isang madaling gamitin na front-end para sa karaniwang mga pagkilos sa antas ng gumagamit (ang mga uri ng mga bagay na ginagamit ng isang normal na gumagamit na kagamitan para sa command-line na Git), habang ang mga plumbing API ay direktang nakikipag-ugnayan sa mga mababang antas ng mga bagay sa repositoryo.

Ang panimulang punto para sa karamihan ng mga sesyon ng JGit ay ang Repository na class, at ang unang bagay na gusto mong gawin ay lumikha ng isang halimbawa nito. Para sa filesystem-based na repositoryo (oo, pinapayagan ng JGit para sa iba pang mga modelo ng imbakan), ito ay gagawin gamit ang FileRepositoryBuilder:

// Paglikha ng bagong repositoryo
Repository newlyCreatedRepo = FileRepositoryBuilder.create(
    new File("/tmp/new_repo/.git"));
newlyCreatedRepo.create();

// Pagbukas ng umiiral na repositoryo
Repository existingRepo = new FileRepositoryBuilder()
    .setGitDir(new File("my_repo/.git"))
    .build();

Ang tagagawa ay may matatas na API para sa pagbibigay ng lahat ng mga bagay na kailangan nito upang makahanap ng isang Git repositoryo, kahit alam man o hindi ang iyong programa kung saan mismo matatagpuan ito. Maaari itong gumamit ng mga environment variable (.readEnvironment()), magsimula sa isang lugar sa gumagana na direktoryo at paghahanap (.setWorkTree(...).findGitDir()), o buksan lamang ang isang nakatalang direktoryo ng .git .

Sa sandaling mayroon kang isang halimbawa na `Repository, maaari mong gawin ang lahat ng mga uri ng mga bagay dito. Narito ang isang mabilis na sampling:

// Get a reference
Ref master = repo.getRef("master");

// Get the object the reference points to
ObjectId masterTip = master.getObjectId();

// Rev-parse
ObjectId obj = repo.resolve("HEAD^{tree}");

// Load raw object contents
ObjectLoader loader = repo.open(masterTip);
loader.copyTo(System.out);

// Create a branch
RefUpdate createBranch1 = repo.updateRef("refs/heads/branch1");
createBranch1.setNewObjectId(masterTip);
createBranch1.update();

// Delete a branch
RefUpdate deleteBranch1 = repo.updateRef("refs/heads/branch1");
deleteBranch1.setForceUpdate(true);
deleteBranch1.delete();

// Config
Config cfg = repo.getConfig();
String name = cfg.getString("user", null, "name");

Mayroong medyo kaunting ginawa dito, kaya’t hayaan natin ito nang isang seksyon sa isang pagkakataon.

Ang unang linya ay nakakakuha ng isang pointer sa master reference. Ang JGit ay awtomatikong kumuha sa actual master ref, na nasa refs/head/master, at nagbalik ng isang bagay na nagbibigay-daan sa iyo makuha ang impormasyon tungkol sa reference. Maaari mong makuha ang pangalan (.getName()), at alinman sa target na bagay ng direktang ini-reference (.getObjectId()) o ang reference na itinuturo ng isang symbolic ref (.getTarget()). Ang mga ref na bagay ay ginagamit din upang kumatawan sa mga ref ng mga tag at mga bagay, upang maaari mong tanungin kung ang tag ay "peeled," na nangangahulugan na tumuturo ito sa huling target ng isang (potensyal na mahaba) na string ng mga bagay ng tag.

Ang ikalawang linya ay nakakakuha ng target ng master reference, na ibinalik bilang isang ObjectId na instance. Ang ObjectId ay kumakatawan sa SHA-1 hash ng bagay, na maaaring o hindi maaaring umiiral sa database ng Git’s na bagay. Ang ikatlong linya ay pareho, ngunit nagpapakita kung paano pinangangasiwaan ng JGit ang rev-parse na syntax (para sa higit pa nito, tingnan ang Mga Reperensiya ng Branch); maaari mong ipasa ang anumang specifier ng bagay na nauunawaan ng Git, at ibabalik ng JGit alinman sa isang balidong ObjectId para sa bagay na iyon, o null.

Ang susunod na dalawang linya ay nagpapakita kung paano i-load ang mga sariwang nilalaman ng isang bagay. Sa halimbawang ito, tinatawagan namin ang ObjectLoader.copyTo() upang i-stream ang mga nilalaman ng bagay direkta sa stdout, ngunit ang ObjectLoader ay mayroon ding mga paraan upang mabasa ang uri at laki ng isang bagay, pati na rin ibalik ito bilang isang byte array. Para sa mga malalaking bagay (kung saan ang .isLarge() ay nagbabalik ng true), maaari kang tumawag sa .openStream() upang makakuha ng InputStream-like na bagay na makakapagbasa ng raw na datos na bagay nang hindi naibabalik ang lahat ng ito sa memorya nang sabay-sabay.

Ang susunod na mga linya ay nagpapakita kung ano ang kinakailangan upang lumikha ng isang bagong branch. Gumawa kami ng isang instance ng RefUpdate, ikompigura ang ilang mga parameter, at tumawag sa .update() upang ma-trigger ang pagbabago. Ang direktang pagsunod nito ay ang code na tanggalin ang parehong branch na iyon. Tandaan na ang .setForceUpdate(true) ay kinakailangan para gumana ito; kung hindi, ang .delete() na tawag ay babalik sa REJECTED, at walang mangyayari.

Ang huling halimbawa ay nagpapakita kung paano makuha ang halaga ng user.name mula sa mga file ng kompigurasyon ng Git. Halimbawa ng Config na ito ay gumagamit ng repositoryo na binuksan namin kanina para sa lokal na kompigurasyon, ngunit awtomatikong makita ang mga file sa kompigurasyon ng global at system at basahin rin ang mga halaga mula sa mga ito.

Ito ay isa lamang na maliit na halimbawa ng buong plumbing API; mayroong maraming iba pang mga pamamaraan at mga class na magagamit. Hindi rin ipinapakita dito ang paraan ng JGit na humahawak ng mga error, na kung saan ay sa pamamagitan ng paggamit ng mga eksepsiyon. Kung minsan ang JGit API ay nagtatapon ng karaniwang mga Java exception (tulad ng IOException), ngunit mayroong isang host ng JGit-specific exception na mga uri na ibinigay din (tulad ng NoRemoteRepositoryException, CorruptObjectException, at NoMergeBaseException).

Porcelain

Ang mga plumbing API sa halip ay kumpleto, ngunit maaari itong maging masalimuot sa string na sama-sama upang makamit ang mga karaniwang layunin, tulad ng pagdaragdag ng isang file sa index, o paggawa ng isang bagong commit. Ang JGit ay nagbibigay ng isang masmataas na antas na hanay ng mga API upang makatulong sa ito, at ang entry point sa mga API na ito ay ang Git class:

Repository repo;
// construct repo...
Git git = new Git(repo);

Ang class ng Git ay may magandang hanay ng mga pamamaraan ng mataas na antas na builder-style na maaaring magamit upang makagawa ng ilang medyo komplikadong kilos. Tingnan natin ang isang halimbawa - paggawa ng ilang bagay tulad ng git ls-remote:

CredentialsProvider cp = new UsernamePasswordCredentialsProvider("username", "p4ssw0rd");
Collection<Ref> remoteRefs = git.lsRemote()
    .setCredentialsProvider(cp)
    .setRemote("origin")
    .setTags(true)
    .setHeads(false)
    .call();
for (Ref ref : remoteRefs) {
    System.out.println(ref.getName() + " -> " + ref.getObjectId().name());
}

Ito ay isang pangkaraniwang anyo sa Git class; ang mga pamamaraan ay bumalik ng isang command na bagay na nagpapahintulot sa iyo ng sunod-sunod ng mga tawag na pamamaraan upang magtakda ng mga parameter, na kung saan ay isasagawa kapag tumawag ka ng .call(). Sa kasong ito, hinihingi namin ang origin remote para sa mga tag, ngunit hindi mga head. Tandaan din ang paggamit ng bagay na CredentialsProvider para sa pagpapatunay.

Maraming iba pang mga utos ang magagamit sa Git class, kabilang ngunit hindi limitado sa add,blame, commit,clean, push,rebase, revert, at reset.

Karagdagang Pagbabasa

Ito ay isang maliit na sampling lamang ng buong kakayahan ng JGit. Kung interesado ka at nais mong matuto nang higit pa, narito kung saan hahanapin ang impormasyon at inspirasyon: