From 5304e6f6e3ebd3bb5ec9fdf079e957f9c987d468 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 11 May 2011 20:31:57 +0400 Subject: [PATCH] [Git] IDEA-51187 Auto-merge for cherry-pick --- .../src/git4idea/commands/GitFileUtils.java | 9 -- .../history/browser/CherryPicker.java | 5 +- .../history/browser/LowLevelAccess.java | 3 +- .../history/browser/LowLevelAccessImpl.java | 105 +++++++++++++++++- 4 files changed, 105 insertions(+), 17 deletions(-) diff --git a/plugins/git4idea/src/git4idea/commands/GitFileUtils.java b/plugins/git4idea/src/git4idea/commands/GitFileUtils.java index 31d09e596a0a..76f1e4a0ca30 100644 --- a/plugins/git4idea/src/git4idea/commands/GitFileUtils.java +++ b/plugins/git4idea/src/git4idea/commands/GitFileUtils.java @@ -60,15 +60,6 @@ public class GitFileUtils { } } - public static void cherryPick(final Project project, final VirtualFile root, final String hash) throws VcsException { - GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.CHERRY_PICK); - handler.addParameters("-x", "-n", hash); - handler.endOptions(); - //handler.addRelativePaths(new FilePathImpl(root)); - handler.setNoSSH(true); - handler.run(); - } - /** * Delete files * diff --git a/plugins/git4idea/src/git4idea/history/browser/CherryPicker.java b/plugins/git4idea/src/git4idea/history/browser/CherryPicker.java index 43c0486ea12a..2146c7ac22c7 100644 --- a/plugins/git4idea/src/git4idea/history/browser/CherryPicker.java +++ b/plugins/git4idea/src/git4idea/history/browser/CherryPicker.java @@ -129,9 +129,8 @@ public class CherryPicker { private void cherryPickStep(CheckinEnvironment ce, int i) { final GitCommit commit = myCommits.get(i); - final SHAHash hash = commit.getHash(); try { - myAccess.cherryPick(hash); + myAccess.cherryPick(commit); } catch (VcsException e) { myExceptions.add(e); @@ -141,7 +140,7 @@ public class CherryPicker { final Collection paths = ChangesUtil.getPaths(changes); String message = ce.getDefaultMessageFor(paths.toArray(new FilePath[paths.size()])); message = (message == null) ? new StringBuilder().append(commit.getDescription()).append("(cherry picked from commit ") - .append(hash.getValue()).append(")").toString() : message; + .append(commit.getShortHash()).append(")").toString() : message; myMessagesInOrder.add(message); myFilesToMove.put(message, paths); diff --git a/plugins/git4idea/src/git4idea/history/browser/LowLevelAccess.java b/plugins/git4idea/src/git4idea/history/browser/LowLevelAccess.java index fe88d733ca3f..be147979b3ce 100644 --- a/plugins/git4idea/src/git4idea/history/browser/LowLevelAccess.java +++ b/plugins/git4idea/src/git4idea/history/browser/LowLevelAccess.java @@ -16,7 +16,6 @@ package git4idea.history.browser; import com.intellij.openapi.util.Getter; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.AsynchConsumer; @@ -57,7 +56,7 @@ public interface LowLevelAccess { void loadAllTags(final Collection sink) throws VcsException; - void cherryPick(SHAHash hash) throws VcsException; + void cherryPick(GitCommit hash) throws VcsException; void loadHashesWithParents(final @NotNull Collection startingPoints, @NotNull final Collection filters, final AsynchConsumer consumer, Getter isCanceled, int useMaxCnt) throws VcsException; List getCommitDetails(final Collection commitIds, SymbolicRefs refs) throws VcsException; diff --git a/plugins/git4idea/src/git4idea/history/browser/LowLevelAccessImpl.java b/plugins/git4idea/src/git4idea/history/browser/LowLevelAccessImpl.java index b2fe33993ac1..1b88653e0f55 100644 --- a/plugins/git4idea/src/git4idea/history/browser/LowLevelAccessImpl.java +++ b/plugins/git4idea/src/git4idea/history/browser/LowLevelAccessImpl.java @@ -16,24 +16,38 @@ */ package git4idea.history.browser; +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationListener; +import com.intellij.notification.NotificationType; +import com.intellij.notification.Notifications; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Getter; +import com.intellij.openapi.util.Key; import com.intellij.openapi.vcs.FilePathImpl; import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.history.VcsRevisionNumber; +import com.intellij.openapi.vcs.merge.MergeDialogCustomizer; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.AsynchConsumer; import git4idea.GitBranch; +import git4idea.GitRevisionNumber; import git4idea.GitTag; -import git4idea.commands.GitFileUtils; +import git4idea.GitVcs; +import git4idea.commands.GitCommand; +import git4idea.commands.GitLineHandler; +import git4idea.commands.GitLineHandlerAdapter; import git4idea.config.GitConfigUtil; import git4idea.history.GitHistoryUtils; import git4idea.history.wholeTree.CommitHashPlusParents; +import git4idea.merge.GitMergeConflictResolver; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.event.HyperlinkEvent; import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; public class LowLevelAccessImpl implements LowLevelAccess { private final static Logger LOG = Logger.getInstance("#git4idea.history.browser.LowLevelAccessImpl"); @@ -181,7 +195,92 @@ public class LowLevelAccessImpl implements LowLevelAccess { GitTag.listAsStrings(myProject, myRoot, sink, null); } - public void cherryPick(SHAHash hash) throws VcsException { - GitFileUtils.cherryPick(myProject, myRoot, hash.getValue()); + public void cherryPick(GitCommit commit) throws VcsException { + final GitLineHandler handler = new GitLineHandler(myProject, myRoot, GitCommand.CHERRY_PICK); + handler.addParameters("-x", "-n", commit.getHash().getValue()); + handler.endOptions(); + handler.setNoSSH(true); + + final AtomicBoolean conflict = new AtomicBoolean(); + + handler.addLineListener(new GitLineHandlerAdapter() { + public void onLineAvailable(String line, Key outputType) { + if (line.contains("after resolving the conflicts, mark the corrected paths")) { + conflict.set(true); + } + } + }); + handler.runInCurrentThread(null); + + if (conflict.get()) { + new CherryPickConflictResolver(myProject, commit.getShortHash().getString(), commit.getAuthor(), commit.getSubject()).merge(Collections.singleton(myRoot)); + } else { + final List errors = handler.errors(); + if (!errors.isEmpty()) { + throw errors.get(0); + } + } + } + + private static class CherryPickConflictResolver extends GitMergeConflictResolver { + + private String myCommitHash; + private String myCommitAuthor; + private String myCommitMessage; + + public CherryPickConflictResolver(Project project, String commitHash, String commitAuthor, String commitMessage) { + super(project, true, new CherryPickMergeDialogCustomizer(commitHash, commitAuthor, commitMessage), "Cherry-picked with conflicts", ""); + myCommitHash = commitHash; + myCommitAuthor = commitAuthor; + myCommitMessage = commitMessage; + } + + @Override + protected void notifyUnresolvedRemain(final Collection roots) { + Notifications.Bus.notify(new Notification(GitVcs.IMPORTANT_ERROR_NOTIFICATION, "Conflicts were not resolved during cherry-pick", + "Cherry-pick is not complete, you have unresolved merges in your working tree
" + + "Resolve conflicts.", + NotificationType.WARNING, new NotificationListener() { + @Override + public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { + if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + if (event.getDescription().equals("resolve")) { + new CherryPickConflictResolver(myProject, myCommitHash, myCommitAuthor, myCommitMessage).justMerge(roots); + } + } + } + })); + } + } + + private static class CherryPickMergeDialogCustomizer extends MergeDialogCustomizer { + + private String myCommitHash; + private String myCommitAuthor; + private String myCommitMessage; + + public CherryPickMergeDialogCustomizer(String commitHash, String commitAuthor, String commitMessage) { + myCommitHash = commitHash; + myCommitAuthor = commitAuthor; + myCommitMessage = commitMessage; + } + + @Override + public String getMultipleFileMergeDescription(Collection files) { + return "Conflicts during cherry-picking commit " + myCommitHash + " made by " + myCommitAuthor + "
" + + "\"" + myCommitMessage + "\""; + } + + @Override + public String getLeftPanelTitle(VirtualFile file) { + return "Local changes"; + } + + @Override + public String getRightPanelTitle(VirtualFile file, VcsRevisionNumber lastRevisionNumber) { + return "Changes from cherry-pick " + ((GitRevisionNumber)lastRevisionNumber).toShortString() + ""; + } + } + }