aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit
diff options
context:
space:
mode:
authorRobin Stocker <robin@nibor.org>2011-04-03 19:37:55 +0200
committerChris Aniszczyk <caniszczyk@gmail.com>2011-04-06 13:28:10 -0500
commit6e10aa42e90a25b82f00f0c27574f57ffa9e4a25 (patch)
treee2bf294858e9a16220df5ab54508d94267c14109 /org.eclipse.jgit
parentfbf35fea4ec254339f9b0eee7865eb6ccfe22700 (diff)
downloadjgit-6e10aa42e90a25b82f00f0c27574f57ffa9e4a25.tar.gz
jgit-6e10aa42e90a25b82f00f0c27574f57ffa9e4a25.zip
Add CHERRY_PICK_HEAD for cherry-pick conflicts
Add handling of CHERRY_PICK_HEAD file in .git (similar to MERGE_HEAD), which is written in case of a conflicting cherry-pick merge. It is used so that Repository.getRepositoryState can return the new states CHERRY_PICKING and CHERRY_PICKING_RESOLVED. These states, as well as CHERRY_PICK_HEAD can be used in EGit to properly show the merge tool. Also, in case of a conflict, MERGE_MSG is written with the original commit message and a "Conflicts" section appended. This way, the cherry-picked message is not lost and can later be re-used in the commit dialog. Bug: 339092 Change-Id: I947967fdc2f1d55016c95106b104c2afcc9797a1 Signed-off-by: Robin Stocker <robin@nibor.org> Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
Diffstat (limited to 'org.eclipse.jgit')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java11
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java24
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java72
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryState.java20
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java21
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/storage/file/RefDirectory.java3
9 files changed, 151 insertions, 10 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 1ececd23f0..c8b7e89f1b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
@@ -60,6 +60,7 @@ import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Ref.Storage;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.merge.MergeMessageFormatter;
import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.merge.ResolveMerger;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -150,7 +151,15 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> {
if (merger.failed())
return new CherryPickResult(merger.getFailingPaths());
- // merge conflicts
+ // there are merge conflicts
+
+ String message = new MergeMessageFormatter()
+ .formatWithConflicts(srcCommit.getFullMessage(),
+ merger.getUnmergedPaths());
+
+ repo.writeCherryPickHead(srcCommit.getId());
+ repo.writeMergeCommitMsg(message);
+
return CherryPickResult.CONFLICT;
}
}
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 963e3ed842..2412e2c6c0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -233,6 +233,9 @@ public class CommitCommand extends GitCommand<RevCommit> {
// used for merge commits
repo.writeMergeCommitMsg(null);
repo.writeMergeHeads(null);
+ } else if (state == RepositoryState.CHERRY_PICKING_RESOLVED) {
+ repo.writeMergeCommitMsg(null);
+ repo.writeCherryPickHead(null);
}
return revCommit;
}
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 cf2111ea7e..7e2e677993 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -399,6 +399,9 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
Constants.CHARACTER_ENCODING));
createFile(rebaseDir, STOPPED_SHA, repo.newObjectReader().abbreviate(
commitToPick).name());
+ // Remove cherry pick state file created by CherryPickCommand, it's not
+ // needed for rebase
+ repo.writeCherryPickHead(null);
return new RebaseResult(commitToPick);
}
@@ -744,6 +747,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
}
// cleanup the files
FileUtils.delete(rebaseDir, FileUtils.RECURSIVE);
+ repo.writeCherryPickHead(null);
return result;
} finally {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
index d55767d3a6..24aae22ffd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
@@ -129,11 +129,12 @@ public class ResetCommand extends GitCommand<Ref> {
RevCommit commit;
try {
- boolean merging = false;
- if (repo.getRepositoryState().equals(RepositoryState.MERGING)
- || repo.getRepositoryState().equals(
- RepositoryState.MERGING_RESOLVED))
- merging = true;
+ RepositoryState state = repo.getRepositoryState();
+ final boolean merging = state.equals(RepositoryState.MERGING)
+ || state.equals(RepositoryState.MERGING_RESOLVED);
+ final boolean cherryPicking = state
+ .equals(RepositoryState.CHERRY_PICKING)
+ || state.equals(RepositoryState.CHERRY_PICKING_RESOLVED);
// resolve the ref to a commit
final ObjectId commitId;
@@ -183,8 +184,12 @@ public class ResetCommand extends GitCommand<Ref> {
}
- if (mode != ResetType.SOFT && merging)
- resetMerge();
+ if (mode != ResetType.SOFT) {
+ if (merging)
+ resetMerge();
+ else if (cherryPicking)
+ resetCherryPick();
+ }
setCallable(false);
r = ru.getRef();
@@ -255,4 +260,9 @@ public class ResetCommand extends GitCommand<Ref> {
repo.writeMergeCommitMsg(null);
}
+ private void resetCherryPick() throws IOException {
+ repo.writeCherryPickHead(null);
+ repo.writeMergeCommitMsg(null);
+ }
+
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
index 0290689c81..1d77cc174f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
@@ -536,6 +536,9 @@ public final class Constants {
/** name of the file containing the IDs of the parents of a merge commit */
public static final String MERGE_HEAD = "MERGE_HEAD";
+ /** name of the file containing the ID of a cherry pick commit in case of conflicts */
+ public static final String CHERRY_PICK_HEAD = "CHERRY_PICK_HEAD";
+
/**
* name of the ref ORIG_HEAD used by certain commands to store the original
* value of HEAD
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
index 759ab3e3a2..4847a5dbf5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -922,7 +922,7 @@ public abstract class Repository {
return RepositoryState.REBASING_MERGE;
// Both versions
- if (new File(getDirectory(), "MERGE_HEAD").exists()) {
+ if (new File(getDirectory(), Constants.MERGE_HEAD).exists()) {
// we are merging - now check whether we have unmerged paths
try {
if (!readDirCache().hasUnmergedPaths()) {
@@ -941,6 +941,20 @@ public abstract class Repository {
if (new File(getDirectory(), "BISECT_LOG").exists())
return RepositoryState.BISECTING;
+ if (new File(getDirectory(), Constants.CHERRY_PICK_HEAD).exists()) {
+ try {
+ if (!readDirCache().hasUnmergedPaths()) {
+ // no unmerged paths
+ return RepositoryState.CHERRY_PICKING_RESOLVED;
+ }
+ } catch (IOException e) {
+ // fall through to CHERRY_PICKING
+ e.printStackTrace();
+ }
+
+ return RepositoryState.CHERRY_PICKING;
+ }
+
return RepositoryState.SAFE;
}
@@ -1192,4 +1206,60 @@ public abstract class Repository {
FileUtils.delete(mergeHeadFile);
}
}
+
+ /**
+ * Return the information stored in the file $GIT_DIR/CHERRY_PICK_HEAD.
+ *
+ * @return object id from CHERRY_PICK_HEAD file or {@code null} if this file
+ * doesn't exist. Also if the file exists but is empty {@code null}
+ * will be returned
+ * @throws IOException
+ * @throws NoWorkTreeException
+ * if this is bare, which implies it has no working directory.
+ * See {@link #isBare()}.
+ */
+ public ObjectId readCherryPickHead() throws IOException,
+ NoWorkTreeException {
+ if (isBare() || getDirectory() == null)
+ throw new NoWorkTreeException();
+
+ File mergeHeadFile = new File(getDirectory(),
+ Constants.CHERRY_PICK_HEAD);
+ byte[] raw;
+ try {
+ raw = IO.readFully(mergeHeadFile);
+ } catch (FileNotFoundException notFound) {
+ return null;
+ }
+
+ if (raw.length == 0)
+ return null;
+
+ return ObjectId.fromString(raw, 0);
+ }
+
+ /**
+ * Write cherry pick commit into $GIT_DIR/CHERRY_PICK_HEAD. This is used in
+ * case of conflicts to store the cherry which was tried to be picked.
+ *
+ * @param head
+ * an object id of the cherry commit or <code>null</code> to
+ * delete the file
+ * @throws IOException
+ */
+ public void writeCherryPickHead(ObjectId head) throws IOException {
+ File cherryPickHeadFile = new File(gitDir, Constants.CHERRY_PICK_HEAD);
+ if (head != null) {
+ BufferedOutputStream bos = new BufferedOutputStream(
+ new FileOutputStream(cherryPickHeadFile));
+ try {
+ head.copyTo(bos);
+ bos.write('\n');
+ } finally {
+ bos.close();
+ }
+ } else {
+ FileUtils.delete(cherryPickHeadFile, FileUtils.SKIP_MISSING);
+ }
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryState.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryState.java
index e0b5389ac0..10170624b1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryState.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryState.java
@@ -93,6 +93,26 @@ public enum RepositoryState {
public String getDescription() { return JGitText.get().repositoryState_merged; }
},
+ /** An unfinished cherry-pick. Must resolve or reset before continuing normally
+ */
+ CHERRY_PICKING {
+ public boolean canCheckout() { return false; }
+ public boolean canResetHead() { return true; }
+ public boolean canCommit() { return false; }
+ public String getDescription() { return JGitText.get().repositoryState_conflicts; }
+ },
+
+ /**
+ * A cherry-pick where all conflicts have been resolved. The index does not
+ * contain any unmerged paths.
+ */
+ CHERRY_PICKING_RESOLVED {
+ public boolean canCheckout() { return true; }
+ public boolean canResetHead() { return true; }
+ public boolean canCommit() { return true; }
+ public String getDescription() { return JGitText.get().repositoryState_merged; }
+ },
+
/**
* An unfinished rebase or am. Must resolve, skip or abort before normal work can take place
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java
index cdd7a2f371..96395d0bfa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java
@@ -123,6 +123,27 @@ public class MergeMessageFormatter {
return sb.toString();
}
+ /**
+ * Add section with conflicting paths to merge message.
+ *
+ * @param message
+ * the original merge message
+ * @param conflictingPaths
+ * the paths with conflicts
+ * @return merge message with conflicting paths added
+ */
+ public String formatWithConflicts(String message,
+ List<String> conflictingPaths) {
+ StringBuilder sb = new StringBuilder(message);
+ if (!message.endsWith("\n"))
+ sb.append("\n");
+ sb.append("\n");
+ sb.append("Conflicts:\n");
+ for (String conflictingPath : conflictingPaths)
+ sb.append('\t').append(conflictingPath).append('\n');
+ return sb.toString();
+ }
+
private static String joinNames(List<String> names, String singular,
String plural) {
if (names.size() == 1)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/RefDirectory.java
index 5a36a71ee4..bba634a6b6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/RefDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/RefDirectory.java
@@ -130,7 +130,8 @@ public class RefDirectory extends RefDatabase {
/** The names of the additional refs supported by this class */
private static final String[] additionalRefsNames = new String[] {
- Constants.MERGE_HEAD, Constants.FETCH_HEAD, Constants.ORIG_HEAD };
+ Constants.MERGE_HEAD, Constants.FETCH_HEAD, Constants.ORIG_HEAD,
+ Constants.CHERRY_PICK_HEAD };
private final FileRepository parent;