@Override
  protected void doOKAction() {
    VirtualFile root = getGitRoot();
    GitLineHandler h = handler();
    final AtomicBoolean conflict = new AtomicBoolean();

    h.addLineListener(
        new GitLineHandlerAdapter() {
          public void onLineAvailable(String line, Key outputType) {
            if (line.contains("Merge conflict")) {
              conflict.set(true);
            }
          }
        });
    int rc =
        GitHandlerUtil.doSynchronously(
            h, GitBundle.getString("unstash.unstashing"), h.printableCommandLine(), false);
    root.refresh(true, true);

    if (conflict.get()) {
      boolean conflictsResolved =
          new UnstashConflictResolver(myProject, root, getSelectedStash()).merge();
      LOG.info("loadRoot " + root + ", conflictsResolved: " + conflictsResolved);
    } else if (rc != 0) {
      GitUIUtil.showOperationErrors(myProject, h.errors(), h.printableCommandLine());
    }
    super.doOKAction();
  }
 private GitUpdateResult handleRebaseFailure(
     GitLineHandler pullHandler,
     GitRebaseProblemDetector rebaseConflictDetector,
     final GitMessageWithFilesDetector untrackedWouldBeOverwrittenDetector) {
   if (rebaseConflictDetector.isMergeConflict()) {
     LOG.info("handleRebaseFailure merge conflict");
     final boolean allMerged = new MyConflictResolver(myProject, myGit, myRoot, myRebaser).merge();
     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, GitPlatformFacade.class),
         untrackedWouldBeOverwrittenDetector.getFiles(),
         "rebase",
         null);
     return GitUpdateResult.ERROR;
   } else {
     LOG.info("handleRebaseFailure error " + pullHandler.errors());
     GitUIUtil.notifyImportantError(
         myProject, "Rebase error", GitUIUtil.stringifyErrors(pullHandler.errors()));
     return GitUpdateResult.ERROR;
   }
 }
  private boolean stash() {
    if (!mySyncResult.hasLocalRepository()) {
      LOG.error("unexpected null local repro in call to stash");
      return false;
    }

    final ChangeListManager changeListManager = ChangeListManager.getInstance(myProject);
    if (changeListManager.isFreezedWithNotification("Can not stash changes now")) return false;

    final GitLineHandler handler =
        new GitLineHandler(myProject, mySourceRepository.getRoot(), GitCommand.STASH);
    handler.addParameters("save");
    handler.addParameters("--keep-index");
    String date =
        DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(new Date());
    myStashMessage =
        "Cloud Debugger saved changes from branch " + myOriginalBranchName + " at " + date;
    handler.addParameters(myStashMessage);
    AccessToken token = DvcsUtil.workingTreeChangeStarted(myProject);
    try {
      GitHandlerUtil.doSynchronously(
          handler, GitBundle.getString("stashing.title"), handler.printableCommandLine());
    } finally {
      DvcsUtil.workingTreeChangeFinished(myProject, token);
    }
    return true;
  }
 /**
  * Executes 'git push' for the given roots to push. Returns the list of errors if there were any.
  */
 private List<VcsException> executePushCommand(final Collection<Root> rootsToPush) {
   final ArrayList<VcsException> errors = new ArrayList<VcsException>();
   for (Root r : rootsToPush) {
     GitLineHandler h = new GitLineHandler(myProject, r.root, GitCommand.PUSH);
     String src = r.commitToPush != null ? r.commitToPush : r.currentBranch;
     h.addParameters("-v", r.remoteName, src + ":" + r.remoteBranch);
     GitPushUtils.trackPushRejectedAsError(
         h, "Rejected push (" + r.root.getPresentableUrl() + "): ");
     errors.addAll(GitHandlerUtil.doSynchronouslyWithExceptions(h));
   }
   return errors;
 }
  protected void fetch() throws ServerRuntimeException {
    final VirtualFile contentRoot = getContentRoot();
    GitRepository repository = getRepository();
    final GitLineHandler fetchHandler =
        new GitLineHandler(getProject(), contentRoot, GitCommand.FETCH);
    fetchHandler.setSilent(false);
    fetchHandler.addParameters(getRemoteName());
    fetchHandler.addLineListener(createGitLineHandlerListener());
    performRemoteGitTask(fetchHandler, CloudBundle.getText("fetching.application", getCloudName()));

    repository.update();
  }
 private static boolean createEmptyGitRepository(
     @NotNull Project project, @NotNull VirtualFile root, @NotNull ProgressIndicator indicator) {
   final GitLineHandler h = new GitLineHandler(project, root, GitCommand.INIT);
   GitHandlerUtil.runInCurrentThread(
       h, indicator, true, GitBundle.getString("initializing.title"));
   if (!h.errors().isEmpty()) {
     GitUIUtil.showOperationErrors(project, h.errors(), "git init");
     LOG.info("Failed to create empty git repo: " + h.errors());
     return false;
   }
   GitInit.refreshAndConfigureVcsMappings(project, root, root.getPath());
   return true;
 }
 /** @return unstash handler */
 private GitLineHandler handler() {
   GitLineHandler h = new GitLineHandler(myProject, getGitRoot(), GitCommand.STASH);
   h.setNoSSH(true);
   String branch = myBranchTextField.getText();
   if (branch.length() == 0) {
     h.addParameters(myPopStashCheckBox.isSelected() ? "pop" : "apply");
     if (myReinstateIndexCheckBox.isSelected()) {
       h.addParameters("--index");
     }
   } else {
     h.addParameters("branch", branch);
   }
   String selectedStash = getSelectedStash().getStash();
   addStashParameter(h, selectedStash);
   return h;
 }
  private static void takeLine(
      final Project project,
      String line,
      StringBuilder sb,
      GitLogParser parser,
      SymbolicRefsI refs,
      VirtualFile root,
      VcsException[] exc,
      GitLineHandler h,
      AsynchConsumer<GitCommit> gitCommitConsumer) {
    final String text = sb.toString();
    sb.setLength(0);
    sb.append(line);
    if (text.length() == 0) return;
    GitLogRecord record = parser.parseOneRecord(text);

    final GitCommit gitCommit;
    try {
      gitCommit = createCommit(project, refs, root, record);
    } catch (VcsException e) {
      exc[0] = e;
      h.cancel();
      return;
    }
    gitCommitConsumer.consume(gitCommit);
  }
  private static void doRebaseCurrentBranch(
      @NotNull final Project project,
      @NotNull final VirtualFile root,
      @NotNull final ProgressIndicator indicator) {
    final GitRepositoryManager repositoryManager = GitUtil.getRepositoryManager(project);

    final GitRebaser rebaser =
        new GitRebaser(project, ServiceManager.getService(Git.class), indicator);

    final GitLineHandler handler = new GitLineHandler(project, root, GitCommand.REBASE);
    handler.addParameters("upstream/master");

    final GitRebaseProblemDetector rebaseConflictDetector = new GitRebaseProblemDetector();
    handler.addLineListener(rebaseConflictDetector);

    final GitUntrackedFilesOverwrittenByOperationDetector untrackedFilesDetector =
        new GitUntrackedFilesOverwrittenByOperationDetector(root);
    handler.addLineListener(untrackedFilesDetector);

    GitTask pullTask = new GitTask(project, handler, "Rebasing from upstream/master");
    pullTask.setProgressIndicator(indicator);
    pullTask.setProgressAnalyzer(new GitStandardProgressAnalyzer());
    pullTask.execute(
        true,
        false,
        new GitTaskResultHandlerAdapter() {
          @Override
          protected void onSuccess() {
            root.refresh(false, true);
            repositoryManager.updateRepository(root);
            GithubNotifications.showInfo(project, "Success", "Successfully rebased GitHub fork");
          }

          @Override
          protected void onFailure() {
            GitUpdateResult result =
                rebaser.handleRebaseFailure(
                    handler, root, rebaseConflictDetector, untrackedFilesDetector);
            repositoryManager.updateRepository(root);
            if (result == GitUpdateResult.NOTHING_TO_UPDATE
                || result == GitUpdateResult.SUCCESS
                || result == GitUpdateResult.SUCCESS_WITH_RESOLVED_CONFLICTS) {
              GithubNotifications.showInfo(project, "Success", "Successfully rebased GitHub fork");
            }
          }
        });
  }
 public void doClone(File cloneDirParent, String cloneDirName, String gitUrl)
     throws ServerRuntimeException {
   final GitLineHandler handler =
       new GitLineHandler(getProject(), cloneDirParent, GitCommand.CLONE);
   handler.setSilent(false);
   handler.setUrl(gitUrl);
   handler.addParameters("--progress");
   handler.addParameters(gitUrl);
   handler.addParameters(cloneDirName);
   handler.addParameters("-o");
   handler.addParameters(getRemoteName());
   handler.addLineListener(createGitLineHandlerListener());
   performRemoteGitTask(
       handler, CloudBundle.getText("cloning.existing.application", getCloudName()));
 }
  protected GitUpdateResult doUpdate() {
    LOG.info("doUpdate ");
    String remoteBranch = getRemoteBranchToMerge();

    final GitLineHandler rebaseHandler = new GitLineHandler(myProject, myRoot, GitCommand.REBASE);
    rebaseHandler.addParameters(remoteBranch);
    final GitRebaseProblemDetector rebaseConflictDetector = new GitRebaseProblemDetector();
    rebaseHandler.addLineListener(rebaseConflictDetector);
    GitUntrackedFilesOverwrittenByOperationDetector untrackedFilesDetector =
        new GitUntrackedFilesOverwrittenByOperationDetector(myRoot);
    rebaseHandler.addLineListener(untrackedFilesDetector);

    GitTask rebaseTask = new GitTask(myProject, rebaseHandler, "Rebasing");
    rebaseTask.setProgressIndicator(myProgressIndicator);
    rebaseTask.setProgressAnalyzer(new GitStandardProgressAnalyzer());
    final AtomicReference<GitUpdateResult> updateResult = new AtomicReference<GitUpdateResult>();
    final AtomicBoolean failure = new AtomicBoolean();
    rebaseTask.executeInBackground(
        true,
        new GitTaskResultHandlerAdapter() {
          @Override
          protected void onSuccess() {
            updateResult.set(GitUpdateResult.SUCCESS);
          }

          @Override
          protected void onCancel() {
            cancel();
            updateResult.set(GitUpdateResult.CANCEL);
          }

          @Override
          protected void onFailure() {
            failure.set(true);
          }
        });

    if (failure.get()) {
      updateResult.set(
          handleRebaseFailure(rebaseHandler, rebaseConflictDetector, untrackedFilesDetector));
    }
    return updateResult.get();
  }
 private static GitLineHandler getLogHandler(
     Project project,
     VirtualFile root,
     GitLogParser parser,
     FilePath path,
     String lastCommit,
     String... parameters) {
   final GitLineHandler h = new GitLineHandler(project, root, GitCommand.LOG);
   h.setNoSSH(true);
   h.setStdoutSuppressed(true);
   h.addParameters("--name-status", parser.getPretty(), "--encoding=UTF-8", lastCommit);
   if (parameters != null && parameters.length > 0) {
     h.addParameters(parameters);
   }
   h.endOptions();
   h.addRelativePaths(path);
   return h;
 }
  public static void historyWithLinks(
      final Project project,
      FilePath path,
      @Nullable final SymbolicRefsI refs,
      @NotNull final AsynchConsumer<GitCommit> gitCommitConsumer,
      @Nullable final Getter<Boolean> isCanceled,
      @Nullable Collection<VirtualFile> paths,
      final String... parameters)
      throws VcsException {
    // adjust path using change manager
    path = getLastCommitName(project, path);
    final VirtualFile root = GitUtil.getGitRoot(path);
    final GitLineHandler h = new GitLineHandler(project, root, GitCommand.LOG);
    final GitLogParser parser =
        new GitLogParser(
            project,
            GitLogParser.NameStatus.STATUS,
            SHORT_HASH,
            HASH,
            COMMIT_TIME,
            AUTHOR_NAME,
            AUTHOR_TIME,
            AUTHOR_EMAIL,
            COMMITTER_NAME,
            COMMITTER_EMAIL,
            SHORT_PARENTS,
            REF_NAMES,
            SUBJECT,
            BODY,
            RAW_BODY);
    h.setNoSSH(true);
    h.setStdoutSuppressed(true);
    h.addParameters(parameters);
    h.addParameters("--name-status", parser.getPretty(), "--encoding=UTF-8", "--full-history");
    if (paths != null && !paths.isEmpty()) {
      h.endOptions();
      h.addRelativeFiles(paths);
    } else {
      h.addParameters("--sparse");
      h.endOptions();
      h.addRelativePaths(path);
    }

    final VcsException[] exc = new VcsException[1];
    final Semaphore semaphore = new Semaphore();
    final StringBuilder sb = new StringBuilder();
    final Ref<Boolean> skipFirst = new Ref<Boolean>(true);
    h.addLineListener(
        new GitLineHandlerAdapter() {
          @Override
          public void onLineAvailable(final String line, final Key outputType) {
            try {
              if (ProcessOutputTypes.STDOUT.equals(outputType)) {
                if (isCanceled != null && isCanceled.get()) {
                  h.cancel();
                  return;
                }
                // if (line.charAt(line.length() - 1) != '\u0003') {
                if ((!line.startsWith("\u0001")) || skipFirst.get()) {
                  if (sb.length() > 0) {
                    sb.append("\n");
                  }
                  sb.append(line);
                  skipFirst.set(false);
                  return;
                }
                takeLine(project, line, sb, parser, refs, root, exc, h, gitCommitConsumer);
              }
            } catch (ProcessCanceledException e) {
              h.cancel();
              semaphore.up();
            }
          }

          @Override
          public void processTerminated(int exitCode) {
            semaphore.up();
          }

          @Override
          public void startFailed(Throwable exception) {
            semaphore.up();
          }
        });
    semaphore.down();
    h.start();
    semaphore.waitFor();
    takeLine(project, "", sb, parser, refs, root, exc, h, gitCommitConsumer);
    gitCommitConsumer.finished();
    if (exc[0] != null) {
      throw exc[0];
    }
  }
  public static void dumpFullHistory(
      final Project project, VirtualFile root, final String outFilePath) throws VcsException {
    if (!GitUtil.isGitRoot(new File(root.getPath())))
      throw new VcsException("Path " + root.getPath() + " is not git repository root");

    final GitLineHandler h = new GitLineHandler(project, root, GitCommand.LOG);
    // GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG);
    GitLogParser parser =
        new GitLogParser(project, GitLogParser.NameStatus.STATUS, HASH, COMMIT_TIME);
    h.setNoSSH(true);
    h.setSilent(true);
    h.addParameters(
        "--all",
        "--pretty=format:%H%x20%ct%x0A",
        "--date-order",
        "--reverse",
        "--encoding=UTF-8",
        "--full-history",
        "--sparse");
    h.endOptions();

    // for file sort
    final Long[] minTs = new Long[1];
    minTs[0] = Long.MAX_VALUE;
    final Long[] maxTs = new Long[1];
    minTs[0] = 0L;

    final OutputStream[] stream = new OutputStream[1];
    try {
      stream[0] = new BufferedOutputStream(new FileOutputStream(outFilePath, false));
      final Semaphore semaphore = new Semaphore();
      final VcsException[] ioExceptions = new VcsException[1];
      h.addLineListener(
          new GitLineHandlerListener() {
            @Override
            public void onLineAvailable(String line, Key outputType) {
              if (line.length() == 0) return;
              try {
                GitCommitsSequentialIndex.parseRecord(line);
                stream[0].write((line + '\n').getBytes("UTF-8"));
              } catch (IOException e) {
                ioExceptions[0] = new VcsException(e);
                h.cancel();
                semaphore.up();
              } catch (ProcessCanceledException e) {
                h.cancel();
                semaphore.up();
              } catch (VcsException e) {
                ioExceptions[0] = e;
                h.cancel();
                semaphore.up();
              }
            }

            @Override
            public void processTerminated(int exitCode) {
              semaphore.up();
            }

            @Override
            public void startFailed(Throwable exception) {
              semaphore.up();
            }
          });
      semaphore.down();
      h.start();
      semaphore.waitFor();
      if (ioExceptions[0] != null) {
        throw ioExceptions[0];
      }
    } catch (FileNotFoundException e) {
      throw new VcsException(e);
    } finally {
      try {
        if (stream[0] != null) {
          stream[0].close();
        }
      } catch (IOException e) {
        throw new VcsException(e);
      }
    }
    /*String result = h.run();
    if (result.length() > 0) {
      throw new VcsException(result);
    }*/
    File file = new File(outFilePath);
    if (!file.exists() || file.length() == 0)
      throw new VcsException("Short repository history not loaded");
  }
  public static void hashesWithParents(
      Project project,
      FilePath path,
      final AsynchConsumer<CommitHashPlusParents> consumer,
      final Getter<Boolean> isCanceled,
      Collection<VirtualFile> paths,
      final String... parameters)
      throws VcsException {
    // adjust path using change manager
    path = getLastCommitName(project, path);
    final VirtualFile root = GitUtil.getGitRoot(path);
    final GitLineHandler h = new GitLineHandler(project, root, GitCommand.LOG);
    final GitLogParser parser =
        new GitLogParser(
            project,
            GitLogParser.NameStatus.NAME,
            SHORT_HASH,
            COMMIT_TIME,
            SHORT_PARENTS,
            AUTHOR_NAME);
    h.setNoSSH(true);
    h.setStdoutSuppressed(true);
    h.addParameters(parameters);
    h.addParameters(parser.getPretty(), "--encoding=UTF-8", "--full-history");

    if (paths != null && !paths.isEmpty()) {
      h.endOptions();
      h.addRelativeFiles(paths);
    } else {
      h.addParameters("--sparse");
      h.endOptions();
      h.addRelativePaths(path);
    }

    final Semaphore semaphore = new Semaphore();
    h.addLineListener(
        new GitLineHandlerListener() {
          @Override
          public void onLineAvailable(final String line, final Key outputType) {
            try {
              if (ProcessOutputTypes.STDOUT.equals(outputType)) {
                if (isCanceled != null && isCanceled.get()) {
                  h.cancel();
                  return;
                }
                GitLogRecord record = parser.parseOneRecord(line);
                consumer.consume(
                    new CommitHashPlusParents(
                        record.getShortHash(),
                        record.getParentsShortHashes(),
                        record.getLongTimeStamp() * 1000,
                        record.getAuthorName()));
              }
            } catch (ProcessCanceledException e) {
              h.cancel();
              semaphore.up();
            }
          }

          @Override
          public void processTerminated(int exitCode) {
            semaphore.up();
          }

          @Override
          public void startFailed(Throwable exception) {
            semaphore.up();
          }
        });
    semaphore.down();
    h.start();
    semaphore.waitFor();
    consumer.finished();
  }
  /**
   * Load VCS roots
   *
   * @param project the project
   * @param roots the VCS root list
   * @param exceptions the list of of exceptions to use
   * @param fetchData if true, the data for remote is fetched.
   * @return the loaded information about vcs roots
   */
  private static List<Root> loadRoots(
      final Project project,
      final List<VirtualFile> roots,
      final Collection<VcsException> exceptions,
      final boolean fetchData) {
    final ArrayList<Root> rc = new ArrayList<Root>();
    for (VirtualFile root : roots) {
      try {
        Root r = new Root();
        rc.add(r);
        r.root = root;
        GitBranch b = GitBranch.current(project, root);
        if (b != null) {
          r.currentBranch = b.getFullName();
          r.remoteName = b.getTrackedRemoteName(project, root);
          r.remoteBranch = b.getTrackedBranchName(project, root);
          if (r.remoteName != null) {
            if (fetchData && !r.remoteName.equals(".")) {
              GitLineHandler fetch = new GitLineHandler(project, root, GitCommand.FETCH);
              fetch.addParameters(r.remoteName, "-v");
              Collection<VcsException> exs = GitHandlerUtil.doSynchronouslyWithExceptions(fetch);
              exceptions.addAll(exs);
            }
            GitBranch tracked = b.tracked(project, root);
            assert tracked != null : "Tracked branch cannot be null here";
            final boolean trackedBranchExists = tracked.exists(root);
            if (!trackedBranchExists) {
              LOG.info("loadRoots tracked branch " + tracked + " doesn't exist yet");
            }

            // check what remote commits are not yet merged
            if (trackedBranchExists) {
              GitSimpleHandler toPull = new GitSimpleHandler(project, root, GitCommand.LOG);
              toPull.addParameters(
                  "--pretty=format:%H", r.currentBranch + ".." + tracked.getFullName());
              toPull.setNoSSH(true);
              toPull.setStdoutSuppressed(true);
              StringScanner su = new StringScanner(toPull.run());
              while (su.hasMoreData()) {
                if (su.line().trim().length() != 0) {
                  r.remoteCommits++;
                }
              }
            }

            // check what local commits are to be pushed
            GitSimpleHandler toPush = new GitSimpleHandler(project, root, GitCommand.LOG);
            // if the tracked branch doesn't exist yet (nobody pushed the branch yet), show all
            // commits on this branch.
            final String revisions =
                trackedBranchExists
                    ? tracked.getFullName() + ".." + r.currentBranch
                    : r.currentBranch;
            toPush.addParameters("--pretty=format:%H%x20%ct%x20%at%x20%s%n%P", revisions);
            toPush.setNoSSH(true);
            toPush.setStdoutSuppressed(true);
            StringScanner sp = new StringScanner(toPush.run());
            while (sp.hasMoreData()) {
              if (sp.isEol()) {
                sp.line();
                continue;
              }
              Commit c = new Commit();
              c.root = r;
              String hash = sp.spaceToken();
              String time = sp.spaceToken();
              c.revision = new GitRevisionNumber(hash, new Date(Long.parseLong(time) * 1000L));
              c.authorTime = sp.spaceToken();
              c.message = sp.line();
              c.isMerge = sp.line().indexOf(' ') != -1;
              r.commits.add(c);
            }
          }
        }
      } catch (VcsException e) {
        exceptions.add(e);
      }
    }
    return rc;
  }