diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java index 9f299c65f0..6a4335346a 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java @@ -5,6 +5,7 @@ import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.MergeResult; import org.eclipse.jgit.api.Status; import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.IndexDiff; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; @@ -23,6 +24,8 @@ import java.io.IOException; import java.util.Set; import static org.eclipse.jgit.merge.MergeStrategy.RECURSIVE; +import static sonia.scm.ContextEntry.ContextBuilder.entity; +import static sonia.scm.NotFoundException.notFound; public class GitMergeCommand extends AbstractGitCommand implements MergeCommand { @@ -46,8 +49,7 @@ public class GitMergeCommand extends AbstractGitCommand implements MergeCommand @Override public MergeConflictResult computeConflicts(MergeCommandRequest request) { - WorkingCopyCloser closer = new WorkingCopyCloser(); - return inClone(git -> new ConflictWorker(git, request, closer), workdirFactory, request.getTargetBranch()); + return inClone(git -> new ConflictWorker(git, request), workdirFactory, request.getTargetBranch()); } private MergeCommandResult mergeWithStrategy(MergeCommandRequest request) { @@ -91,68 +93,79 @@ public class GitMergeCommand extends AbstractGitCommand implements MergeCommand } private class ConflictWorker extends GitCloneWorker { - private final Git git; - private final MergeCommandRequest request; - private final WorkingCopyCloser closer; + private final String branchToMerge; + private final String targetBranch; private final CanonicalTreeParser treeParser; private final ObjectId treeId; private final ByteArrayOutputStream diffBuffer; - private ConflictWorker(Git git, MergeCommandRequest request, WorkingCopyCloser closer) { + private final MergeConflictResult result = new MergeConflictResult(); + + + private ConflictWorker(Git git, MergeCommandRequest request) { super(git, context, repository); - this.git = git; - this.request = request; - this.closer = closer; + branchToMerge = request.getBranchToMerge(); + targetBranch = request.getTargetBranch(); treeParser = new CanonicalTreeParser(); - treeId = git.getRepository().resolve(request.getTargetBranch() + "^{tree}"); diffBuffer = new ByteArrayOutputStream(); + try { + treeId = git.getRepository().resolve(request.getTargetBranch() + "^{tree}"); + } catch (IOException e) { + throw notFound(entity("branch", request.getTargetBranch()).in(repository)); + } } @Override MergeConflictResult run() throws IOException { MergeResult mergeResult = doTemporaryMerge(); - if (mergeResult.getConflicts() == null) { - return new MergeConflictResult(); + if (mergeResult.getConflicts() != null) { + getStatus().getConflictingStageState().forEach(this::computeConflict); } - - Status status = getStatus(); - - MergeConflictResult result = new MergeConflictResult(); - - - status.getConflictingStageState().forEach((path, value) -> { - switch (value) { - case BOTH_MODIFIED: - diffBuffer.reset(); - try (ObjectReader reader = git.getRepository().newObjectReader()) { - treeParser.reset(reader, treeId); - git - .diff() - .setOldTree(treeParser) - .setPathFilter(PathFilter.create(path)) - .setOutputStream(diffBuffer) - .call(); - result.addBothModified(path, diffBuffer.toString()); - } catch (GitAPIException | IOException e) { - throw new InternalRepositoryException(repository, "could not calculate diff for path " + path, e); - } finally { - closer.close(); - } - break; - case DELETED_BY_THEM: - result.addDeletedByThem(path); - break; - case DELETED_BY_US: - result.addDeletedByUs(path); - break; - default: - throw new InternalRepositoryException(context.getRepository(), "unexpected conflict type: " + value); - } - }); return result; } + private void computeConflict(String path, IndexDiff.StageState stageState) { + switch (stageState) { + case BOTH_MODIFIED: + diffBuffer.reset(); + try (ObjectReader reader = getClone().getRepository().newObjectReader()) { + treeParser.reset(reader, treeId); + getClone() + .diff() + .setOldTree(treeParser) + .setPathFilter(PathFilter.create(path)) + .setOutputStream(diffBuffer) + .call(); + result.addBothModified(path, diffBuffer.toString()); + } catch (GitAPIException | IOException e) { + throw new InternalRepositoryException(repository, "could not calculate diff for path " + path, e); + } + break; + case DELETED_BY_THEM: + result.addDeletedByThem(path); + break; + case DELETED_BY_US: + result.addDeletedByUs(path); + break; + default: + throw new InternalRepositoryException(context.getRepository(), "unexpected conflict type: " + stageState); + } + } + + private MergeResult doTemporaryMerge() throws IOException { + ObjectId sourceRevision = resolveRevision(branchToMerge); + try { + return getClone().merge() + .setFastForward(org.eclipse.jgit.api.MergeCommand.FastForwardMode.NO_FF) + .setCommit(false) + .include(branchToMerge, sourceRevision) + .call(); + } catch (GitAPIException e) { + throw new InternalRepositoryException(context.getRepository(), "could not merge branch " + branchToMerge + " into " + targetBranch, e); + } + } + private Status getStatus() { Status status; try { @@ -162,20 +175,5 @@ public class GitMergeCommand extends AbstractGitCommand implements MergeCommand } return status; } - - private MergeResult doTemporaryMerge() throws IOException { - ObjectId sourceRevision = resolveRevision(request.getBranchToMerge()); - MergeResult mergeResult; - try { - mergeResult = getClone().merge() - .setFastForward(org.eclipse.jgit.api.MergeCommand.FastForwardMode.NO_FF) - .setCommit(false) - .include(request.getBranchToMerge(), sourceRevision) - .call(); - } catch (GitAPIException e) { - throw new InternalRepositoryException(context.getRepository(), "could not merge branch " + request.getBranchToMerge() + " into " + request.getTargetBranch(), e); - } - return mergeResult; - } } }