aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit/src/org/eclipse/jgit/api
diff options
context:
space:
mode:
authorMatthias Sohn <matthias.sohn@sap.com>2021-05-12 08:59:07 +0200
committerMatthias Sohn <matthias.sohn@sap.com>2021-05-12 08:59:07 +0200
commit1aa3cf7f416658a4fafd592732ba70f5a1aee19e (patch)
tree275b1176d04d102832641292a765d1a8f3e1b3a2 /org.eclipse.jgit/src/org/eclipse/jgit/api
parentb6d4844b5d60f63a46f2b8b42189f70de653b385 (diff)
parentfe3034d5b90a8a1f2592a40a670705fbd7305158 (diff)
downloadjgit-1aa3cf7f416658a4fafd592732ba70f5a1aee19e.tar.gz
jgit-1aa3cf7f416658a4fafd592732ba70f5a1aee19e.zip
Merge branch 'master' into next
* master: (34 commits) Remove texts which were added by mistake in 00386272 Fix formatting which was broken in 00386272 LockFile: create OutputStream only when needed Add a cgit interoperability test for LockFile Add TemporaryBuffer.toString(int limit) LockFile: create OutputStream only when needed Prepare 5.12.0-SNAPSHOT builds JGit v5.12.0.202105051250-m2 Update jetty to 9.4.40.v20210413 [releng] Update eclipse-jarsigner-plugin to 1.3.1 Implement ours/theirs content conflict resolution ssh: ensure list is modifiable before using Iterator.remove(). Update orbit to S20210406213021 and add 4.20-staging target Fix typo in test method name Allow file mode conflicts in virtual base commit on recursive merge. sshd: don't lock the known_hosts files on reading Allow info messages in UsernamePasswordCredentialsProvider ssh config: do environment variable replacement sshd: implement server-sig-algs SSH extension (client side) Upgrade ecj to 3.25.0 ... Change-Id: Ibc39a9c4e431d15b67ab4a307241f47a7f3740a9
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/api')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java70
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java185
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java24
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java34
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java34
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java89
6 files changed, 302 insertions, 134 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
index 5d0154c6dc..7922f9e729 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com> and others
+ * Copyright (C) 2010, 2021 Christian Halstrick <christian.halstrick@sap.com> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -13,6 +13,7 @@ import java.io.IOException;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
import org.eclipse.jgit.api.errors.GitAPIException;
@@ -35,9 +36,12 @@ import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Ref.Storage;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.merge.ContentMergeStrategy;
import org.eclipse.jgit.merge.MergeMessageFormatter;
import org.eclipse.jgit.merge.MergeStrategy;
+import org.eclipse.jgit.merge.Merger;
import org.eclipse.jgit.merge.ResolveMerger;
+import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.FileTreeIterator;
@@ -61,6 +65,8 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> {
private MergeStrategy strategy = MergeStrategy.RECURSIVE;
+ private ContentMergeStrategy contentStrategy;
+
private Integer mainlineParentNumber;
private boolean noCommit = false;
@@ -121,16 +127,30 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> {
String cherryPickName = srcCommit.getId().abbreviate(7).name()
+ " " + srcCommit.getShortMessage(); //$NON-NLS-1$
- ResolveMerger merger = (ResolveMerger) strategy.newMerger(repo);
- merger.setWorkingTreeIterator(new FileTreeIterator(repo));
- merger.setBase(srcParent.getTree());
- merger.setCommitNames(new String[] { "BASE", ourName, //$NON-NLS-1$
- cherryPickName });
- if (merger.merge(newHead, srcCommit)) {
- if (!merger.getModifiedFiles().isEmpty()) {
+ Merger merger = strategy.newMerger(repo);
+ merger.setProgressMonitor(monitor);
+ boolean noProblems;
+ Map<String, MergeFailureReason> failingPaths = null;
+ List<String> unmergedPaths = null;
+ if (merger instanceof ResolveMerger) {
+ ResolveMerger resolveMerger = (ResolveMerger) merger;
+ resolveMerger.setContentMergeStrategy(contentStrategy);
+ resolveMerger.setCommitNames(
+ new String[] { "BASE", ourName, cherryPickName }); //$NON-NLS-1$
+ resolveMerger
+ .setWorkingTreeIterator(new FileTreeIterator(repo));
+ resolveMerger.setBase(srcParent.getTree());
+ noProblems = merger.merge(newHead, srcCommit);
+ failingPaths = resolveMerger.getFailingPaths();
+ unmergedPaths = resolveMerger.getUnmergedPaths();
+ if (!resolveMerger.getModifiedFiles().isEmpty()) {
repo.fireEvent(new WorkingTreeModifiedEvent(
- merger.getModifiedFiles(), null));
+ resolveMerger.getModifiedFiles(), null));
}
+ } else {
+ noProblems = merger.merge(newHead, srcCommit);
+ }
+ if (noProblems) {
if (AnyObjectId.isEqual(newHead.getTree().getId(),
merger.getResultTreeId())) {
continue;
@@ -153,24 +173,26 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> {
}
cherryPickedRefs.add(src);
} else {
- if (merger.failed()) {
- return new CherryPickResult(merger.getFailingPaths());
+ if (failingPaths != null && !failingPaths.isEmpty()) {
+ return new CherryPickResult(failingPaths);
}
// there are merge conflicts
- String message = new MergeMessageFormatter()
+ String message;
+ if (unmergedPaths != null) {
+ message = new MergeMessageFormatter()
.formatWithConflicts(srcCommit.getFullMessage(),
- merger.getUnmergedPaths());
+ unmergedPaths);
+ } else {
+ message = srcCommit.getFullMessage();
+ }
if (!noCommit) {
repo.writeCherryPickHead(srcCommit.getId());
}
repo.writeMergeCommitMsg(message);
- repo.fireEvent(new WorkingTreeModifiedEvent(
- merger.getModifiedFiles(), null));
-
return CherryPickResult.CONFLICT;
}
}
@@ -291,6 +313,22 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> {
}
/**
+ * Sets the content merge strategy to use if the
+ * {@link #setStrategy(MergeStrategy) merge strategy} is "resolve" or
+ * "recursive".
+ *
+ * @param strategy
+ * the {@link ContentMergeStrategy} to be used
+ * @return {@code this}
+ * @since 5.12
+ */
+ public CherryPickCommand setContentMergeStrategy(
+ ContentMergeStrategy strategy) {
+ this.contentStrategy = strategy;
+ return this;
+ }
+
+ /**
* Set the (1-based) parent number to diff against
*
* @param mainlineParentNumber
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
index 041276c0f8..37f1d482aa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -20,6 +20,7 @@ import java.util.LinkedList;
import java.util.List;
import org.eclipse.jgit.api.errors.AbortedByHookException;
+import org.eclipse.jgit.api.errors.CanceledException;
import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
import org.eclipse.jgit.api.errors.EmptyCommitException;
import org.eclipse.jgit.api.errors.GitAPIException;
@@ -36,6 +37,8 @@ import org.eclipse.jgit.dircache.DirCacheBuildIterator;
import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.dircache.DirCacheIterator;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.UnmergedPathException;
import org.eclipse.jgit.hooks.CommitMsgHook;
import org.eclipse.jgit.hooks.Hooks;
@@ -67,6 +70,8 @@ import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
import org.eclipse.jgit.util.ChangeIdUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* A class used to execute a {@code Commit} command. It has setters for all
@@ -78,6 +83,9 @@ import org.eclipse.jgit.util.ChangeIdUtil;
* >Git documentation about Commit</a>
*/
public class CommitCommand extends GitCommand<RevCommit> {
+ private static final Logger log = LoggerFactory
+ .getLogger(CommitCommand.class);
+
private PersonIdent author;
private PersonIdent committer;
@@ -173,8 +181,7 @@ public class CommitCommand extends GitCommand<RevCommit> {
if (all && !repo.isBare()) {
try (Git git = new Git(repo)) {
- git.add()
- .addFilepattern(".") //$NON-NLS-1$
+ git.add().addFilepattern(".") //$NON-NLS-1$
.setUpdate(true).call();
} catch (NoFilepatternException e) {
// should really not happen
@@ -212,7 +219,7 @@ public class CommitCommand extends GitCommand<RevCommit> {
.setCommitMessage(message).call();
}
- // lock the index
+ RevCommit revCommit;
DirCache index = repo.lockDirCache();
try (ObjectInserter odi = repo.newObjectInserter()) {
if (!only.isEmpty())
@@ -226,100 +233,37 @@ public class CommitCommand extends GitCommand<RevCommit> {
if (insertChangeId)
insertChangeId(indexTreeId);
- // Check for empty commits
- if (headId != null && !allowEmpty.booleanValue()) {
- RevCommit headCommit = rw.parseCommit(headId);
- headCommit.getTree();
- if (indexTreeId.equals(headCommit.getTree())) {
- throw new EmptyCommitException(
- JGitText.get().emptyCommit);
- }
- }
+ checkIfEmpty(rw, headId, indexTreeId);
// Create a Commit object, populate it and write it
CommitBuilder commit = new CommitBuilder();
commit.setCommitter(committer);
commit.setAuthor(author);
commit.setMessage(message);
-
commit.setParentIds(parents);
commit.setTreeId(indexTreeId);
if (signCommit.booleanValue()) {
- if (gpgSigner == null) {
- throw new ServiceUnavailableException(
- JGitText.get().signingServiceUnavailable);
- }
- if (gpgSigner instanceof GpgObjectSigner) {
- ((GpgObjectSigner) gpgSigner).signObject(commit,
- signingKey, committer, credentialsProvider,
- gpgConfig);
- } else {
- if (gpgConfig.getKeyFormat() != GpgFormat.OPENPGP) {
- throw new UnsupportedSigningFormatException(JGitText
- .get().onlyOpenPgpSupportedForSigning);
- }
- gpgSigner.sign(commit, signingKey, committer,
- credentialsProvider);
- }
+ sign(commit);
}
ObjectId commitId = odi.insert(commit);
odi.flush();
+ revCommit = rw.parseCommit(commitId);
- RevCommit revCommit = rw.parseCommit(commitId);
- RefUpdate ru = repo.updateRef(Constants.HEAD);
- ru.setNewObjectId(commitId);
- if (!useDefaultReflogMessage) {
- ru.setRefLogMessage(reflogComment, false);
- } else {
- String prefix = amend ? "commit (amend): " //$NON-NLS-1$
- : parents.isEmpty() ? "commit (initial): " //$NON-NLS-1$
- : "commit: "; //$NON-NLS-1$
- ru.setRefLogMessage(prefix + revCommit.getShortMessage(),
- false);
- }
- if (headId != null)
- ru.setExpectedOldObjectId(headId);
- else
- ru.setExpectedOldObjectId(ObjectId.zeroId());
- Result rc = ru.forceUpdate();
- switch (rc) {
- case NEW:
- case FORCED:
- case FAST_FORWARD: {
- setCallable(false);
- if (state == RepositoryState.MERGING_RESOLVED
- || isMergeDuringRebase(state)) {
- // Commit was successful. Now delete the files
- // used for merge commits
- repo.writeMergeCommitMsg(null);
- repo.writeMergeHeads(null);
- } else if (state == RepositoryState.CHERRY_PICKING_RESOLVED) {
- repo.writeMergeCommitMsg(null);
- repo.writeCherryPickHead(null);
- } else if (state == RepositoryState.REVERTING_RESOLVED) {
- repo.writeMergeCommitMsg(null);
- repo.writeRevertHead(null);
- }
- Hooks.postCommit(repo,
- hookOutRedirect.get(PostCommitHook.NAME),
- hookErrRedirect.get(PostCommitHook.NAME)).call();
-
- return revCommit;
- }
- case REJECTED:
- case LOCK_FAILURE:
- throw new ConcurrentRefUpdateException(
- JGitText.get().couldNotLockHEAD, ru.getRef(), rc);
- default:
- throw new JGitInternalException(MessageFormat.format(
- JGitText.get().updatingRefFailed, Constants.HEAD,
- commitId.toString(), rc));
- }
+ updateRef(state, headId, revCommit, commitId);
} finally {
index.unlock();
}
+ try {
+ Hooks.postCommit(repo, hookOutRedirect.get(PostCommitHook.NAME),
+ hookErrRedirect.get(PostCommitHook.NAME)).call();
+ } catch (Exception e) {
+ log.error(MessageFormat.format(
+ JGitText.get().postCommitHookFailed, e.getMessage()),
+ e);
+ }
+ return revCommit;
} catch (UnmergedPathException e) {
throw new UnmergedPathsException(e);
} catch (IOException e) {
@@ -328,6 +272,89 @@ public class CommitCommand extends GitCommand<RevCommit> {
}
}
+ private void checkIfEmpty(RevWalk rw, ObjectId headId, ObjectId indexTreeId)
+ throws EmptyCommitException, MissingObjectException,
+ IncorrectObjectTypeException, IOException {
+ if (headId != null && !allowEmpty.booleanValue()) {
+ RevCommit headCommit = rw.parseCommit(headId);
+ headCommit.getTree();
+ if (indexTreeId.equals(headCommit.getTree())) {
+ throw new EmptyCommitException(JGitText.get().emptyCommit);
+ }
+ }
+ }
+
+ private void sign(CommitBuilder commit) throws ServiceUnavailableException,
+ CanceledException, UnsupportedSigningFormatException {
+ if (gpgSigner == null) {
+ throw new ServiceUnavailableException(
+ JGitText.get().signingServiceUnavailable);
+ }
+ if (gpgSigner instanceof GpgObjectSigner) {
+ ((GpgObjectSigner) gpgSigner).signObject(commit,
+ signingKey, committer, credentialsProvider,
+ gpgConfig);
+ } else {
+ if (gpgConfig.getKeyFormat() != GpgFormat.OPENPGP) {
+ throw new UnsupportedSigningFormatException(JGitText
+ .get().onlyOpenPgpSupportedForSigning);
+ }
+ gpgSigner.sign(commit, signingKey, committer,
+ credentialsProvider);
+ }
+ }
+
+ private void updateRef(RepositoryState state, ObjectId headId,
+ RevCommit revCommit, ObjectId commitId)
+ throws ConcurrentRefUpdateException, IOException {
+ RefUpdate ru = repo.updateRef(Constants.HEAD);
+ ru.setNewObjectId(commitId);
+ if (!useDefaultReflogMessage) {
+ ru.setRefLogMessage(reflogComment, false);
+ } else {
+ String prefix = amend ? "commit (amend): " //$NON-NLS-1$
+ : parents.isEmpty() ? "commit (initial): " //$NON-NLS-1$
+ : "commit: "; //$NON-NLS-1$
+ ru.setRefLogMessage(prefix + revCommit.getShortMessage(),
+ false);
+ }
+ if (headId != null) {
+ ru.setExpectedOldObjectId(headId);
+ } else {
+ ru.setExpectedOldObjectId(ObjectId.zeroId());
+ }
+ Result rc = ru.forceUpdate();
+ switch (rc) {
+ case NEW:
+ case FORCED:
+ case FAST_FORWARD: {
+ setCallable(false);
+ if (state == RepositoryState.MERGING_RESOLVED
+ || isMergeDuringRebase(state)) {
+ // Commit was successful. Now delete the files
+ // used for merge commits
+ repo.writeMergeCommitMsg(null);
+ repo.writeMergeHeads(null);
+ } else if (state == RepositoryState.CHERRY_PICKING_RESOLVED) {
+ repo.writeMergeCommitMsg(null);
+ repo.writeCherryPickHead(null);
+ } else if (state == RepositoryState.REVERTING_RESOLVED) {
+ repo.writeMergeCommitMsg(null);
+ repo.writeRevertHead(null);
+ }
+ break;
+ }
+ case REJECTED:
+ case LOCK_FAILURE:
+ throw new ConcurrentRefUpdateException(
+ JGitText.get().couldNotLockHEAD, ru.getRef(), rc);
+ default:
+ throw new JGitInternalException(MessageFormat.format(
+ JGitText.get().updatingRefFailed, Constants.HEAD,
+ commitId.toString(), rc));
+ }
+ }
+
private void insertChangeId(ObjectId treeId) {
ObjectId firstParentId = null;
if (!parents.isEmpty())
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
index d88f4ec561..c611f915ae 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
- * Copyright (C) 2010-2014, Stefan Lay <stefan.lay@sap.com>
- * Copyright (C) 2016, Laurent Delaigue <laurent.delaigue@obeo.fr> and others
+ * Copyright (C) 2010, 2014, Stefan Lay <stefan.lay@sap.com>
+ * Copyright (C) 2016, 2021 Laurent Delaigue <laurent.delaigue@obeo.fr> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -45,6 +45,7 @@ import org.eclipse.jgit.lib.Ref.Storage;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.merge.ContentMergeStrategy;
import org.eclipse.jgit.merge.MergeConfig;
import org.eclipse.jgit.merge.MergeMessageFormatter;
import org.eclipse.jgit.merge.MergeStrategy;
@@ -71,6 +72,8 @@ public class MergeCommand extends GitCommand<MergeResult> {
private MergeStrategy mergeStrategy = MergeStrategy.RECURSIVE;
+ private ContentMergeStrategy contentStrategy;
+
private List<Ref> commits = new LinkedList<>();
private Boolean squash;
@@ -320,6 +323,7 @@ public class MergeCommand extends GitCommand<MergeResult> {
List<String> unmergedPaths = null;
if (merger instanceof ResolveMerger) {
ResolveMerger resolveMerger = (ResolveMerger) merger;
+ resolveMerger.setContentMergeStrategy(contentStrategy);
resolveMerger.setCommitNames(new String[] {
"BASE", "HEAD", ref.getName() }); //$NON-NLS-1$ //$NON-NLS-2$
resolveMerger.setWorkingTreeIterator(new FileTreeIterator(repo));
@@ -473,6 +477,22 @@ public class MergeCommand extends GitCommand<MergeResult> {
}
/**
+ * Sets the content merge strategy to use if the
+ * {@link #setStrategy(MergeStrategy) merge strategy} is "resolve" or
+ * "recursive".
+ *
+ * @param strategy
+ * the {@link ContentMergeStrategy} to be used
+ * @return {@code this}
+ * @since 5.12
+ */
+ public MergeCommand setContentMergeStrategy(ContentMergeStrategy strategy) {
+ checkCallable();
+ this.contentStrategy = strategy;
+ return this;
+ }
+
+ /**
* Reference to a commit to be merged with the current head
*
* @param aCommit
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
index 449250890c..281ecfd011 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
* Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
- * Copyright (C) 2016, Laurent Delaigue <laurent.delaigue@obeo.fr> and others
+ * Copyright (C) 2016, 2021 Laurent Delaigue <laurent.delaigue@obeo.fr> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -43,6 +43,7 @@ import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
import org.eclipse.jgit.lib.SubmoduleConfig.FetchRecurseSubmodulesMode;
+import org.eclipse.jgit.merge.ContentMergeStrategy;
import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
@@ -69,6 +70,8 @@ public class PullCommand extends TransportCommand<PullCommand, PullResult> {
private MergeStrategy strategy = MergeStrategy.RECURSIVE;
+ private ContentMergeStrategy contentStrategy;
+
private TagOpt tagOption;
private FastForwardMode fastForwardMode;
@@ -275,8 +278,7 @@ public class PullCommand extends TransportCommand<PullCommand, PullResult> {
JGitText.get().pullTaskName));
// we check the updates to see which of the updated branches
- // corresponds
- // to the remote branch name
+ // corresponds to the remote branch name
AnyObjectId commitToMerge;
if (isRemote) {
Ref r = null;
@@ -354,8 +356,11 @@ public class PullCommand extends TransportCommand<PullCommand, PullResult> {
}
RebaseCommand rebase = new RebaseCommand(repo);
RebaseResult rebaseRes = rebase.setUpstream(commitToMerge)
- .setUpstreamName(upstreamName).setProgressMonitor(monitor)
- .setOperation(Operation.BEGIN).setStrategy(strategy)
+ .setProgressMonitor(monitor)
+ .setUpstreamName(upstreamName)
+ .setOperation(Operation.BEGIN)
+ .setStrategy(strategy)
+ .setContentMergeStrategy(contentStrategy)
.setPreserveMerges(
pullRebaseMode == BranchRebaseMode.PRESERVE)
.call();
@@ -363,7 +368,9 @@ public class PullCommand extends TransportCommand<PullCommand, PullResult> {
} else {
MergeCommand merge = new MergeCommand(repo);
MergeResult mergeRes = merge.include(upstreamName, commitToMerge)
- .setStrategy(strategy).setProgressMonitor(monitor)
+ .setProgressMonitor(monitor)
+ .setStrategy(strategy)
+ .setContentMergeStrategy(contentStrategy)
.setFastForward(getFastForwardMode()).call();
monitor.update(1);
result = new PullResult(fetchRes, remote, mergeRes);
@@ -442,6 +449,21 @@ public class PullCommand extends TransportCommand<PullCommand, PullResult> {
}
/**
+ * Sets the content merge strategy to use if the
+ * {@link #setStrategy(MergeStrategy) merge strategy} is "resolve" or
+ * "recursive".
+ *
+ * @param strategy
+ * the {@link ContentMergeStrategy} to be used
+ * @return {@code this}
+ * @since 5.12
+ */
+ public PullCommand setContentMergeStrategy(ContentMergeStrategy strategy) {
+ this.contentStrategy = strategy;
+ return this;
+ }
+
+ /**
* Set the specification of annotated tag behavior during fetch
*
* @param tagOpt
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
index 836175dcea..a26ffc2e66 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010, 2013 Mathias Kinzler <mathias.kinzler@sap.com>
- * Copyright (C) 2016, Laurent Delaigue <laurent.delaigue@obeo.fr> and others
+ * Copyright (C) 2016, 2021 Laurent Delaigue <laurent.delaigue@obeo.fr> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -65,6 +65,7 @@ import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.merge.ContentMergeStrategy;
import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevSort;
@@ -212,6 +213,8 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
private MergeStrategy strategy = MergeStrategy.RECURSIVE;
+ private ContentMergeStrategy contentStrategy;
+
private boolean preserveMerges = false;
/**
@@ -501,8 +504,11 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
String ourCommitName = getOurCommitName();
try (Git git = new Git(repo)) {
CherryPickResult cherryPickResult = git.cherryPick()
- .include(commitToPick).setOurCommitName(ourCommitName)
- .setReflogPrefix(REFLOG_PREFIX).setStrategy(strategy)
+ .include(commitToPick)
+ .setOurCommitName(ourCommitName)
+ .setReflogPrefix(REFLOG_PREFIX)
+ .setStrategy(strategy)
+ .setContentMergeStrategy(contentStrategy)
.call();
switch (cherryPickResult.getStatus()) {
case FAILED:
@@ -556,7 +562,8 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
.include(commitToPick)
.setOurCommitName(ourCommitName)
.setReflogPrefix(REFLOG_PREFIX)
- .setStrategy(strategy);
+ .setStrategy(strategy)
+ .setContentMergeStrategy(contentStrategy);
if (isMerge) {
pickCommand.setMainlineParentNumber(1);
// We write a MERGE_HEAD and later commit explicitly
@@ -592,6 +599,8 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
MergeCommand merge = git.merge()
.setFastForward(MergeCommand.FastForwardMode.NO_FF)
.setProgressMonitor(monitor)
+ .setStrategy(strategy)
+ .setContentMergeStrategy(contentStrategy)
.setCommit(false);
for (int i = 1; i < commitToPick.getParentCount(); i++)
merge.include(newParents.get(i));
@@ -1137,7 +1146,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
}
private List<RevCommit> calculatePickList(RevCommit headCommit)
- throws GitAPIException, NoHeadException, IOException {
+ throws IOException {
List<RevCommit> cherryPickList = new ArrayList<>();
try (RevWalk r = new RevWalk(repo)) {
r.sort(RevSort.TOPO_KEEP_BRANCH_TOGETHER, true);
@@ -1587,6 +1596,21 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
}
/**
+ * Sets the content merge strategy to use if the
+ * {@link #setStrategy(MergeStrategy) merge strategy} is "resolve" or
+ * "recursive".
+ *
+ * @param strategy
+ * the {@link ContentMergeStrategy} to be used
+ * @return {@code this}
+ * @since 5.12
+ */
+ public RebaseCommand setContentMergeStrategy(ContentMergeStrategy strategy) {
+ this.contentStrategy = strategy;
+ return this;
+ }
+
+ /**
* Whether to preserve merges during rebase
*
* @param preserve
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
index 56b3992fcd..1004d3e50f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2017 GitHub Inc. and others
+ * Copyright (C) 2012, 2021 GitHub Inc. and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -38,7 +38,9 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
+import org.eclipse.jgit.merge.ContentMergeStrategy;
import org.eclipse.jgit.merge.MergeStrategy;
+import org.eclipse.jgit.merge.Merger;
import org.eclipse.jgit.merge.ResolveMerger;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
@@ -71,6 +73,8 @@ public class StashApplyCommand extends GitCommand<ObjectId> {
private MergeStrategy strategy = MergeStrategy.RECURSIVE;
+ private ContentMergeStrategy contentStrategy;
+
/**
* Create command to apply the changes of a stashed commit
*
@@ -166,16 +170,25 @@ public class StashApplyCommand extends GitCommand<ObjectId> {
if (restoreUntracked && stashCommit.getParentCount() == 3)
untrackedCommit = revWalk.parseCommit(stashCommit.getParent(2));
- ResolveMerger merger = (ResolveMerger) strategy.newMerger(repo);
- merger.setCommitNames(new String[] { "stashed HEAD", "HEAD", //$NON-NLS-1$ //$NON-NLS-2$
- "stash" }); //$NON-NLS-1$
- merger.setBase(stashHeadCommit);
- merger.setWorkingTreeIterator(new FileTreeIterator(repo));
- boolean mergeSucceeded = merger.merge(headCommit, stashCommit);
- List<String> modifiedByMerge = merger.getModifiedFiles();
- if (!modifiedByMerge.isEmpty()) {
- repo.fireEvent(
- new WorkingTreeModifiedEvent(modifiedByMerge, null));
+ Merger merger = strategy.newMerger(repo);
+ boolean mergeSucceeded;
+ if (merger instanceof ResolveMerger) {
+ ResolveMerger resolveMerger = (ResolveMerger) merger;
+ resolveMerger
+ .setCommitNames(new String[] { "stashed HEAD", "HEAD", //$NON-NLS-1$ //$NON-NLS-2$
+ "stash" }); //$NON-NLS-1$
+ resolveMerger.setBase(stashHeadCommit);
+ resolveMerger
+ .setWorkingTreeIterator(new FileTreeIterator(repo));
+ resolveMerger.setContentMergeStrategy(contentStrategy);
+ mergeSucceeded = resolveMerger.merge(headCommit, stashCommit);
+ List<String> modifiedByMerge = resolveMerger.getModifiedFiles();
+ if (!modifiedByMerge.isEmpty()) {
+ repo.fireEvent(new WorkingTreeModifiedEvent(modifiedByMerge,
+ null));
+ }
+ } else {
+ mergeSucceeded = merger.merge(headCommit, stashCommit);
}
if (mergeSucceeded) {
DirCache dc = repo.lockDirCache();
@@ -184,11 +197,14 @@ public class StashApplyCommand extends GitCommand<ObjectId> {
dco.setFailOnConflict(true);
dco.checkout(); // Ignoring failed deletes....
if (restoreIndex) {
- ResolveMerger ixMerger = (ResolveMerger) strategy
- .newMerger(repo, true);
- ixMerger.setCommitNames(new String[] { "stashed HEAD", //$NON-NLS-1$
- "HEAD", "stashed index" }); //$NON-NLS-1$//$NON-NLS-2$
- ixMerger.setBase(stashHeadCommit);
+ Merger ixMerger = strategy.newMerger(repo, true);
+ if (ixMerger instanceof ResolveMerger) {
+ ResolveMerger resolveMerger = (ResolveMerger) ixMerger;
+ resolveMerger.setCommitNames(new String[] { "stashed HEAD", //$NON-NLS-1$
+ "HEAD", "stashed index" }); //$NON-NLS-1$//$NON-NLS-2$
+ resolveMerger.setBase(stashHeadCommit);
+ resolveMerger.setContentMergeStrategy(contentStrategy);
+ }
boolean ok = ixMerger.merge(headCommit, stashIndexCommit);
if (ok) {
resetIndex(revWalk
@@ -200,16 +216,20 @@ public class StashApplyCommand extends GitCommand<ObjectId> {
}
if (untrackedCommit != null) {
- ResolveMerger untrackedMerger = (ResolveMerger) strategy
- .newMerger(repo, true);
- untrackedMerger.setCommitNames(new String[] {
- "null", "HEAD", "untracked files" }); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
- // There is no common base for HEAD & untracked files
- // because the commit for untracked files has no parent. If
- // we use stashHeadCommit as common base (as in the other
- // merges) we potentially report conflicts for files
- // which are not even member of untracked files commit
- untrackedMerger.setBase(null);
+ Merger untrackedMerger = strategy.newMerger(repo, true);
+ if (untrackedMerger instanceof ResolveMerger) {
+ ResolveMerger resolveMerger = (ResolveMerger) untrackedMerger;
+ resolveMerger.setCommitNames(new String[] { "null", "HEAD", //$NON-NLS-1$//$NON-NLS-2$
+ "untracked files" }); //$NON-NLS-1$
+ // There is no common base for HEAD & untracked files
+ // because the commit for untracked files has no parent.
+ // If we use stashHeadCommit as common base (as in the
+ // other merges) we potentially report conflicts for
+ // files which are not even member of untracked files
+ // commit.
+ resolveMerger.setBase(null);
+ resolveMerger.setContentMergeStrategy(contentStrategy);
+ }
boolean ok = untrackedMerger.merge(headCommit,
untrackedCommit);
if (ok) {
@@ -279,6 +299,23 @@ public class StashApplyCommand extends GitCommand<ObjectId> {
}
/**
+ * Sets the content merge strategy to use if the
+ * {@link #setStrategy(MergeStrategy) merge strategy} is "resolve" or
+ * "recursive".
+ *
+ * @param strategy
+ * the {@link ContentMergeStrategy} to be used
+ * @return {@code this}
+ * @since 5.12
+ */
+ public StashApplyCommand setContentMergeStrategy(
+ ContentMergeStrategy strategy) {
+ checkCallable();
+ this.contentStrategy = strategy;
+ return this;
+ }
+
+ /**
* Whether the command should restore untracked files
*
* @param applyUntracked