diff --git a/plugins/git4idea/src/git4idea/push/GitPusher.java b/plugins/git4idea/src/git4idea/push/GitPusher.java index ebb558aec8fe..b150324b3218 100644 --- a/plugins/git4idea/src/git4idea/push/GitPusher.java +++ b/plugins/git4idea/src/git4idea/push/GitPusher.java @@ -15,6 +15,7 @@ */ package git4idea.push; +import com.intellij.notification.Notification; import com.intellij.notification.NotificationType; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; @@ -45,6 +46,7 @@ import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryManager; import git4idea.settings.GitPushSettings; import git4idea.update.GitUpdateProcess; +import git4idea.update.GitUpdateResult; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -546,12 +548,31 @@ public final class GitPusher { private boolean update(@NotNull Collection rootsToUpdate, @NotNull UpdateMethod updateMethod) { GitUpdateProcess.UpdateMethod um = updateMethod == UpdateMethod.MERGE ? GitUpdateProcess.UpdateMethod.MERGE : GitUpdateProcess.UpdateMethod.REBASE; - boolean updateResult = new GitUpdateProcess(myProject, myProgressIndicator, new HashSet(rootsToUpdate), + GitUpdateResult updateResult = new GitUpdateProcess(myProject, myProgressIndicator, new HashSet(rootsToUpdate), UpdatedFiles.create()).update(um); for (GitRepository repository : rootsToUpdate) { repository.getRoot().refresh(true, true); } - return updateResult; + if (updateResult == GitUpdateResult.SUCCESS) { + return true; + } + else if (updateResult == GitUpdateResult.SUCCESS_WITH_RESOLVED_CONFLICTS || updateResult == GitUpdateResult.INCOMPLETE) { + String title = "Push cancelled"; + String description; + if (updateResult == GitUpdateResult.INCOMPLETE) { + description = "Push has been cancelled, because not all conflicts were resolved during update.
" + + "Resolve the conflicts and invoke push again."; + } + else { + description = "Push has been cancelled, because there were conflicts during update.
" + + "Check that conflicts were resolved correctly, and invoke push again."; + } + new Notification(GitVcs.MINOR_NOTIFICATION.getDisplayId(), title, description, NotificationType.WARNING).notify(myProject); + return false; + } + else { + return false; + } } } diff --git a/plugins/git4idea/src/git4idea/update/GitMergeUpdater.java b/plugins/git4idea/src/git4idea/update/GitMergeUpdater.java index 1360c937e990..6d4c72597fac 100644 --- a/plugins/git4idea/src/git4idea/update/GitMergeUpdater.java +++ b/plugins/git4idea/src/git4idea/update/GitMergeUpdater.java @@ -113,7 +113,7 @@ public class GitMergeUpdater extends GitUpdater { LOG.info("Conflict detected"); final boolean allMerged = new MyConflictResolver(myProject, myGit, merger, myRoot).merge(); - return allMerged ? GitUpdateResult.SUCCESS : GitUpdateResult.INCOMPLETE; + return allMerged ? GitUpdateResult.SUCCESS_WITH_RESOLVED_CONFLICTS : GitUpdateResult.INCOMPLETE; } else if (error == MergeError.LOCAL_CHANGES) { LOG.info("Local changes would be overwritten by merge"); diff --git a/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java b/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java index 74b7df43e02b..be59067a6cfb 100644 --- a/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java +++ b/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java @@ -105,7 +105,7 @@ public class GitRebaseUpdater extends GitUpdater { if (rebaseConflictDetector.isMergeConflict()) { LOG.info("handleRebaseFailure merge conflict"); final boolean allMerged = new MyConflictResolver(myProject, myGit, myRoot, myRebaser).merge(); - return allMerged ? GitUpdateResult.SUCCESS : GitUpdateResult.INCOMPLETE; + return allMerged ? GitUpdateResult.SUCCESS_WITH_RESOLVED_CONFLICTS : GitUpdateResult.INCOMPLETE; } else if (untrackedWouldBeOverwrittenDetector.wasMessageDetected()) { LOG.info("handleRebaseFailure: untracked files would be overwritten by checkout"); UntrackedFilesNotifier.notifyUntrackedFilesOverwrittenBy(myProject, ServiceManager.getService(myProject, PlatformFacade.class), diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java b/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java index 1ef496047022..0fa3515fdf7c 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java @@ -66,7 +66,7 @@ public class GitUpdateEnvironment implements UpdateEnvironment { GitRepositoryManager repositoryManager = getRepositoryManager(myProject); final GitUpdateProcess gitUpdateProcess = new GitUpdateProcess(myProject, progressIndicator, getRepositoriesFromRoots(repositoryManager, roots), updatedFiles); - boolean result = gitUpdateProcess.update(GitUpdateProcess.UpdateMethod.READ_FROM_SETTINGS); + boolean result = gitUpdateProcess.update(GitUpdateProcess.UpdateMethod.READ_FROM_SETTINGS).isSuccess(); return new GitUpdateSession(result); } diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java index 4a7ac4604fbd..0602ce75c7cd 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java @@ -42,6 +42,7 @@ import git4idea.repo.GitBranchTrackInfo; import git4idea.repo.GitRepository; import git4idea.stash.GitChangesSaver; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.HashMap; @@ -67,7 +68,7 @@ public class GitUpdateProcess { private final GitChangesSaver mySaver; private final Map myTrackedBranches = new HashMap(); - private boolean myResult; + private GitUpdateResult myResult; private final Map myUpdaters; private final Collection myRootsToSave; @@ -94,12 +95,7 @@ public class GitUpdateProcess { /** * Checks if update is possible, saves local changes and updates all roots. * In case of error shows notification and returns false. If update completes without errors, returns true. - */ - public boolean update() { - return update(UpdateMethod.READ_FROM_SETTINGS); - } - - /** + * * Perform update on all roots. * 0. Blocks reloading project on external change, saving/syncing on frame deactivation. * 1. Checks if update is possible (rebase/merge in progress, no tracked branches...) and provides merge dialog to solve problems. @@ -110,18 +106,19 @@ public class GitUpdateProcess { * local changes are not restored. * */ - public boolean update(final UpdateMethod updateMethod) { + @NotNull + public GitUpdateResult update(final UpdateMethod updateMethod) { LOG.info("update started|" + updateMethod); String oldText = myProgressIndicator.getText(); myProgressIndicator.setText("Updating..."); // check if update is possible if (checkRebaseInProgress() || isMergeInProgress() || areUnmergedFiles() || !checkTrackedBranchesConfigured()) { - return false; + return GitUpdateResult.NOT_READY; } if (!fetchAndNotify()) { - return false; + return GitUpdateResult.NOT_READY; } GitComplexProcess.Operation updateOperation = new GitComplexProcess.Operation() { @@ -135,7 +132,8 @@ public class GitUpdateProcess { return myResult; } - private boolean updateImpl(UpdateMethod updateMethod, ContinuationContext context) { + @NotNull + private GitUpdateResult updateImpl(UpdateMethod updateMethod, ContinuationContext context) { // define updaters for roots LOG.info("updateImpl: defining updaters..."); try { @@ -158,10 +156,10 @@ public class GitUpdateProcess { } catch (VcsException e) { LOG.info(e); notifyError(myProject, "Git update failed", e.getMessage(), true, e); - return false; + return GitUpdateResult.ERROR; } - if (myUpdaters.isEmpty()) return true; + if (myUpdaters.isEmpty()) return GitUpdateResult.NOTHING_TO_UPDATE; // save local changes if needed (update via merge may perform without saving). LOG.info("updateImpl: identifying if save is needed..."); @@ -182,13 +180,13 @@ public class GitUpdateProcess { notifyError(myProject, "Git update failed", "Tried to save uncommitted changes in " + mySaver.getSaverName() + " before update, but failed with an error.
" + "Update was cancelled.", true, e); - return false; + return GitUpdateResult.ERROR; } // update each root LOG.info("updateImpl: updating..."); boolean incomplete = false; - boolean success = true; + GitUpdateResult compoundResult = null; VirtualFile currentlyUpdatedRoot = null; try { for (Map.Entry entry : myUpdaters.entrySet()) { @@ -199,7 +197,7 @@ public class GitUpdateProcess { if (res == GitUpdateResult.INCOMPLETE) { incomplete = true; } - success &= res.isSuccess(); + compoundResult = joinResults(compoundResult, res); } } catch (VcsException e) { String rootName = (currentlyUpdatedRoot == null) ? "" : currentlyUpdatedRoot.getName(); @@ -207,7 +205,7 @@ public class GitUpdateProcess { notifyImportantError(myProject, "Error updating " + rootName, "Updating " + rootName + " failed with an error: " + e.getLocalizedMessage()); } finally { - if (incomplete || !success) { + if (incomplete || !!compoundResult.isSuccess()) { mySaver.notifyLocalChangesAreNotRestored(); } else { @@ -215,7 +213,15 @@ public class GitUpdateProcess { restoreLocalChanges(context); } } - return success; + return compoundResult; + } + + @NotNull + private static GitUpdateResult joinResults(@Nullable GitUpdateResult compoundResult, GitUpdateResult result) { + if (compoundResult == null) { + return result; + } + return compoundResult.join(result); } private void restoreLocalChanges(ContinuationContext context) { diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateResult.java b/plugins/git4idea/src/git4idea/update/GitUpdateResult.java index 323060120313..215cbb688224 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdateResult.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdateResult.java @@ -15,19 +15,43 @@ */ package git4idea.update; +import org.jetbrains.annotations.NotNull; + /** * @author Kirill Likhodedov */ public enum GitUpdateResult { - SUCCESS, - /** User cancelled update, everything that has changed was rolled back (git rebase/merge --abort) */ - CANCEL, - /** exception happened during update */ - ERROR, + /** Nothing to update. */ + NOTHING_TO_UPDATE(1), + /** Successful update, without merge conflict resolution during update. */ + SUCCESS(2), + /** Update introduced a merge conflict, that was immediately resolved by user. */ + SUCCESS_WITH_RESOLVED_CONFLICTS(3), /** Update introduced a merge conflict that wasn't immediately resolved. */ - INCOMPLETE; + INCOMPLETE(4), + /** User cancelled update, everything that has changed was rolled back (git rebase/merge --abort) */ + CANCEL(5), + /** An error happened during update */ + ERROR(6), + /** Update is not possible due to a configuration error or because of a failed fetch. */ + NOT_READY(7); + + private final int myPriority; + + GitUpdateResult(int priority) { + myPriority = priority; + } public boolean isSuccess() { - return this == SUCCESS || this == INCOMPLETE; + return this == SUCCESS || this == SUCCESS_WITH_RESOLVED_CONFLICTS || this == INCOMPLETE || this == NOTHING_TO_UPDATE; } + + @NotNull + public GitUpdateResult join(@NotNull GitUpdateResult next) { + if (myPriority >= next.myPriority) { + return this; + } + return next; + } + }