How to merge in JGit? - java

How do I merge in JGit?
Let's say I want to merge master with foo branch, how do I do this?

To merge, you can use the MergeCommand (in package org.eclipse.jgit.api), after a CheckoutCommand. To provide you with an example, because indeed Jgit lacks examples:
Git git = ... // you get it through a CloneCommand, InitCommand
// or through the file system
CheckoutCommand coCmd = git.checkout();
// Commands are part of the api module, which include git-like calls
coCmd.setName("master");
coCmd.setCreateBranch(false); // probably not needed, just to make sure
coCmd.call(); // switch to "master" branch
MergeCommand mgCmd = git.merge();
mgCmd.include("foo"); // "foo" is considered as a Ref to a branch
MergeResult res = mgCmd.call(); // actually do the merge
if (res.getMergeStatus().equals(MergeResult.MergeStatus.CONFLICTING)){
System.out.println(res.getConflicts().toString());
// inform the user he has to handle the conflicts
}
I did not try the code so it might not be perfect, but it's just to provide a start. And I didn't include the imports. Developing with JGit implies a lot of tries based on the javadoc

You will find in the JGit repository various test classes for Merge, including for instance the SimpleMergeTest
Merger ourMerger = MergeStrategy.OURS.newMerger(db);
boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
assertTrue(merge);

Passing an ObjectId is convenient for me, e.g.
void merge(String uri,File file){
try(Git git = Git.cloneRepository()
.setURI(uri)
.setBranch("master")
.setDirectory(file)
.call()){
ObjectId objectId = git.getRepository().resolve("origin/develop");
MergeResult mergeResult = git.merge().include(objectId).call();
log.debug(mergeResult.getMergeStatus());
} catch (GitAPIException | IOException e) {
log.error("error",e);
}
}
furthermore, you can find more examples here: https://github.com/centic9/jgit-cookbook

JGit has a full blown Java implementation of the git resolve merge strategy since 2010. If you need examples look at the corresponding JGit test cases and have a look how EGit is using the MergeCommand, look at class org.eclipse.egit.core.op.MergeOperation.

Related

Bitbucket Repository Hook: create PullRequest with source and targetBranch in Java

I want to develop a hook that will automatically merge a branch (always the same one) into the master when smth happens. This should happen because there are some strange diffs when pull requests are opened and we found out that this merging is the solution.
So I am working with the BitBucket Server API and I found the class PullRequestCreateRequest and the interface PullRequestService
This is what I got atm:
if (MYCONDITION)
{
PullRequestImpl pullRequest = new PullRequestImpl(); //class that implements PullRequestService
PullRequestCreateRequest prCreate = new PullRequestCreateRequest.Builder()
.title("Automatic Merge Branch Foo Into Master")
.description("blablabla")
.repository(request.getRepository()) //from head of the method
//.fromBranch("MyBranch") HELP pls
.toBranchId("master")
.build();
pullRequest.create(prCreate);
pullRequest.merge(prCreate);
}
My Problem is, that I don't know how to specify my source branch. I searched in the Doc, but just found some RefIds, etc.
Has someone an idea?
Btw: I create the PR first because it's not allowed to merge directly into the master and I can't change this.
Use fromRefId():
PullRequestCreateRequest prCreate = new PullRequestCreateRequest.Builder()
.title("Automatic Merge Branch Foo Into Master")
.description("blablabla")
.repository(request.getRepository())
.fromRefId("Foo") //<-- here you go
.toBranchId("master")
.build();

recognize parameter change from git repository

