@NotNull
  private GitFileRevision createParentRevision(
      @NotNull GitRepository repository,
      @NotNull GitFileRevision currentRevision,
      @NotNull String parentHash)
      throws VcsException {
    FilePath currentRevisionPath = currentRevision.getPath();
    if (currentRevisionPath.isDirectory()) {
      // for directories the history doesn't follow renames
      return makeRevisionFromHash(currentRevisionPath, parentHash);
    }

    // can't limit by the path: in that case rename information will be missed
    Collection<Change> changes =
        GitChangeUtils.getDiff(
            myProject, repository.getRoot(), parentHash, currentRevision.getHash(), null);
    for (Change change : changes) {
      ContentRevision afterRevision = change.getAfterRevision();
      ContentRevision beforeRevision = change.getBeforeRevision();
      if (afterRevision != null && afterRevision.getFile().equals(currentRevisionPath)) {
        // if the file was renamed, taking the path how it was in the parent; otherwise the path
        // didn't change
        FilePath path =
            (beforeRevision != null ? beforeRevision.getFile() : afterRevision.getFile());
        return new GitFileRevision(myProject, path, new GitRevisionNumber(parentHash), true);
      }
    }
    LOG.error(
        String.format(
            "Could not find parent revision. Will use the path from parent revision. Current revision: %s, parent hash: %s",
            currentRevision, parentHash));
    return makeRevisionFromHash(currentRevisionPath, parentHash);
  }
  public static void getLocalCommittedChanges(
      final Project project,
      final VirtualFile root,
      final Consumer<GitSimpleHandler> parametersSpecifier,
      final Consumer<GitCommittedChangeList> consumer,
      boolean skipDiffsForMerge)
      throws VcsException {
    GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG);
    h.setSilent(true);
    h.addParameters(
        "--pretty=format:%x04%x01" + GitChangeUtils.COMMITTED_CHANGELIST_FORMAT, "--name-status");
    parametersSpecifier.consume(h);

    String output = h.run();
    LOG.debug("getLocalCommittedChanges output: '" + output + "'");
    StringScanner s = new StringScanner(output);
    final StringBuilder sb = new StringBuilder();
    boolean firstStep = true;
    while (s.hasMoreData()) {
      final String line = s.line();
      final boolean lineIsAStart = line.startsWith("\u0004\u0001");
      if ((!firstStep) && lineIsAStart) {
        final StringScanner innerScanner = new StringScanner(sb.toString());
        sb.setLength(0);
        consumer.consume(
            GitChangeUtils.parseChangeList(
                project, root, innerScanner, skipDiffsForMerge, h, false, false));
      }
      sb.append(lineIsAStart ? line.substring(2) : line).append('\n');
      firstStep = false;
    }
    if (sb.length() > 0) {
      final StringScanner innerScanner = new StringScanner(sb.toString());
      sb.setLength(0);
      consumer.consume(
          GitChangeUtils.parseChangeList(
              project, root, innerScanner, skipDiffsForMerge, h, false, false));
    }
    if (s.hasMoreData()) {
      throw new IllegalStateException("More input is avaialble: " + s.line());
    }
  }
  @NotNull
  private DiffInfo doLoadDiffInfo(@NotNull final BranchInfo branch) throws VcsException {
    // TODO: make cancelable and abort old speculative requests (when git4idea will allow to do so)
    String currentBranch = myCurrentBranch;
    String targetBranch = branch.getForkInfo().getRemoteName() + "/" + branch.getRemoteName();

    List<GitCommit> commits1 =
        GitHistoryUtils.history(myProject, myGitRepository.getRoot(), ".." + targetBranch);
    List<GitCommit> commits2 =
        GitHistoryUtils.history(myProject, myGitRepository.getRoot(), targetBranch + "..");
    Collection<Change> diff =
        GitChangeUtils.getDiff(
            myProject, myGitRepository.getRoot(), targetBranch, myCurrentBranch, null);
    GitCommitCompareInfo info =
        new GitCommitCompareInfo(GitCommitCompareInfo.InfoType.BRANCH_TO_HEAD);
    info.put(myGitRepository, diff);
    info.put(myGitRepository, Couple.of(commits1, commits2));

    return new DiffInfo(info, currentBranch, targetBranch);
  }
 @Nullable
 private static DiffInfo loadDiffInfo(
     @NotNull final Project project,
     @NotNull final GitRepository repository,
     @NotNull final String currentBranch,
     @NotNull final String targetBranch) {
   try {
     List<GitCommit> commits1 =
         GitHistoryUtils.history(project, repository.getRoot(), ".." + targetBranch);
     List<GitCommit> commits2 =
         GitHistoryUtils.history(project, repository.getRoot(), targetBranch + "..");
     Collection<Change> diff =
         GitChangeUtils.getDiff(
             repository.getProject(), repository.getRoot(), targetBranch, currentBranch, null);
     GitCommitCompareInfo info =
         new GitCommitCompareInfo(GitCommitCompareInfo.InfoType.BRANCH_TO_HEAD);
     info.put(repository, diff);
     info.put(repository, Pair.create(commits1, commits2));
     return new DiffInfo(info, currentBranch, targetBranch);
   } catch (VcsException e) {
     LOG.info(e);
     return null;
   }
 }