@Override protected void save(@NotNull Collection<VirtualFile> rootsToSave) throws VcsException { LOG.info("saving " + rootsToSave); for (VirtualFile root : rootsToSave) { final String message = GitHandlerUtil.formatOperationName("Stashing changes from", root); LOG.info(message); final String oldProgressTitle = myProgressIndicator.getText(); myProgressIndicator.setText(message); GitRepository repository = myRepositoryManager.getRepositoryForRoot(root); if (repository == null) { LOG.error("Repository is null for root " + root); } else { GitCommandResult result = myGit.stashSave(repository, myStashMessage); if (result.success() && somethingWasStashed(result)) { myStashedRoots.add(root); } else { String error = "stash " + repository.getRoot() + ": " + result.getErrorOutputAsJoinedString(); if (!result.success()) { throw new VcsException(error); } else { LOG.warn(error); } } } myProgressIndicator.setText(oldProgressTitle); } }
private boolean doDeleteRemote( @NotNull String branchName, @NotNull Collection<GitRepository> repositories) { Couple<String> pair = splitNameOfRemoteBranch(branchName); String remoteName = pair.getFirst(); String branch = pair.getSecond(); GitCompoundResult result = new GitCompoundResult(myProject); for (GitRepository repository : repositories) { GitCommandResult res; GitRemote remote = getRemoteByName(repository, remoteName); if (remote == null) { String error = "Couldn't find remote by name: " + remoteName; LOG.error(error); res = GitCommandResult.error(error); } else { res = pushDeletion(repository, remote, branch); if (!res.success() && isAlreadyDeletedError(res.getErrorOutputAsJoinedString())) { res = myGit.remotePrune(repository, remote); } } result.append(repository, res); repository.update(); } if (!result.totalSuccess()) { VcsNotifier.getInstance(myProject) .notifyError( "Failed to delete remote branch " + branchName, result.getErrorOutputWithReposIndication()); } return result.totalSuccess(); }
/** * Returns absolute paths which have changed remotely comparing to the current branch, i.e. * performs <code>git diff --name-only master..origin/master</code> * * <p>Paths are absolute, Git-formatted (i.e. with forward slashes). */ @NotNull public static Collection<String> getPathsDiffBetweenRefs( @NotNull Git git, @NotNull GitRepository repository, @NotNull String beforeRef, @NotNull String afterRef) throws VcsException { List<String> parameters = Arrays.asList("--name-only", "--pretty=format:"); String range = beforeRef + ".." + afterRef; GitCommandResult result = git.diff(repository, parameters, range); if (!result.success()) { LOG.info( String.format( "Couldn't get diff in range [%s] for repository [%s]", range, repository.toLogString())); return Collections.emptyList(); } final Collection<String> remoteChanges = new HashSet<String>(); for (StringScanner s = new StringScanner(result.getOutputAsJoinedString()); s.hasMoreData(); ) { final String relative = s.line(); if (StringUtil.isEmptyOrSpaces(relative)) { continue; } final String path = repository.getRoot().getPath() + "/" + unescapePath(relative); remoteChanges.add(path); } return remoteChanges; }
/** * Returns true if the root was loaded with conflict. False is returned in all other cases: in the * case of success and in case of some other error. */ private boolean loadRoot(final VirtualFile root) { LOG.info("loadRoot " + root); myProgressIndicator.setText(GitHandlerUtil.formatOperationName("Unstashing changes to", root)); GitRepository repository = myRepositoryManager.getRepositoryForRoot(root); if (repository == null) { LOG.error("Repository is null for root " + root); return false; } GitSimpleEventDetector conflictDetector = new GitSimpleEventDetector(GitSimpleEventDetector.Event.MERGE_CONFLICT_ON_UNSTASH); GitCommandResult result = myGit.stashPop(repository, conflictDetector); VfsUtil.markDirtyAndRefresh(false, true, false, root); if (result.success()) { return false; } else if (conflictDetector.hasHappened()) { return true; } else { LOG.info("unstash failed " + result.getErrorOutputAsJoinedString()); GitUIUtil.notifyImportantError( myProject, "Couldn't unstash", "<br/>" + result.getErrorOutputAsHtmlString()); return false; } }
private static boolean pushCurrentBranch( @NotNull Project project, @NotNull GitRepository repository, @NotNull String remoteName, @NotNull String remoteUrl, @NotNull String name, @NotNull String url) { Git git = ServiceManager.getService(Git.class); GitLocalBranch currentBranch = repository.getCurrentBranch(); if (currentBranch == null) { GithubNotifications.showErrorURL( project, "Can't finish GitHub sharing process", "Successfully created project ", "'" + name + "'", " on GitHub, but initial push failed: no current branch", url); return false; } GitCommandResult result = git.push(repository, remoteName, remoteUrl, currentBranch.getName(), true); if (!result.success()) { GithubNotifications.showErrorURL( project, "Can't finish GitHub sharing process", "Successfully created project ", "'" + name + "'", " on GitHub, but initial push failed:<br/>" + result.getErrorOutputAsHtmlString(), url); return false; } return true; }
/** * Tries to execute {@code git merge --ff-only}. * * @return true, if everything is successful; false for any error (to let a usual "fair" update * deal with it). */ public boolean fastForwardMerge() { LOG.info("Trying fast-forward merge for " + myRoot); GitRepository repository = GitUtil.getRepositoryManager(myProject).getRepositoryForRoot(myRoot); if (repository == null) { LOG.error("Repository is null for " + myRoot); return false; } try { markStart(myRoot); } catch (VcsException e) { LOG.info("Couldn't mark start for repository " + myRoot, e); return false; } GitCommandResult result = myGit.merge(repository, getRemoteBranchToMerge(), Collections.singletonList("--ff-only")); try { markEnd(myRoot); } catch (VcsException e) { // this is not critical, and update has already happened, // so we just notify the user about problems with collecting the updated changes. LOG.info("Couldn't mark end for repository " + myRoot, e); Notificator.getInstance(myProject) .notifyWeakWarning( "Couldn't collect the updated files info", String.format( "Update of %s was successful, but we couldn't collect the updated changes because of an error", myRoot), null); } return result.success(); }
private boolean wasFileTouched(@NotNull GitRepository repository, @NotNull GitFileRevision rev) throws VcsException { GitCommandResult result = myGit.show(repository, rev.getHash()); if (result.success()) { return isFilePresentInOutput(repository, rev.getPath(), result.getOutput()); } throw new VcsException(result.getErrorOutputAsJoinedString()); }
protected static void checkGitResult(GitCommandResult commandResult) throws ServerRuntimeException { if (!commandResult.success()) { Throwable exception = commandResult.getException(); if (exception != null) { LOG.info(exception); throw new ServerRuntimeException(exception); } else { throw new ServerRuntimeException(commandResult.getErrorOutputAsJoinedString()); } } }
private ListenableFuture<Pair<String, GitCommandResult>> doPushCommits( @NotNull final GitRepository gitRepository, @NotNull final GitLocalBranch localBranch, @NotNull final GitRemote gitRemote, @NotNull final ProgressIndicator indicator) { // just set the result without going off to another thread, we should already be in a background // task SettableFuture<Pair<String, GitCommandResult>> pushResult = SettableFuture.<Pair<String, GitCommandResult>>create(); indicator.setText(TfPluginBundle.message(TfPluginBundle.KEY_CREATE_PR_PUSH_TITLE)); final Git git = ServiceManager.getService(Git.class); final GitRemoteBranch trackingBranch = localBranch.findTrackedBranch(gitRepository); final String createdBranchNameOnServer; final StringBuilder pushSpec = new StringBuilder(localBranch.getName()); if (trackingBranch != null && trackingBranch.getRemote().equals(gitRemote)) { // if the tracking branch is on the same remote, we should update that pushSpec.append(":").append(trackingBranch.getNameForRemoteOperations()); createdBranchNameOnServer = trackingBranch.getNameForRemoteOperations(); } else { createdBranchNameOnServer = localBranch.getName(); } final String fetchUrl = getFetchUrl(gitRemote); final String pushSpecStr = pushSpec.toString(); final String gitRemoteName = gitRemote.getName(); logger.debug("Pushing {} to {}: {}", pushSpecStr, gitRemoteName, fetchUrl); final GitCommandResult result = git.push(gitRepository, gitRemoteName, fetchUrl, pushSpecStr, true); if (result.success()) { pushResult.set(Pair.create(createdBranchNameOnServer, result)); } else { final String errMsg = result.getErrorOutputAsJoinedString(); pushResult.setException(new GitExecutionException(errMsg, null)); } return pushResult; }
/** * Parse changes from lines * * @param root the git root * @return a set of unmerged files * @throws com.intellij.openapi.vcs.VcsException if the input format does not matches expected * format */ private List<VirtualFile> unmergedFiles(final VirtualFile root) throws VcsException { GitRepository repository = myRepositoryManager.getRepositoryForRoot(root); if (repository == null) { LOG.error("Repository not found for root " + root); return Collections.emptyList(); } GitCommandResult result = myGit.getUnmergedFiles(repository); if (!result.success()) { throw new VcsException(result.getErrorOutputAsJoinedString()); } String output = StringUtil.join(result.getOutput(), "\n"); HashSet<String> unmergedPaths = ContainerUtil.newHashSet(); for (StringScanner s = new StringScanner(output); s.hasMoreData(); ) { if (s.isEol()) { s.nextLine(); continue; } s.boundedToken('\t'); String relative = s.line(); unmergedPaths.add(GitUtil.unescapePath(relative)); } if (unmergedPaths.size() == 0) { return Collections.emptyList(); } else { List<File> files = ContainerUtil.map( unmergedPaths, new Function<String, File>() { @Override public File fun(String path) { return new File(root.getPath(), path); } }); return sortVirtualFilesByPresentation(findVirtualFilesWithRefresh(files)); } }
private static boolean somethingWasStashed(@NotNull GitCommandResult result) { return !StringUtil.containsIgnoreCase( result.getErrorOutputAsJoinedString(), NO_LOCAL_CHANGES_TO_SAVE) && !StringUtil.containsIgnoreCase( result.getOutputAsJoinedString(), NO_LOCAL_CHANGES_TO_SAVE); }