I want to extract signature changes (method parameter changes to be exact) from commits to git repository by a java program. I have used the following code:
for (Ref branch : branches) {
String branchName = branch.getName();
for (RevCommit commit : commits) {
boolean foundInThisBranch = false;
RevCommit targetCommit = walk.parseCommit(repo.resolve(
commit.getName()));
for (Map.Entry<String, Ref> e : repo.getAllRefs().entrySet()) {
if (e.getKey().startsWith(Constants.R_HEADS)) {
if (walk.isMergedInto(targetCommit, walk.parseCommit(
e.getValue().getObjectId()))) {
String foundInBranch = e.getValue().getName();
if (branchName.equals(foundInBranch)) {
foundInThisBranch = true;
break;
}
}
}
}
I can extract commit message, commit data and Author name from that, however, I am not able to extract parameter changes from them. I mean it is unable for me to identify parameter changes. I want to know if there is any way to recognize that. I mean it is impossible to recognize them from commit notes that are generated by programmers; I am looking for something like any specific annotation or something else.
This is my code to extract differences:
CanonicalTreeParser oldTreeIter = new CanonicalTreeParser();
oldTreeIter.reset(reader, oldId);
CanonicalTreeParser newTreeIter = new CanonicalTreeParser();
newTreeIter.reset(reader, headId);
List<DiffEntry> diffs= git.diff()
.setNewTree(newTreeIter)
.setOldTree(oldTreeIter)
.call();
ByteArrayOutputStream out = new ByteArrayOutputStream();
DiffFormatter df = new DiffFormatter(out);
df.setRepository(git.getRepository());
The export is really huge and impossible to extract method changes.
You show a way you've found to examine the diffs, but say that the output is too large and you can't extract the method signature changes. If by that you mean that you're asking about specific git support for telling you that a method signature changes, then no - no such support exists. This is because git does not "know" anything about the languages you may or may not have used in the files under source control. Everything is just content that is, or is not, different from other content.
Since a method signature could be split across lines in any number of ways, it's not even guaranteed that just because a method's signature changed its name would appear anywhere in the diff. What you would really have to do is perform a sort of "structural diff". That is, you would have to
check out the "old" version, and pass it to a java parser
check out the "new" version, and pass it to a java parser
compare the resulting parse trees, looking for methods that belong to the same object, but have changed
Even that won't be terribly easy, because methods could be renamed, and because method overloading could make it unclear which signature change goes with which version of a method.
From there what you have is a non-trivial coding problem, which is beyond the scope of SO to answer. If you decide to tackle this problem and run into specific programming questions along the way, of course you could post those questions and perhaps someone will be able to help.

Not possible to pass multiple files per commit per GitHub API?

I already use the GitHub API to make automated commits.
For this I'm using a Java Library from Kohsuke
It works with this API command:
Create a file
This method creates a new file in a repository
PUT /repos/:owner/:repo/contents/:path
But is it possible to include multiple files in 1 Commit per GitHub API?
The following code snippit will allow you to prepare a commit with multiple files, then associate a new branch to it, using the Java library from Kohsuke
// start with a Repository ref
GHRepository repo = ...
// get a sha to represent the root branch to start your commit from.
// this can come from any number of classes:
// GHBranch, GHCommit, GHTree, etc...
// for this example, we'll start from the master branch
GHBranch masterBranch = repo.getBranch("master");
// get a tree builder object to build up into the commit.
// the base of the tree will be the master branch
GHTreeBuilder treeBuilder = repo.createTree().baseTree(masterBranch.getSHA1());
// add entries to the tree in various ways.
// the nice thing about GHTreeBuilder.textEntry() is that it is an "upsert" (create new or update existing)
treeBuilder = treeBuilder.textEntry(pathToFile, contentOfFile, executable);
// repeat calls of treeBuider.textEntry() or .shaEntry() or .entry() ....
// perform the commit
GHCommit commit = repo.createCommit()
// base the commit on the tree we built
.tree(treeBuilder.create().getSha())
// set the parent of the commit as the master branch
.parent(masterBranch.getSHA1()).message("multi-file commit").create();
// create a new branch from that commit
String newBranchName = "myNewBranchName";
GHRef newRef = repo.createRef("/refs/heads/" + newBranchName, commit.getSHA1();
GHBranch newBranch = repo.getBranch(newBranchName);
Extending on Dan Dowma's answer, it is possible to push these changes to an existing branch
final String branchName = "main";
// start with a Repository ref
GHRepository repo = ...
// get a sha to represent the root branch to start your commit from.
// this can come from any number of classes:
// GHBranch, GHCommit, GHTree, etc...
// for this example, we'll start from the selected branch
GHBranch selectedBranch = repo.getBranch(branchName);
// get a tree builder object to build up into the commit.
// the base of the tree will be the master branch
GHTreeBuilder treeBuilder = repo.createTree().baseTree(selectedBranch.getSHA1());
// add entries to the tree.
treeBuilder = treeBuilder.add(pathToFile, contentOfFile, executable);
// perform the commit
GHCommit commit = repo.createCommit()
// base the commit on the tree we built
.tree(treeBuilder.create().getSha())
// set the parent of the commit as the master branch
.parent(selectedBranch.getSHA1()).message("multi-file commit").create();
// Update an existing branch from that commit
GHRef existingBranchRef = repo.getRef("/refs/heads/" + branchName);
existingBranchRef.updateTo(commit.getSHA1());
Not sure if this is what you want, maybe a little bit more description would help, but take a look at this:
https://developer.github.com/v3/git/

Is there a way to test if anyone pushed to the remote repo using JGit from local repo?

I am designing a User interface in Java and I am trying to make my own buildbot like thing. So for that I want to create a function like buildbot's gitpoller in JGit. Is it possible?
Yes, it's possible. You can use a FetchCommand and then inspect the FetchResult. Something like this:
Repository repository = FileRepositoryBuilder.create(gitDir);
Git git = Git.wrap(repository);
FetchResult result = git.fetch().call();
for (TrackingRefUpdate refUpdate : result.getTrackingRefUpdates()) {
// ...
}

How to get the id of commit using JavaGit library?

I use this code from the JavaGit example:
File repositoryDirectory = new File("Library\\build\\jar\\");
DotGit dotGit = DotGit.getInstance(repositoryDirectory);
// Print commit messages of the current branch
for (Commit c : dotGit.getLog()) {
System.out.println(c.getMessage());
}
How could I get the id of commit this way?
Or it might be more appropriate library to interact with git?
According to the documentation (I don't know very much this library), you should invoke the getCommitName() method and use the returned Ref object to get the information you want (I think the SHA1 hash or the tag).

Categories

Resources