Git
Chapters ▾ 2nd Edition

A2.3 Додатак B: Уграђивање програма Гит у ваше апликације - JGit

JGit

Ако Гит желите да користите из Јава програма, постоји Гит библиотека са комплетним могућностима, пос називом JGit. JGit је релативно комплетна Гит имплементација написана природно на Јави и доста је користи у Јава заједници. JGit пројекат је под Eclipse кишобраном и његова почетна страница се налази на адреси https://www.eclipse.org/jgit.

Почетно подешавање

Постоји већи број начина да повежете свој пројекат са JGit и почнете да пишете кôд уз њега. Вероватно најлакши је да користите Maven – интеграција се постиже додавањем следећег исечка у <dependencies> ознаку у pom.xml фајл:

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

У време када ово читате, version је највероватније мало напредовала; проверите https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit да погледате ажуриране информације о репозиторијуму. Када се изврши овај корак, Maven ће аутоматски да преузме и употреби JGit библиотеке које су вам потребне.

Ако радије сами желите да управљате зависностима, на адреси https://www.eclipse.org/jgit/download можете пронаћи већ изграђене JGit бинарне фајлове. На следећи начин можете да их уградите у свој пројекат:

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

Водовод

JGit поседује два основна API нивоа: водовод и порцелан. Ова терминологија долази из самог програма Гит, а JGit је грубо говорећи подељен на исте врсте области: порцелан API су пријатни приступ уобичајеним акцијама на корисничком нивоу (она врста ствари коју би обични корисник обављао користећи Гит алат из команде линије), док су водоводни API за директну интеракцију са објектима репозиторијума ниског нивоа.

Почетна тачка већине JGit сесија је Repository класа и прва ствар коју желите да урадите је да креирате њену инстанцу. За репозиторијум базиран на фајл систему (тако је, JGit омогућава и друге моделе складиштења), ово се постиже употребом FileRepositoryBuilder:

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

Изграђивач поседује течни API којим достављање свих ствари које су му потребне да пронађе Гит репозиторијум, без обзира на то да ли ваш програм зна или не где се он тачно налази. Може да користи променљиве окружења (.readEnvironment()), крене са места у радном директоријуму и претражује (.setWorkTree(…).findGitDir()), или једноставно отвори познати .git директоријум као што је приказано изнад.

Када дођете до Repository инстанце, можете да урадите свашта са њом. Ево у кратким цртама неких могућности:

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

Овде се свашта дешава, па хајде да опишемо одељке, један по један.

Прва линија добавља показивач на master референцу. JGit аутоматски прибавља стварну мастер референцу која се налази у refs/heads/master, и враћа објекат који вам омогућава да дођете до информација у вези референце. Можете да добијете име (.getName()), било циљни објекат директне референце (.getObjectId()) или референцу на коју показује симболичка референца (.getTarget()). Ref објекти се користе и за представљање референци ознака и објеката, тако да можете питати да ли је ознака „ољуштена”, што значи да показује на крајњи циљ (потенцијално дугачког) стринга објеката ознака.

Друга линија враћа циљ master референце који се добија као ObjectId инстанца. ObjectId представља SHA-1 хеш објекта који може а не мора да постоји у Гит бази објеката. Трећа линија је слична, али приказује како JGit обрађује rev-parse синтаксу (за више о овоме, погледајте Референце грана); можете да проследите било који спецификатор објекта који програм Гит разуме, и JGit ће вратити или важећи ObjectId за тај објекат, или null.

Наредне две линије показују како да се учита сирови садржај неког објекта. У овом примеру позивамо ObjectLoader.copyTo() да стримује садржај објекта директно на stdout, али ObjectLoader такође има методе за читање типа и величине објекта, као да га врати као низ бајтова. За велике објекте (где .isLarge() враћа true), можете да позовете .openStream() и добијете објекат који личи на InputStream и који може да прочита податке сировог објекта без потребе да га целог довлачи у меморију.

Наредних неколико линија приказују шта је потребно да се креира нова грана. Креирамо RefUpdate инстанцу, конфигуришемо неке параметре, па позовемо .update() да окинемо измену. Непосредно затим следи кôд за брисање те исте гране. Приметите да је неопходно .setForceUpdate(true) да би ово радило; у супротном ће .delete() позив да врату REJECTED и ништа се неће догодити.

Последњи пример приказује како да се из Гит конфигурационих фајлова добије вредност опције user.name. Ова Config инстанца користи репозиторијум који смо раније отворили за локалну конфигурацију, али ће аутоматски да детектује фајлове глобалне и системске конфигурације и такође ће из њих а чита вредности.

Ово је само мали део комплетног водоводног API; доступно је још много метода и класа. Овде није приказан начин на који JGit обрађује грешке, а то је путем изузетака. JGit API понекад бацају стандардне Јава изузетке (као што је IOException), али доступна је и гомила JGit специфичних типова изузетака (као што су NoRemoteRepositoryException, CorruptObjectException и NoMergeBaseException).

Порцулан

Водоводни APIs је прилично комплетан, али може бити незгодно да акције надовежу заједно како би се постигли уобичајени циљеви, као што је додавање фајл у индекс, или прављење новог комита. JGit обезбеђује скуп API вишег нивоа који помаже у томе и почетна тачка ових API је Git класа:

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

Гит класа поседује фин скуп метода вишег нивоа у builder стилу које могу да се употребе за конструкцију прилично сложеног понашања. Хајде да погледамо приме – постизање нечега као што је 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());
}

Ово је уобичајен шаблон са Гит класом; методе враћају објекат команде који вам омогућава да уланчавате позиве метода како би поставили параметре, а који се затим извршавају када позовете .call(). У овом случају, питамо удаљени репозиторијум origin да нам пошаље ознаке, али не и главе. Приметите такође употребу CredentialsProvider објекта за аутентификцију.

Кроз Гит класу су доступне многе друге команде, укључујући, али не и само add, blame, commit, clean, push, rebase, revert и reset.

Наставак читања

Ово је само мали део свих могућности библиотеке JGit. Ако вас интересује да научите још, ево где да потражите информације и инспирацију:

  • Званична документација за JGit API је дотупна на мрежи, на адреси https://www.eclipse.org/jgit/documentation. То је стандардни Javadoc, тако да ће ваш омиљени JVM IDE такође моћи да је инсталира у локално.

  • JGit Cookbook на адреси https://github.com/centic9/jgit-cookbook има много примера начина да се одређени задаци изврше са JGit.