try {
Ref head = repo.getRef(Constants.HEAD);
if (head == null)
- throw new NoHeadException(JGitText.get().commitOnRepoWithoutHEADCurrentlyNotSupported);
+ throw new NoHeadException(
+ JGitText.get().commitOnRepoWithoutHEADCurrentlyNotSupported);
StringBuilder refLogMessage = new StringBuilder("merge ");
// Check for FAST_FORWARD, ALREADY_UP_TO_DATE
RevCommit srcCommit = revWalk.lookupCommit(objectId);
if (revWalk.isMergedInto(srcCommit, headCommit)) {
setCallable(false);
- return new MergeResult(headCommit,
+ return new MergeResult(headCommit, srcCommit,
+ new ObjectId[] { srcCommit, headCommit },
MergeStatus.ALREADY_UP_TO_DATE, mergeStrategy);
} else if (revWalk.isMergedInto(headCommit, srcCommit)) {
// FAST_FORWARD detected: skip doing a real merge but only
checkoutNewHead(revWalk, headCommit, srcCommit);
updateHead(refLogMessage, srcCommit, head.getObjectId());
setCallable(false);
- return new MergeResult(srcCommit, MergeStatus.FAST_FORWARD,
- mergeStrategy);
+ return new MergeResult(srcCommit, headCommit,
+ new ObjectId[] { srcCommit, headCommit },
+ MergeStatus.FAST_FORWARD, mergeStrategy);
} else {
return new MergeResult(
headCommit,
+ null,
+ new ObjectId[] { srcCommit, headCommit },
MergeResult.MergeStatus.NOT_SUPPORTED,
mergeStrategy,
JGitText.get().onlyAlreadyUpToDateAndFastForwardMergesAreAvailable);
}
private void checkoutNewHead(RevWalk revWalk, RevCommit headCommit,
- RevCommit newHeadCommit) throws IOException, CheckoutConflictException {
+ RevCommit newHeadCommit) throws IOException,
+ CheckoutConflictException {
GitIndex index = repo.getIndex();
File workDir = repo.getWorkTree();
}
}
- private void updateHead(StringBuilder refLogMessage,
- ObjectId newHeadId, ObjectId oldHeadID) throws IOException,
+ private void updateHead(StringBuilder refLogMessage, ObjectId newHeadId,
+ ObjectId oldHeadID) throws IOException,
ConcurrentRefUpdateException {
RefUpdate refUpdate = repo.updateRef(Constants.HEAD);
refUpdate.setNewObjectId(newHeadId);
/**
* @param commit
- * a reference to a commit which is merged with the current
- * head
+ * a reference to a commit which is merged with the current head
* @return {@code this}
*/
public MergeCommand include(Ref commit) {
}
/**
- * @param name a name given to the commit
+ * @param name
+ * a name given to the commit
* @param commit
* the Id of a commit which is merged with the current head
* @return {@code this}
package org.eclipse.jgit.api;
import java.text.MessageFormat;
+import java.util.Map;
import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.lib.ObjectId;
}
},
/** */
+ CONFLICTING {
+ public String toString() {
+ return "Conflicting";
+ }
+ },
+ /** */
NOT_SUPPORTED {
public String toString() {
return "Not-yet-supported";
}
}
+ private ObjectId[] mergedCommits;
+
+ private ObjectId base;
+
private ObjectId newHead;
+ private Map<String, int[][]> conflicts;
+
private MergeStatus mergeStatus;
private String description;
private MergeStrategy mergeStrategy;
/**
- * @param newHead the object the head points at after the merge
- * @param mergeStatus the status the merge resulted in
- * @param mergeStrategy the used {@link MergeStrategy}
+ * @param newHead
+ * the object the head points at after the merge
+ * @param base
+ * the common base which was used to produce a content-merge. May
+ * be <code>null</code> if the merge-result was produced without
+ * computing a common base
+ * @param mergedCommits
+ * all the commits which have been merged together
+ * @param mergeStatus
+ * the status the merge resulted in
+ * @param mergeStrategy
+ * the used {@link MergeStrategy}
*/
- public MergeResult(ObjectId newHead, MergeStatus mergeStatus,
+ public MergeResult(ObjectId newHead, ObjectId base,
+ ObjectId[] mergedCommits, MergeStatus mergeStatus,
MergeStrategy mergeStrategy) {
- this.newHead = newHead;
- this.mergeStatus = mergeStatus;
- this.mergeStrategy = mergeStrategy;
+ this(newHead, base, mergedCommits, mergeStatus, mergeStrategy, null);
}
/**
- * @param newHead the object the head points at after the merge
- * @param mergeStatus the status the merge resulted in
- * @param mergeStrategy the used {@link MergeStrategy}
- * @param description a user friendly description of the merge result
+ * @param newHead
+ * the object the head points at after the merge
+ * @param base
+ * the common base which was used to produce a content-merge. May
+ * be <code>null</code> if the merge-result was produced without
+ * computing a common base
+ * @param mergedCommits
+ * all the commits which have been merged together
+ * @param mergeStatus
+ * the status the merge resulted in
+ * @param mergeStrategy
+ * the used {@link MergeStrategy}
+ * @param description
+ * a user friendly description of the merge result
*/
- public MergeResult(ObjectId newHead, MergeStatus mergeStatus,
+ public MergeResult(ObjectId newHead, ObjectId base,
+ ObjectId[] mergedCommits, MergeStatus mergeStatus,
MergeStrategy mergeStrategy, String description) {
this.newHead = newHead;
+ this.mergedCommits = mergedCommits;
+ this.base = base;
this.mergeStatus = mergeStatus;
this.mergeStrategy = mergeStrategy;
this.description = description;
return mergeStatus;
}
+ /**
+ * @return all the commits which have been merged together
+ */
+ public ObjectId[] getMergedCommits() {
+ return mergedCommits;
+ }
+
+ /**
+ * @return base the common base which was used to produce a content-merge.
+ * May be <code>null</code> if the merge-result was produced without
+ * computing a common base
+ */
+ public ObjectId getBase() {
+ return base;
+ }
+
@Override
public String toString() {
+ boolean first = true;
+ StringBuilder commits = new StringBuilder();
+ for (ObjectId commit : mergedCommits) {
+ if (!first)
+ commits.append(", ");
+ else
+ first = false;
+ commits.append(ObjectId.toString(commit));
+ }
return MessageFormat.format(
JGitText.get().mergeUsingStrategyResultedInDescription,
- mergeStrategy.getName(), mergeStatus, (description == null ? ""
- : ", " + description));
+ commits, ObjectId.toString(base), mergeStrategy.getName(),
+ mergeStatus, (description == null ? "" : ", " + description));
}
+ /**
+ * @param conflicts
+ * the conflicts to set
+ */
+ public void setConflicts(Map<String, int[][]> conflicts) {
+ this.conflicts = conflicts;
+ }
+
+ /**
+ * Returns information about the conflicts which occurred during a
+ * {@link MergeCommand}. The returned value maps the path of a conflicting
+ * file to a two-dimensional int-array of line-numbers telling where in the
+ * file conflict markers for which merged commit can be found.
+ * <p>
+ * If the returned value contains a mapping "path"->[x][y]=z then this means
+ * <ul>
+ * <li>the file with path "path" contains conflicts</li>
+ * <li>if y < "number of merged commits": for conflict number x in this file
+ * the chunk which was copied from commit number y starts on line number z.
+ * All numberings and line numbers start with 0.</li>
+ * <li>if y == "number of merged commits": the first non-conflicting line
+ * after conflict number x starts at line number z</li>
+ * </ul>
+ * <p>
+ * Example code how to parse this data:
+ * <pre> MergeResult m=...;
+ * Map<String, int[][]> allConflicts = m.getConflicts();
+ * for (String path : allConflicts.keySet()) {
+ * int[][] c = allConflicts.get(path);
+ * System.out.println("Conflicts in file " + path);
+ * for (int i = 0; i < c.length; ++i) {
+ * System.out.println(" Conflict #" + i);
+ * for (int j = 0; j < (c[i].length) - 1; ++j) {
+ * if (c[i][j] >= 0)
+ * System.out.println(" Chunk for "
+ * + m.getMergedCommits()[j] + " starts on line #"
+ * + c[i][j]);
+ * }
+ * }
+ * }</pre>
+ *
+ * @return the conflicts or <code>null</code> if no conflict occured
+ */
+ public Map<String, int[][]> getConflicts() {
+ return conflicts;
+ }
}