/**
  * Mark root as dirty
  *
  * @param root a vcs root to rescan
  */
 private void markRootDirty(final VirtualFile root) {
   // Note that the root is invalidated because changes are detected per-root anyway.
   // Otherwise it is not possible to detect moves.
   myDirtyScopeManager.dirDirtyRecursively(root);
 }
  /**
   * Preform a merge commit
   *
   * @param project a project
   * @param root a vcs root
   * @param added added files
   * @param removed removed files
   * @param messageFile a message file for commit
   * @param author an author
   * @param exceptions the list of exceptions to report
   * @param partialOperation
   * @return true if merge commit was successful
   */
  private static boolean mergeCommit(
      final Project project,
      final VirtualFile root,
      final Set<FilePath> added,
      final Set<FilePath> removed,
      final File messageFile,
      final String author,
      List<VcsException> exceptions,
      @NotNull final PartialOperation partialOperation) {
    HashSet<FilePath> realAdded = new HashSet<FilePath>();
    HashSet<FilePath> realRemoved = new HashSet<FilePath>();
    // perform diff
    GitSimpleHandler diff = new GitSimpleHandler(project, root, GitCommand.DIFF);
    diff.setSilent(true);
    diff.setStdoutSuppressed(true);
    diff.addParameters("--diff-filter=ADMRUX", "--name-status", "HEAD");
    diff.endOptions();
    String output;
    try {
      output = diff.run();
    } catch (VcsException ex) {
      exceptions.add(ex);
      return false;
    }
    String rootPath = root.getPath();
    for (StringTokenizer lines = new StringTokenizer(output, "\n", false);
        lines.hasMoreTokens(); ) {
      String line = lines.nextToken().trim();
      if (line.length() == 0) {
        continue;
      }
      String[] tk = line.split("\t");
      switch (tk[0].charAt(0)) {
        case 'M':
        case 'A':
          realAdded.add(VcsUtil.getFilePath(rootPath + "/" + tk[1]));
          break;
        case 'D':
          realRemoved.add(VcsUtil.getFilePathForDeletedFile(rootPath + "/" + tk[1], false));
          break;
        default:
          throw new IllegalStateException("Unexpected status: " + line);
      }
    }
    realAdded.removeAll(added);
    realRemoved.removeAll(removed);
    if (realAdded.size() != 0 || realRemoved.size() != 0) {

      final List<FilePath> files = new ArrayList<FilePath>();
      files.addAll(realAdded);
      files.addAll(realRemoved);
      final Ref<Boolean> mergeAll = new Ref<Boolean>();
      try {
        GuiUtils.runOrInvokeAndWait(
            new Runnable() {
              public void run() {
                String message =
                    GitBundle.message("commit.partial.merge.message", partialOperation.getName());
                SelectFilePathsDialog dialog =
                    new SelectFilePathsDialog(
                        project,
                        files,
                        message,
                        null,
                        "Commit All Files",
                        CommonBundle.getCancelButtonText(),
                        false);
                dialog.setTitle(GitBundle.getString("commit.partial.merge.title"));
                dialog.show();
                mergeAll.set(dialog.isOK());
              }
            });
      } catch (RuntimeException ex) {
        throw ex;
      } catch (Exception ex) {
        throw new RuntimeException("Unable to invoke a message box on AWT thread", ex);
      }
      if (!mergeAll.get()) {
        return false;
      }
      // update non-indexed files
      if (!updateIndex(project, root, realAdded, realRemoved, exceptions)) {
        return false;
      }
      for (FilePath f : realAdded) {
        VcsDirtyScopeManager.getInstance(project).fileDirty(f);
      }
      for (FilePath f : realRemoved) {
        VcsDirtyScopeManager.getInstance(project).fileDirty(f);
      }
    }
    // perform merge commit
    try {
      GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.COMMIT);
      handler.setStdoutSuppressed(false);
      handler.addParameters("-F", messageFile.getAbsolutePath());
      if (author != null) {
        handler.addParameters("--author=" + author);
      }
      handler.endOptions();
      handler.run();
      GitRepositoryManager manager = GitUtil.getRepositoryManager(project);
      manager.updateRepository(root);
    } catch (VcsException ex) {
      exceptions.add(ex);
      return false;
    }
    return true;
  }