From 8b7c2730b59144d497df096dedd3b52e3a1a5086 Mon Sep 17 00:00:00 2001 From: Constantine Plotnikov Date: Wed, 30 Sep 2009 22:25:30 +0400 Subject: [PATCH] git4idea: Added blocking project update until unstashed merge resolves. --- .../src/git4idea/update/GitUpdateEnvironment.java | 253 +++++++++++++-------- 1 file changed, 155 insertions(+), 98 deletions(-) diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java b/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java index 2710e5ef53..73b3ba580c 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java @@ -19,6 +19,7 @@ import com.intellij.openapi.options.Configurable; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ex.ProjectManagerEx; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Ref; @@ -36,7 +37,10 @@ import git4idea.GitRevisionNumber; import git4idea.GitUtil; import git4idea.GitVcs; import git4idea.changes.GitChangeUtils; -import git4idea.commands.*; +import git4idea.commands.GitHandler; +import git4idea.commands.GitHandlerUtil; +import git4idea.commands.GitLineHandler; +import git4idea.commands.GitLineHandlerAdapter; import git4idea.config.GitVcsSettings; import git4idea.i18n.GitBundle; import git4idea.merge.MergeChangeCollector; @@ -95,6 +99,7 @@ public class GitUpdateEnvironment implements UpdateEnvironment { @NotNull Ref sequentialUpdatesContextRef) throws ProcessCanceledException { List exceptions = new ArrayList(); + ProjectManagerEx projectManager = ProjectManagerEx.getInstanceEx(); for (final VirtualFile root : GitUtil.gitRoots(Arrays.asList(filePaths))) { try { // check if there is a remote for the branch @@ -106,122 +111,119 @@ public class GitUpdateEnvironment implements UpdateEnvironment { if (value == null || value.length() == 0) { continue; } - boolean stashCreated = - mySettings.UPDATE_STASH && GitStashUtils.saveStash(myProject, root, "Uncommitted changes before update operation"); + final Ref cancelled = new Ref(false); + final Ref ex = new Ref(); + projectManager.blockReloadingProjectOnExternalChanges(); try { - // remember the current position - GitRevisionNumber before = GitRevisionNumber.resolve(myProject, root, "HEAD"); - // do pull - GitLineHandler h = new GitLineHandler(myProject, root, GitHandler.PULL); - // ignore merge failure for the pull - h.ignoreErrorCode(1); - switch (mySettings.UPDATE_TYPE) { - case REBASE: - h.addParameters("--rebase"); - break; - case MERGE: - h.addParameters("--no-rebase"); - break; - case BRANCH_DEFAULT: - // use default for the branch - break; - default: - assert false : "Unknown update type: " + mySettings.UPDATE_TYPE; - } - h.addParameters("--no-stat"); - h.addParameters("-v"); - final Ref cancelled = new Ref(false); + boolean stashCreated = + mySettings.UPDATE_STASH && GitStashUtils.saveStash(myProject, root, "Uncommitted changes before update operation"); try { - RebaseConflictDetector rebaseConflictDetector = new RebaseConflictDetector(); - h.addLineListener(rebaseConflictDetector); - try { - GitHandlerUtil.doSynchronouslyWithExceptions(h, progressIndicator); + // remember the current position + GitRevisionNumber before = GitRevisionNumber.resolve(myProject, root, "HEAD"); + // do pull + GitLineHandler h = new GitLineHandler(myProject, root, GitHandler.PULL); + // ignore merge failure for the pull + h.ignoreErrorCode(1); + switch (mySettings.UPDATE_TYPE) { + case REBASE: + h.addParameters("--rebase"); + break; + case MERGE: + h.addParameters("--no-rebase"); + break; + case BRANCH_DEFAULT: + // use default for the branch + break; + default: + assert false : "Unknown update type: " + mySettings.UPDATE_TYPE; } - finally { - if (!rebaseConflictDetector.isRebaseConflict()) { - exceptions.addAll(h.errors()); + h.addParameters("--no-stat"); + h.addParameters("-v"); + try { + RebaseConflictDetector rebaseConflictDetector = new RebaseConflictDetector(); + h.addLineListener(rebaseConflictDetector); + try { + GitHandlerUtil.doSynchronouslyWithExceptions(h, progressIndicator); } - } - do { - final Ref ex = new Ref(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - public void run() { - try { - List affectedFiles = GitChangeUtils.unmergedFiles(myProject, root); - while (affectedFiles.size() != 0) { - AbstractVcsHelper.getInstance(myProject).showMergeDialog(affectedFiles, myVcs.getMergeProvider()); - affectedFiles = GitChangeUtils.unmergedFiles(myProject, root); - if (affectedFiles.size() != 0) { - int result = Messages.showYesNoDialog(myProject, GitBundle.message("update.rebase.unmerged", affectedFiles.size(), - root.getPresentableUrl()), - GitBundle.getString("update.rebase.unmerged.title"), Messages.getErrorIcon()); - if (result != 0) { - cancelled.set(true); - return; - } - } + finally { + if (!rebaseConflictDetector.isRebaseConflict()) { + exceptions.addAll(h.errors()); + } + } + do { + mergeFiles(root, cancelled, ex); + //noinspection ThrowableResultOfMethodCallIgnored + if (ex.get() != null) { + //noinspection ThrowableResultOfMethodCallIgnored + throw GitUtil.rethrowVcsException(ex.get()); + } + checkLocallyModified(root, cancelled, ex); + //noinspection ThrowableResultOfMethodCallIgnored + if (ex.get() != null) { + //noinspection ThrowableResultOfMethodCallIgnored + throw GitUtil.rethrowVcsException(ex.get()); + } + if (cancelled.get()) { + break; + } + doRebase(progressIndicator, root, rebaseConflictDetector, "--continue"); + final Ref result = new Ref(); + noChangeLoop: + while (rebaseConflictDetector.isNoChange()) { + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + public void run() { + int rc = Messages.showDialog(myProject, GitBundle.message("update.rebase.no.change", root.getPresentableUrl()), + GitBundle.getString("update.rebase.no.change.title"), + new String[]{GitBundle.getString("update.rebase.no.change.skip"), + GitBundle.getString("update.rebase.no.change.retry"), + GitBundle.getString("update.rebase.no.change.cancel")}, 0, Messages.getErrorIcon()); + result.set(rc); } - if(!GitUpdateLocallyModifiedDialog.showIfNeeded(myProject, root)) { + }); + switch (result.get()) { + case 0: + doRebase(progressIndicator, root, rebaseConflictDetector, "--skip"); + continue noChangeLoop; + case 1: + continue noChangeLoop; + case 2: cancelled.set(true); - } - } - catch (Throwable t) { - ex.set(t); + break noChangeLoop; } } - }); - //noinspection ThrowableResultOfMethodCallIgnored - if (ex.get() != null) { - //noinspection ThrowableResultOfMethodCallIgnored - throw GitUtil.rethrowVcsException(ex.get()); } + while (rebaseConflictDetector.isRebaseConflict() && !cancelled.get()); if (cancelled.get()) { - break; - } - doRebase(progressIndicator, root, rebaseConflictDetector, "--continue"); - final Ref result = new Ref(); - noChangeLoop: - while (rebaseConflictDetector.isNoChange()) { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - public void run() { - int rc = Messages.showDialog(myProject, GitBundle.message("update.rebase.no.change", root.getPresentableUrl()), - GitBundle.getString("update.rebase.no.change.title"), - new String[]{GitBundle.getString("update.rebase.no.change.skip"), - GitBundle.getString("update.rebase.no.change.retry"), - GitBundle.getString("update.rebase.no.change.cancel")}, 0, Messages.getErrorIcon()); - result.set(rc); - } - }); - switch (result.get()) { - case 0: - doRebase(progressIndicator, root, rebaseConflictDetector, "--skip"); - continue noChangeLoop; - case 1: - continue noChangeLoop; - case 2: - cancelled.set(true); - break noChangeLoop; - } + //noinspection ThrowableInstanceNeverThrown + exceptions.add(new VcsException("The update process was cancelled for " + root.getPresentableUrl())); + doRebase(progressIndicator, root, rebaseConflictDetector, "--abort"); } } - while (rebaseConflictDetector.isRebaseConflict() && !cancelled.get()); - if (cancelled.get()) { - //noinspection ThrowableInstanceNeverThrown - exceptions.add(new VcsException("The update process was cancelled for " + root.getPresentableUrl())); - doRebase(progressIndicator, root, rebaseConflictDetector, "--abort"); + finally { + if (!cancelled.get()) { + // find out what have changed + MergeChangeCollector collector = new MergeChangeCollector(myProject, root, before, updatedFiles); + collector.collect(exceptions); + } } } finally { - if (!cancelled.get()) { - // find out what have changed - MergeChangeCollector collector = new MergeChangeCollector(myProject, root, before, updatedFiles); - collector.collect(exceptions); + if (stashCreated) { + GitStashUtils.popLastStash(myProject, root); } } } finally { - if (stashCreated) { - GitStashUtils.popLastStash(myProject, root); + try { + mergeFiles(root, cancelled, ex); + //noinspection ThrowableResultOfMethodCallIgnored + if (ex.get() != null) { + //noinspection ThrowableResultOfMethodCallIgnored + exceptions.add(GitUtil.rethrowVcsException(ex.get())); + } + } + finally { + projectManager.unblockReloadingProjectOnExternalChanges(); } } } @@ -233,6 +235,61 @@ public class GitUpdateEnvironment implements UpdateEnvironment { } /** + * Merge files + * + * @param root the project root + * @param cancelled the cancelled indicator + * @param ex the exception holder + */ + private void mergeFiles(final VirtualFile root, final Ref cancelled, final Ref ex) { + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + public void run() { + try { + List affectedFiles = GitChangeUtils.unmergedFiles(myProject, root); + while (affectedFiles.size() != 0) { + AbstractVcsHelper.getInstance(myProject).showMergeDialog(affectedFiles, myVcs.getMergeProvider()); + affectedFiles = GitChangeUtils.unmergedFiles(myProject, root); + if (affectedFiles.size() != 0) { + int result = Messages + .showYesNoDialog(myProject, GitBundle.message("update.rebase.unmerged", affectedFiles.size(), root.getPresentableUrl()), + GitBundle.getString("update.rebase.unmerged.title"), Messages.getErrorIcon()); + if (result != 0) { + cancelled.set(true); + return; + } + } + } + } + catch (Throwable t) { + ex.set(t); + } + } + }); + } + + /** + * Check and process locally modified files + * + * @param root the project root + * @param cancelled the cancelled indicator + * @param ex the exception holder + */ + private void checkLocallyModified(final VirtualFile root, final Ref cancelled, final Ref ex) { + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + public void run() { + try { + if (!GitUpdateLocallyModifiedDialog.showIfNeeded(myProject, root)) { + cancelled.set(true); + } + } + catch (Throwable t) { + ex.set(t); + } + } + }); + } + + /** * Do rebase operation as part of update operator * * @param progressIndicator the progress indicator for the update -- 2.11.4.GIT