[git] IDEA-85684 Better support of commit when CHERRY_PICK_HEAD exists

* GitCheckinEnvironment already has support for the case when the MERGE_HEAD file exists. Add support for cherry-pick.
* Make better dialog about partial commit: show the files via SelectFilePathsDialog.
This commit is contained in:
Kirill Likhodedov
2012-12-12 13:45:46 +04:00
parent 2380fd55be
commit eafd53deb3
4 changed files with 54 additions and 30 deletions
@@ -36,8 +36,8 @@ public class SelectFilePathsDialog extends AbstractSelectFilesDialog<FilePath> {
public SelectFilePathsDialog(final Project project, List<FilePath> originalFiles, final String prompt,
final VcsShowConfirmationOption confirmationOption,
@Nullable String okActionName, @Nullable String cancelActionName) {
super(project, false, confirmationOption, prompt, true);
@Nullable String okActionName, @Nullable String cancelActionName, boolean showDoNotAskOption) {
super(project, false, confirmationOption, prompt, showDoNotAskOption);
myFileList = new ChangesTreeList<FilePath>(project, originalFiles, true, true, null, null) {
protected DefaultTreeModel buildTreeModel(final List<FilePath> changes, ChangeNodeDecorator changeNodeDecorator) {
return new TreeModelBuilder(project, false).buildModelFromFilePaths(changes);
@@ -190,7 +190,7 @@ public class AbstractVcsHelperImpl extends AbstractVcsHelper {
}
final SelectFilePathsDialog dlg =
new SelectFilePathsDialog(myProject, files, prompt, confirmationOption, okActionName, cancelActionName);
new SelectFilePathsDialog(myProject, files, prompt, confirmationOption, okActionName, cancelActionName, true);
dlg.setTitle(title);
if (! confirmationOption.isPersistent()) {
dlg.setDoNotAskOption(null);
@@ -15,10 +15,11 @@
*/
package git4idea.checkin;
import com.intellij.CommonBundle;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.CheckinProjectPanel;
@@ -26,6 +27,7 @@ import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.ObjectsConvertor;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.*;
import com.intellij.openapi.vcs.changes.ui.SelectFilePathsDialog;
import com.intellij.openapi.vcs.checkin.CheckinChangeListSpecificComponent;
import com.intellij.openapi.vcs.checkin.CheckinEnvironment;
import com.intellij.openapi.vcs.ui.RefreshableOnComponent;
@@ -182,10 +184,11 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
commit(myProject, root, files, messageFile, myNextCommitAuthor, myNextCommitAmend, myNextCommitAuthorDate);
}
catch (VcsException ex) {
if (!isMergeCommit(ex)) {
PartialOperation partialOperation = isMergeCommit(ex);
if (partialOperation == PartialOperation.NONE) {
throw ex;
}
if (!mergeCommit(myProject, root, added, removed, messageFile, myNextCommitAuthor, exceptions)) {
if (!mergeCommit(myProject, root, added, removed, messageFile, myNextCommitAuthor, exceptions, partialOperation)) {
throw ex;
}
}
@@ -223,6 +226,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
/**
* Preform a merge commit
*
*
* @param project a project
* @param root a vcs root
* @param added added files
@@ -230,6 +234,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
* @param messageFile a message file for commit
* @param author an author
* @param exceptions the list of exceptions to report
* @param partialOperation
* @return true if merge commit was successful
*/
private static boolean mergeCommit(final Project project,
@@ -238,7 +243,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
final Set<FilePath> removed,
final File messageFile,
final String author,
List<VcsException> exceptions) {
List<VcsException> exceptions, @NotNull final PartialOperation partialOperation) {
HashSet<FilePath> realAdded = new HashSet<FilePath>();
HashSet<FilePath> realRemoved = new HashSet<FilePath>();
// perform diff
@@ -278,26 +283,20 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
realAdded.removeAll(added);
realRemoved.removeAll(removed);
if (realAdded.size() != 0 || realRemoved.size() != 0) {
TreeSet<String> files = new TreeSet<String>();
for (FilePath f : realAdded) {
files.add(f.getPresentableUrl());
}
for (FilePath f : realRemoved) {
files.add(f.getPresentableUrl());
}
final StringBuilder fileList = new StringBuilder();
for (String f : files) {
//noinspection HardCodedStringLiteral
fileList.append("<li>");
fileList.append(StringUtil.escapeXml(f));
fileList.append("</li>");
}
final int[] rc = new int[1];
final List<FilePath> files = new ArrayList<FilePath>();
files.addAll(realAdded);
files.addAll(realRemoved);
final Ref<Boolean> mergeAll = new Ref<Boolean>();
try {
GuiUtils.runOrInvokeAndWait(new Runnable() {
public void run() {
rc[0] = Messages.showOkCancelDialog(project, GitBundle.message("commit.partial.merge.message", fileList.toString()),
GitBundle.getString("commit.partial.merge.title"), null);
String message = GitBundle.message("commit.partial.merge.message", partialOperation.getName());
SelectFilePathsDialog dialog = new SelectFilePathsDialog(project, files, message,
null, "Commit All Files", CommonBundle.getCancelButtonText(), false);
dialog.setTitle(GitBundle.getString("commit.partial.merge.title"));
dialog.show();
mergeAll.set(dialog.isOK());
}
});
}
@@ -307,7 +306,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
catch (Exception ex) {
throw new RuntimeException("Unable to invoke a message box on AWT thread", ex);
}
if (rc[0] != 0) {
if (!mergeAll.get()) {
return false;
}
// update non-indexed files
@@ -342,14 +341,21 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
}
/**
* Check if commit has failed due to unfinished merge
* Check if commit has failed due to unfinished merge or cherry-pick.
*
*
* @param ex an exception to examine
* @return true if exception means that there is a partial commit during merge
*/
private static boolean isMergeCommit(final VcsException ex) {
//noinspection HardCodedStringLiteral
return ex.getMessage().contains("fatal: cannot do a partial commit during a merge.");
private static PartialOperation isMergeCommit(final VcsException ex) {
String message = ex.getMessage();
if (message.contains("fatal: cannot do a partial commit during a merge")) {
return PartialOperation.MERGE;
}
if (message.contains("fatal: cannot do a partial commit during a cherry-pick")) {
return PartialOperation.CHERRY_PICK;
}
return PartialOperation.NONE;
}
/**
@@ -514,6 +520,22 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
return rc;
}
private enum PartialOperation {
NONE("none"),
MERGE("merge"),
CHERRY_PICK("cherry-pick");
private final String myName;
PartialOperation(String name) {
myName = name;
}
String getName() {
return myName;
}
}
/**
* Sort changes by roots
*
@@ -62,7 +62,9 @@ commit.author.tooltip=<html>Specify a commit author here if it is different from
commit.author=&Author:
commit.amend.tooltip=<html>Merge this commit with the previous one</html>
commit.amend=Amend commit
commit.partial.merge.message=<html>The following files are not included in commit.<ul>{0}</ul>Perform commit with all files included?</html>
commit.partial.merge.message=Partial commit during a {0} is not allowed.\n\
The following files are not included in commit.\n\
Perform commit with all files included?
commit.partial.merge.title=Partial Merge Commit
commit.push.changes.tooltip=When this option is enabled, changes are pushed to the server after commit.
commit.push.changes=&Push Changes