/** * Returns proper updater based on the update policy (merge or rebase) selected by user or stored * in his .git/config * * @return {@link GitMergeUpdater} or {@link GitRebaseUpdater}. */ @NotNull public static GitUpdater getUpdater( @NotNull Project project, @NotNull Git git, @NotNull Map<VirtualFile, GitBranchPair> trackedBranches, @NotNull VirtualFile root, @NotNull ProgressIndicator progressIndicator, @NotNull UpdatedFiles updatedFiles) { final GitVcsSettings settings = GitVcsSettings.getInstance(project); if (settings == null) { return getDefaultUpdaterForBranch( project, git, root, trackedBranches, progressIndicator, updatedFiles); } switch (settings.getUpdateType()) { case REBASE: return new GitRebaseUpdater( project, git, root, trackedBranches, progressIndicator, updatedFiles); case MERGE: return new GitMergeUpdater( project, git, root, trackedBranches, progressIndicator, updatedFiles); case BRANCH_DEFAULT: // use default for the branch return getDefaultUpdaterForBranch( project, git, root, trackedBranches, progressIndicator, updatedFiles); } return getDefaultUpdaterForBranch( project, git, root, trackedBranches, progressIndicator, updatedFiles); }
/** * Updates the recently visited branch in the settings. This is to be performed after successful * checkout operation. */ protected void updateRecentBranch() { if (getRepositories().size() == 1) { GitRepository repository = myRepositories.iterator().next(); mySettings.setRecentBranchOfRepository(repository.getRoot().getPath(), myCurrentBranchOrRev); } else { mySettings.setRecentCommonBranch(myCurrentBranchOrRev); } }
@Before public void setUp() throws Throwable { IdeaTestApplication.getInstance(); myTestName = createTestName(); myProjectFixture = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(myTestName).getFixture(); edt( new ThrowableRunnable<Exception>() { @Override public void run() throws Exception { myProjectFixture.setUp(); } }); myProject = myProjectFixture.getProject(); myProjectRoot = myProject.getBasePath(); myProjectDir = myProject.getBaseDir(); myTestRoot = myProjectRoot; myGit = ServiceManager.getService(myProject, Git.class); mySettings = GitVcsSettings.getInstance(myProject); mySettings.getAppSettings().setPathToGit(GitExecutor.PathHolder.GIT_EXECUTABLE); // dynamic overriding is used instead of making it in plugin.xml, // because MockVcsHelper is not ready to be a full featured implementation for all tests. myVcsHelper = GitTestUtil.overrideService(myProject, AbstractVcsHelper.class, MockVcsHelper.class); myChangeListManager = ChangeListManagerImpl.getInstanceImpl(myProject); myNotificator = (TestVcsNotifier) ServiceManager.getService(myProject, VcsNotifier.class); myVcs = GitVcs.getInstance(myProject); myRepositoryManager = GitUtil.getRepositoryManager(myProject); virtualCommits = new GitTestVirtualCommitsHolder(); myAsyncTasks = new ArrayList<>(); cd(myProjectRoot); myRepository = GitTestUtil.createRepository(myProject, myProjectRoot); ProjectLevelVcsManagerImpl vcsManager = (ProjectLevelVcsManagerImpl) ProjectLevelVcsManager.getInstance(myProject); AbstractVcs vcs = vcsManager.findVcsByName("Git"); Assert.assertEquals(1, vcsManager.getRootsUnderVcs(vcs).length); GitTestUtil.assumeSupportedGitVersion(myVcs); LOG.info(getStartTestMarker()); }
@NotNull private ReturnResult warnAboutCrlfIfNeeded() { GitVcsSettings settings = GitVcsSettings.getInstance(myProject); if (!settings.warnAboutCrlf()) { return ReturnResult.COMMIT; } final GitPlatformFacade platformFacade = ServiceManager.getService(myProject, GitPlatformFacade.class); final Git git = ServiceManager.getService(Git.class); final Collection<VirtualFile> files = myPanel .getVirtualFiles(); // deleted files aren't included, but for them we don't care about // CRLFs. final AtomicReference<GitCrlfProblemsDetector> crlfHelper = new AtomicReference<GitCrlfProblemsDetector>(); ProgressManager.getInstance() .run( new Task.Modal(myProject, "Checking for line separator issues...", true) { @Override public void run(@NotNull ProgressIndicator indicator) { crlfHelper.set( GitCrlfProblemsDetector.detect( GitCheckinHandlerFactory.MyCheckinHandler.this.myProject, platformFacade, git, files)); } }); if (crlfHelper.get() == null) { // detection cancelled return ReturnResult.CANCEL; } if (crlfHelper.get().shouldWarn()) { final GitCrlfDialog dialog = new GitCrlfDialog(myProject); UIUtil.invokeAndWaitIfNeeded( new Runnable() { @Override public void run() { dialog.show(); } }); int decision = dialog.getExitCode(); if (decision == GitCrlfDialog.CANCEL) { return ReturnResult.CANCEL; } else { if (decision == GitCrlfDialog.SET) { VirtualFile anyRoot = myPanel .getRoots() .iterator() .next(); // config will be set globally => any root will do. setCoreAutoCrlfAttribute(anyRoot); } else { if (dialog.dontWarnAgain()) { settings.setWarnAboutCrlf(false); } } return ReturnResult.COMMIT; } } return ReturnResult.COMMIT; }
@Override protected void rememberRecentRoot(@NotNull String path) { mySettings.setRecentRoot(path); }
@Nullable @Override protected GitRepository guessCurrentRepository(@NotNull Project project) { return DvcsUtil.guessCurrentRepositoryQuick( project, GitUtil.getRepositoryManager(project), mySettings.getRecentRootPath()); }
public GitBranchWidget(@NotNull Project project) { super(project, "Git"); mySettings = GitVcsSettings.getInstance(project); }
@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); }
/** * Constructs new dialog. Loads settings, registers listeners. * * @param project the project * @param vcsRoots the vcs roots * @param roots the loaded information about roots */ private GitPushActiveBranchesDialog( final Project project, List<VirtualFile> vcsRoots, List<Root> roots) { super(project, true); myVcs = GitVcs.getInstance(project); myProject = project; myVcsRoots = vcsRoots; myGeneralSettings = GeneralSettings.getInstance(); myProjectManager = ProjectManagerEx.getInstanceEx(); updateTree(roots, null); updateUI(); final GitVcsSettings settings = GitVcsSettings.getInstance(project); if (settings != null) { UpdatePolicyUtils.updatePolicyItem( settings.getPushActiveBranchesRebaseSavePolicy(), myStashRadioButton, myShelveRadioButton); } ChangeListener listener = new ChangeListener() { public void stateChanged(ChangeEvent e) { if (settings != null) { settings.setPushActiveBranchesRebaseSavePolicy( UpdatePolicyUtils.getUpdatePolicy(myStashRadioButton, myShelveRadioButton)); } } }; myStashRadioButton.addChangeListener(listener); myShelveRadioButton.addChangeListener(listener); myCommitTree .getSelectionModel() .addTreeSelectionListener( new TreeSelectionListener() { public void valueChanged(TreeSelectionEvent e) { TreePath path = myCommitTree.getSelectionModel().getSelectionPath(); if (path == null) { myViewButton.setEnabled(false); return; } DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent(); myViewButton.setEnabled( node != null && myCommitTree.getSelectionCount() == 1 && node.getUserObject() instanceof Commit); } }); myViewButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { TreePath path = myCommitTree.getSelectionModel().getSelectionPath(); if (path == null) { return; } DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent(); if (node == null || !(node.getUserObject() instanceof Commit)) { return; } Commit c = (Commit) node.getUserObject(); GitShowAllSubmittedFilesAction.showSubmittedFiles( project, c.revision.asString(), c.root.root); } }); myFetchButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { fetch(); } }); myRebaseButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { rebase(); } }); myPushButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { push(); } }); setTitle(GitBundle.getString("push.active.title")); setOKButtonText(GitBundle.getString("push.active.rebase.and.push")); setCancelButtonText(GitBundle.getString("git.push.active.close")); init(); }