Skip to content

Commit

Permalink
Use JGit to find merge base between branches.
Browse files Browse the repository at this point in the history
This replaces the filtering tip branches logic to use a
JGit RevWalk to find the merge base of two branches instead
of invoking the 'git merge-base' command.
  • Loading branch information
kevinsawicki committed Jun 9, 2011
1 parent 92ff8a0 commit 2773af2
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 28 deletions.
2 changes: 1 addition & 1 deletion src/main/java/hudson/plugins/git/GitAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -980,7 +980,7 @@ public String getAllLogEntries(String branch) {
return launchCommand("log", "--all", "--pretty=format:'%H#%ct'", branch);
}

private Repository getRepository() throws IOException {
public Repository getRepository() throws IOException {
return new FileRepository(new File(workspace.getRemote(), Constants.DOT_GIT));
}

Expand Down
3 changes: 3 additions & 0 deletions src/main/java/hudson/plugins/git/IGitAPI.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package hudson.plugins.git;

import hudson.EnvVars;
import hudson.FilePath;
import hudson.model.TaskListener;

import java.io.File;
Expand All @@ -11,6 +12,7 @@

import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.RemoteConfig;

/**
Expand All @@ -19,6 +21,7 @@
public interface IGitAPI {
String getGitExe();
EnvVars getEnvironment();
Repository getRepository() throws IOException;

public void init() throws GitException;

Expand Down
94 changes: 67 additions & 27 deletions src/main/java/hudson/plugins/git/util/GitUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,24 @@
import hudson.plugins.git.Branch;
import hudson.plugins.git.GitException;
import hudson.plugins.git.IGitAPI;
import hudson.plugins.git.IndexEntry;
import hudson.plugins.git.Revision;


import java.io.IOException;
import java.io.OutputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.filter.RevFilter;

public class GitUtils {
IGitAPI git;
Expand Down Expand Up @@ -92,39 +93,78 @@ public Revision getRevisionForSHA1(ObjectId sha1) throws GitException, IOExcepti
/**
* Return a list of 'tip' branches (I.E. branches that aren't included entirely within another branch).
*
* @param git
* @return
* @param revisions
* @return filtered tip branches
*/
public Collection<Revision> filterTipBranches(Collection<Revision> revisions) {
// If we have 3 branches that we might want to build
// ----A--.---.--- B
// \-----C

// we only want (B) and (C), as (A) is an ancestor (old).

List<Revision> l = new ArrayList<Revision>(revisions);

OUTER:
for (int i=0; i<l.size(); i++) {
for (int j=i+1; j<l.size(); j++) {
Revision ri = l.get(i);
Revision rj = l.get(j);
ObjectId commonAncestor = git.mergeBase(ri.getSha1(), rj.getSha1());
if (commonAncestor==null) continue;

if (commonAncestor.equals(ri.getSha1())) {
LOGGER.fine("filterTipBranches: "+rj+" subsumes "+ri);
l.remove(i);
i--;
continue OUTER;
}
if (commonAncestor.equals(rj.getSha1())) {
LOGGER.fine("filterTipBranches: "+ri+" subsumes "+rj);
l.remove(j);
j--;
final List<Revision> l = new ArrayList<Revision>(revisions);

// Bypass any rev walks if only one branch or less
if (l.size() <= 1)
return l;

final boolean log = LOGGER.isLoggable(Level.FINE);
Revision revI;
Revision revJ;
ObjectId shaI;
ObjectId shaJ;
ObjectId commonAncestor;
RevWalk walk = null;
final long start = System.currentTimeMillis();
long calls = 0;
if (log)
LOGGER.fine(MessageFormat.format(
"Computing merge base of {0} branches", l.size()));
try {
walk = new RevWalk(git.getRepository());
walk.setRetainBody(false);
walk.setRevFilter(RevFilter.MERGE_BASE);
for (int i = 0; i < l.size(); i++)
for (int j = i + 1; j < l.size(); j++) {
revI = l.get(i);
revJ = l.get(j);
shaI = revI.getSha1();
shaJ = revJ.getSha1();

walk.reset();
walk.markStart(walk.parseCommit(shaI));
walk.markStart(walk.parseCommit(shaJ));
commonAncestor = walk.next();
calls++;

if (commonAncestor == null)
continue;
if (commonAncestor.equals(shaI)) {
if (log)
LOGGER.fine("filterTipBranches: " + revJ
+ " subsumes " + revI);
l.remove(i);
i--;
break;
}
if (commonAncestor.equals(shaJ)) {
if (log)
LOGGER.fine("filterTipBranches: " + revI
+ " subsumes " + revJ);
l.remove(j);
j--;
}
}
}
} catch (IOException e) {
throw new GitException("Error computing merge base", e);
} finally {
if (walk != null)
walk.release();
}
if (log)
LOGGER.fine(MessageFormat.format(
"Computed {0} merge bases in {1} ms", calls,
(System.currentTimeMillis() - start)));

return l;
}
Expand Down

0 comments on commit 2773af2

Please sign in to comment.