Git
Chapters ▾ 2nd Edition

A2.3 Appendix B: Proqramlara Git Daxil Etmək - JGit

JGit

Bir Java proqramı daxilində Git istifadə etmək istəyirsinizsə, JGit adlı tam özəllikli Git kitabxanası var. JGit, Git’in yerli olaraq Java dilində yazılmış və Java cəmiyyətində geniş istifadə edilən nisbətən tam bir tətbiqdir. JGit layihəsi Eclipse çətirinin altındadır və evinə https://www.eclipse.org/jgit/ ünvanından baxmaq olar.

Quraşdırılması

Layihənizi JGit ilə bağlamaq və ona qarşı kod yazmağa başlamağın bir sıra yolu var. Yəqin ki, ən asan olanı Maven istifadə etməkdir - inteqrasiya pom.xml faylınızdakı <dependencies>` etiketinə aşağıdakı snippet əlavə etməklə həyata keçirilir:

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

Versiya çox güman ki, bunu oxuduğunuz zaman inkişaf etmiş olacaq; Yenilənmiş depo məlumatları üçünhttps://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit[] bölməsinə baxın. Bu addım atıldıqdan sonra, Maven avtomatik olaraq ehtiyacınız olan JGit kitabxanalarını əldə edəcək və istifadə edəcəkdir.

İkili bağlantıları özünüz idarə etmək istəsəniz, əvvəlcədən qurulmuş JGit binarları https://www.eclipse.org/jgit/download saytından əldə edilə bilər. Bu kimi bir əmr işlədərək onları layihənizdə qura bilərsiniz:

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

JGit, API-nin iki əsas səviyyəsinə malikdir: plumbing and porcelain. Bunların terminologiyası Git’in özündən irəli gəlir və JGit təxminən eyni bölgələrə bölünür: porcelain API’ləri ümumi istifadəçi səviyyəli hərəkətlər üçün əlverişli bir yerdir (normal istifadəçinin Git əmr sətrini istifadə edəcəyi şeylər), plumbing API’ləri isə birbaşa aşağı səviyyəli depo obyektləri ilə qarşılıqlı əlaqə yaratmaq üçündür.

Əksər JGit sessiyalarının başlanğıc nöqtəsi Repository sinifidir və etmək istədiyiniz ilk şey bunun nümunəsini yaratmaqdır. Bir fayl sistemi əsaslı depo üçün (bəli, JGit digər saxlama modellərinə imkan verir), bu, FileRepositoryBuilder istifadə edərək həyata keçirilir:

// Create a new repository
Repository newlyCreatedRepo = FileRepositoryBuilder.create(
    new File("/tmp/new_repo/.git"));
newlyCreatedRepo.create();

// Open an existing repository
Repository existingRepo = new FileRepositoryBuilder()
    .setGitDir(new File("my_repo/.git"))
    .build();

Proqramın, Git deposunu tapmaq üçün lazım olan hər şeyi təmin etmək üçün proqramınızın harada olduğunu dəqiq bilməməsindən asılı olmayaraq, səlis bir API var. Ətraf mühit dəyişənlərindən (.readEnvironment())istifadə edə bilər, iş qovluğundakı bir yerdən başlayaraq (.setWorkTree(…).findGitDir()) axtarır və ya yuxarıdakı kimi bilinən .git qovluğunu aça bilər.

Bir Repository nümunəsinə sahib olduqda, onunla hər şeyi edə bilərsiniz. Bu da sürətli bir nümunə:

// 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");

Burada çox şey var, buna görə hər bir hissədən keçək. Birinci sətir master referansına bir işarə alır. JGit avtomatik olaraq refs/heads/master-də yaşayan actual master ref-ni tutur və arayış haqqında məlumat almağa imkan verən bir obyekti qaytarır.

Ad (.getName()) və ya birbaşa istinadın hədəf obyekti (.getObjectId()) və ya simvolik bir ref (.getTarget()) ilə göstərilən istinad əldə edə bilərsiniz. Ref obyektləri etiket reflərini və obyektlərini təmsil etmək üçün də istifadə olunur, beləliklə etiketin “peeled” olub olmadığını soruşa bilərsiniz, yəni etiket obyektlərinin bir (potensial uzun) sətrinin son hədəfinə işarə edir.

İkinci sətir, ObjectId nümunəsi olaraq qaytarılmış olan master referansının hədəfini alır. ObjectId, Git’in obyekt bazasında mövcud ola biləcək və ya olmaya bilən bir obyektin SHA-1 hash-ını təmsil edir.

Üçüncü sətir oxşardır, lakin JGit-in yenidən təhlil sintaksisini necə işlədiyini göstərir (bu barədə daha çox məlumat üçün Branch Referansları); Git’in başa düşdüyü hər hansı bir obyekt göstəricisini keçə bilərsiniz və JGit həmin obyekt üçün ya etibarlı bir ObjectId ya da null qaytaracaq.

Növbəti iki sətirdə bir obyektin kontektinin necə yüklənəcəyi göstərilir. Bu nümunədə obyektin məzmunu birbaşa stdout-a axın etmək üçün ObjectLoader.copyTo()-ı çağırırıq, lakin ObjectLoader-də bir obyektin növünü və ölçüsünü oxumaq, həmçinin bayt massivi kimi qaytarmaq üçün metodlar var.

Böyük obyektlər üçün (harada .isLarge() true`qayıdır), hamısını bir anda yaddaşına çəkmədən oxuya bilən InputStream-ə bənzər bir obyekt əldə etmək üçün `.openStream() adlandıra bilərsiniz.

Sonrakı bir neçə sətir yeni bir branch yaratmaq üçün nə lazım olduğunu göstərir. Bir RefUpdate nümunəsi yaradırıq, bəzi parametrləri konfiqurasiya edirik və dəyişikliyi tetiklemek üçün .update() çağırırıq. Bunu birbaşa izləmək eyni branch-ı silmək üçün koddur. Qeyd edək ki, bunun üçün .setForceUpdate(true) tələb olunur; əks təqdirdə .delete() çağırışı REJECTED qaytaracaq və heç bir şey olmayacaq.

Son nümunə, Git konfiqurasiya sənədlərindən user.name dəyərinin necə alınacağını göstərir. Bu Config misalı əvvəllər yerli konfiqurasiya üçün açdığımız depodan istifadə edir, lakin avtomatik olaraq qlobal və sistem konfiqurasiya fayllarını aşkarlayacaq və onlardan dəyərləri də oxuyacaqdır.

Bu, tam plumbing API’sinin yalnız kiçik bir nümunəsidir; daha çox metod və sinif mövcuddur. Burada JGit-in istisnaların tətbiqi ilə edilən səhvləri necə həll etməsi göstərilmir. JGit API-ləri bəzən standart Java istisnalarını (məsələn, IOException) atırlar, lakin JGit-ə məxsus istisna növləri də var (məsələn, NoRemoteRepositoryException, CorruptObjectException`və `NoMergeBaseException)

Porcelain

Plumbing API-ləri kifayət qədər tamamlanmışdır, lakin indeksə bir fayl əlavə etmək və ya yeni bir commit götürmək kimi ümumi hədəflərə çatmaq üçün onları bir-birinə bağlamaq çətin ola bilər. JGit bu işdə kömək etmək üçün daha yüksək səviyyəli API dəsti təmin edir və bu API-lərə giriş nöqtəsi Git sinifidir:

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

Git sinfi, olduqca mürəkkəb bir davranış qurmaq üçün istifadə edilə bilən yüksək səviyyəli builder stil metodlarından ibarətdir. Bir nümunəyə baxaq - git ls-remote kimi bir şey edək:

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());
}

Bu, Git sinfi ilə ümumi bir nümunədir; metodlar zəncirvari metod çağırışlarını parametrləri təyin etməyə imkan verən bir əmr obyektini qaytarır, bunlar .call(). Bu vəziyyətdə origin remote-dan etiketlər istəyirik, head-ləri yox. Doğrulama üçün bir CredentialsProvider obyektinin istifadəsinə də diqqət yetirin.

Git sinfi vasitəsilə bir çox digər əmrlər mövcuddur, lakin add, blame, commit, clean, push, rebase, revert, və reset-lə məhdudlaşmır.

Əlavə Oxu

Bu JGit-in tam imkanlarından yalnız kiçik bir nümunədir. Əgər maraqlanırsınızsa və daha çox öyrənmək istəyirsinizsə, məlumat və ilham axtaracaq yeriniz budur:

scroll-to-top