@NotNull private Map<VirtualFile, GitUpdater> defineUpdaters(@NotNull UpdateMethod updateMethod) throws VcsException { final Map<VirtualFile, GitUpdater> updaters = new HashMap<VirtualFile, GitUpdater>(); LOG.info("updateImpl: defining updaters..."); for (GitRepository repository : myRepositories) { VirtualFile root = repository.getRoot(); GitUpdater updater = GitUpdater.getUpdater( myProject, myGit, myTrackedBranches, root, myProgressIndicator, myUpdatedFiles, updateMethod); if (updater.isUpdateNeeded()) { updaters.put(root, updater); } LOG.info("update| root=" + root + " ,updater=" + updater); } return updaters; }
@NotNull private GitUpdateResult updateImpl(@NotNull UpdateMethod updateMethod) { Map<VirtualFile, GitUpdater> updaters; try { updaters = defineUpdaters(updateMethod); } catch (VcsException e) { LOG.info(e); notifyError(myProject, "Git update failed", e.getMessage(), true, e); return GitUpdateResult.ERROR; } if (updaters.isEmpty()) { return GitUpdateResult.NOTHING_TO_UPDATE; } updaters = tryFastForwardMergeForRebaseUpdaters(updaters); if (updaters.isEmpty()) { // everything was updated via the fast-forward merge return GitUpdateResult.SUCCESS; } if (myCheckRebaseOverMergeProblem) { Collection<VirtualFile> problematicRoots = findRootsRebasingOverMerge(updaters); if (!problematicRoots.isEmpty()) { GitRebaseOverMergeProblem.Decision decision = GitRebaseOverMergeProblem.showDialog(); if (decision == GitRebaseOverMergeProblem.Decision.MERGE_INSTEAD) { for (VirtualFile root : problematicRoots) { updaters.put( root, new GitMergeUpdater( myProject, myGit, root, myTrackedBranches, myProgressIndicator, myUpdatedFiles)); } } else if (decision == GitRebaseOverMergeProblem.Decision.CANCEL_OPERATION) { return GitUpdateResult.CANCEL; } } } // save local changes if needed (update via merge may perform without saving). final Collection<VirtualFile> myRootsToSave = ContainerUtil.newArrayList(); LOG.info("updateImpl: identifying if save is needed..."); for (Map.Entry<VirtualFile, GitUpdater> entry : updaters.entrySet()) { VirtualFile root = entry.getKey(); GitUpdater updater = entry.getValue(); if (updater.isSaveNeeded()) { myRootsToSave.add(root); LOG.info("update| root " + root + " needs save"); } } LOG.info("updateImpl: saving local changes..."); final Ref<Boolean> incomplete = Ref.create(false); final Ref<GitUpdateResult> compoundResult = Ref.create(); final Map<VirtualFile, GitUpdater> finalUpdaters = updaters; new GitPreservingProcess( myProject, myGit, myRootsToSave, "Update", "Remote", GitVcsSettings.getInstance(myProject).updateChangesPolicy(), myProgressIndicator, new Runnable() { @Override public void run() { LOG.info("updateImpl: updating..."); VirtualFile currentlyUpdatedRoot = null; try { for (Map.Entry<VirtualFile, GitUpdater> entry : finalUpdaters.entrySet()) { currentlyUpdatedRoot = entry.getKey(); GitUpdater updater = entry.getValue(); GitUpdateResult res = updater.update(); LOG.info("updating root " + currentlyUpdatedRoot + " finished: " + res); if (res == GitUpdateResult.INCOMPLETE) { incomplete.set(true); } compoundResult.set(joinResults(compoundResult.get(), res)); } } catch (VcsException e) { String rootName = (currentlyUpdatedRoot == null) ? "" : currentlyUpdatedRoot.getName(); LOG.info("Error updating changes for root " + currentlyUpdatedRoot, e); notifyImportantError( myProject, "Error updating " + rootName, "Updating " + rootName + " failed with an error: " + e.getLocalizedMessage()); } } }) .execute( new Computable<Boolean>() { @Override public Boolean compute() { // Note: compoundResult normally should not be null, because the updaters map was // checked for non-emptiness. // But if updater.update() fails with exception for the first root, then the value // would not be assigned. // In this case we don't restore local changes either, because update failed. return !incomplete.get() && !compoundResult.isNull() && compoundResult.get().isSuccess(); } }); // GitPreservingProcess#save may fail due index.lock presence return ObjectUtils.notNull(compoundResult.get(), GitUpdateResult.ERROR); }