Implement diff between two changesets for git

This commit is contained in:
René Pfeuffer
2018-11-06 12:04:33 +01:00
parent a725e4232b
commit 8be8c19a26
4 changed files with 66 additions and 10 deletions

View File

@@ -109,6 +109,9 @@ public final class DiffCommandRequest extends FileBaseCommandRequest
this.format = format; this.format = format;
} }
public void setAncestorChangeset(String ancestorChangeset) {
this.ancestorChangeset = ancestorChangeset;
}
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------
/** /**
@@ -124,8 +127,13 @@ public final class DiffCommandRequest extends FileBaseCommandRequest
return format; return format;
} }
public String getAncestorChangeset() {
return ancestorChangeset;
}
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------
/** diff format */ /** diff format */
private DiffFormat format = DiffFormat.NATIVE; private DiffFormat format = DiffFormat.NATIVE;
private String ancestorChangeset;
} }

View File

@@ -48,6 +48,7 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.transport.FetchResult; import org.eclipse.jgit.transport.FetchResult;
import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.transport.RefSpec;
@@ -716,6 +717,18 @@ public final class GitUtil
return (id != null) &&!id.equals(ObjectId.zeroId()); return (id != null) &&!id.equals(ObjectId.zeroId());
} }
/**
* Computes the first common ancestor of two revisions, aka merge base.
*/
public static ObjectId computeCommonAncestor(org.eclipse.jgit.lib.Repository repository, ObjectId revision1, ObjectId revision2) throws IOException {
try (RevWalk mergeBaseWalk = new RevWalk(repository)) {
mergeBaseWalk.setRevFilter(RevFilter.MERGE_BASE);
mergeBaseWalk.markStart(mergeBaseWalk.lookupCommit(revision1));
mergeBaseWalk.markStart(mergeBaseWalk.parseCommit(revision2));
return mergeBaseWalk.next().getId();
}
}
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------
/** /**

View File

@@ -34,27 +34,25 @@ package sonia.scm.repository.spi;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Strings;
import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter; import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.EmptyTreeIterator; import org.eclipse.jgit.treewalk.EmptyTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter; import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.repository.GitUtil; import sonia.scm.repository.GitUtil;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
import sonia.scm.util.Util; import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.List; import java.util.List;
/** /**
@@ -107,7 +105,8 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand
walk = new RevWalk(gr); walk = new RevWalk(gr);
RevCommit commit = walk.parseCommit(gr.resolve(request.getRevision())); ObjectId revision = gr.resolve(request.getRevision());
RevCommit commit = walk.parseCommit(revision);
walk.markStart(commit); walk.markStart(commit);
commit = walk.next(); commit = walk.next();
@@ -120,7 +119,15 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand
treeWalk.setFilter(PathFilter.create(request.getPath())); treeWalk.setFilter(PathFilter.create(request.getPath()));
} }
if (commit.getParentCount() > 0)
if (!Strings.isNullOrEmpty(request.getAncestorChangeset()))
{
ObjectId otherRevision = gr.resolve(request.getAncestorChangeset());
ObjectId ancestorId = computeCommonAncestor(gr, revision, otherRevision);
RevTree tree = walk.parseCommit(ancestorId).getTree();
treeWalk.addTree(tree);
}
else if (commit.getParentCount() > 0)
{ {
RevTree tree = commit.getParent(0).getTree(); RevTree tree = commit.getParent(0).getTree();
@@ -156,7 +163,6 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand
} }
catch (Exception ex) catch (Exception ex)
{ {
// TODO throw exception // TODO throw exception
logger.error("could not create diff", ex); logger.error("could not create diff", ex);
} }
@@ -167,4 +173,9 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand
GitUtil.release(formatter); GitUtil.release(formatter);
} }
} }
private ObjectId computeCommonAncestor(org.eclipse.jgit.lib.Repository repository, ObjectId revision1, ObjectId revision2) throws IOException {
return GitUtil.computeCommonAncestor(repository, revision1, revision2);
}
} }

View File

@@ -42,4 +42,28 @@ public class GitDiffCommandTest extends AbstractGitCommandTestBase {
gitDiffCommand.getDiffResult(diffCommandRequest, output); gitDiffCommand.getDiffResult(diffCommandRequest, output);
assertEquals(DIFF_LATEST_COMMIT_TEST_BRANCH, output.toString()); assertEquals(DIFF_LATEST_COMMIT_TEST_BRANCH, output.toString());
} }
@Test
public void diffBetweenTwoBranchesShouldCreateDiff() {
GitDiffCommand gitDiffCommand = new GitDiffCommand(createContext(), repository);
DiffCommandRequest diffCommandRequest = new DiffCommandRequest();
diffCommandRequest.setRevision("master");
diffCommandRequest.setAncestorChangeset("test-branch");
ByteArrayOutputStream output = new ByteArrayOutputStream();
gitDiffCommand.getDiffResult(diffCommandRequest, output);
assertEquals("diff --git a/a.txt b/a.txt\n" +
"index 7898192..2f8bc28 100644\n" +
"--- a/a.txt\n" +
"+++ b/a.txt\n" +
"@@ -1 +1,2 @@\n" +
" a\n" +
"+line for blame\n" +
"diff --git a/f.txt b/f.txt\n" +
"new file mode 100644\n" +
"index 0000000..6a69f92\n" +
"--- /dev/null\n" +
"+++ b/f.txt\n" +
"@@ -0,0 +1 @@\n" +
"+f\n", output.toString());
}
} }