diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java index 7175d3b646..992e595382 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java @@ -70,6 +70,7 @@ import java.util.Optional; import java.util.concurrent.TimeUnit; import static java.util.Optional.of; +import static java.util.Optional.ofNullable; //~--- JDK imports ------------------------------------------------------------ @@ -722,12 +723,13 @@ public final class GitUtil /** * 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 { + public static Optional 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(); + RevCommit commonAncestor = mergeBaseWalk.next(); + return ofNullable(commonAncestor).map(RevCommit::getId); } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/Differ.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/Differ.java index ca417550f4..81d19886c3 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/Differ.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/Differ.java @@ -10,11 +10,15 @@ import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.EmptyTreeIterator; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.filter.PathFilter; +import sonia.scm.BadRequestException; import sonia.scm.repository.GitUtil; import sonia.scm.util.Util; import java.io.IOException; import java.util.List; +import java.util.Optional; + +import static java.util.Collections.emptyList; final class Differ implements AutoCloseable { @@ -55,7 +59,9 @@ final class Differ implements AutoCloseable { if (!Strings.isNullOrEmpty(request.getAncestorChangeset())) { ObjectId otherRevision = repository.resolve(request.getAncestorChangeset()); - ObjectId ancestorId = computeCommonAncestor(repository, revision, otherRevision); + ObjectId ancestorId = + computeCommonAncestor(repository, revision, otherRevision) + .orElseThrow(NoCommonHistoryException::new); RevTree tree = walk.parseCommit(ancestorId).getTree(); treeWalk.addTree(tree); } @@ -82,7 +88,7 @@ final class Differ implements AutoCloseable { return new Differ(commit, walk, treeWalk); } - private static ObjectId computeCommonAncestor(org.eclipse.jgit.lib.Repository repository, ObjectId revision1, ObjectId revision2) throws IOException { + private static Optional computeCommonAncestor(org.eclipse.jgit.lib.Repository repository, ObjectId revision1, ObjectId revision2) throws IOException { return GitUtil.computeCommonAncestor(repository, revision1, revision2); } @@ -115,4 +121,16 @@ final class Differ implements AutoCloseable { return entries; } } + + private static class NoCommonHistoryException extends BadRequestException { + + private NoCommonHistoryException() { + super(emptyList(), "no common history"); + } + + @Override + public String getCode() { + return "4iRct4avG1"; + } + } } diff --git a/scm-webapp/src/main/resources/locales/de/plugins.json b/scm-webapp/src/main/resources/locales/de/plugins.json index 9c5bb3f5f5..ef6d5d8c96 100644 --- a/scm-webapp/src/main/resources/locales/de/plugins.json +++ b/scm-webapp/src/main/resources/locales/de/plugins.json @@ -175,6 +175,10 @@ "40RaYIeeR1": { "displayName": "Es wurden keine Änderungen durchgeführt", "description": "Das Repository wurde nicht verändert. Daher konnte kein neuer Commit erzeugt werden." + }, + "4iRct4avG1": { + "displayName": "Die Revisionen haben keinen gemeinsamen Ursprung", + "description": "Die Historie der Revisionen hat keinen gemeinsamen Urspung und kann somit auch nicht gegen einen solchen verglichen werden." } }, "namespaceStrategies": { diff --git a/scm-webapp/src/main/resources/locales/en/plugins.json b/scm-webapp/src/main/resources/locales/en/plugins.json index 1ffffd73b7..247fa212f3 100644 --- a/scm-webapp/src/main/resources/locales/en/plugins.json +++ b/scm-webapp/src/main/resources/locales/en/plugins.json @@ -175,6 +175,10 @@ "40RaYIeeR1": { "displayName": "No changes were made", "description": "No changes were made to the files of the repository. Therefor no new commit could be created." + }, + "4iRct4avG1": { + "displayName": "The revisions have unrelated histories", + "description": "The revisions have unrelated histories. Therefor there is no common commit to compare with." } }, "namespaceStrategies": {