public void launchLoadDiffInfo(@NotNull final BranchInfo branch) {
    if (branch.getForkInfo().getRemoteName() == null) return;

    if (branch.getDiffInfoTask() != null) return;
    synchronized (branch.LOCK) {
      if (branch.getDiffInfoTask() != null) return;

      launchFetchRemote(branch.getForkInfo());
      MasterFutureTask<Void> masterTask = branch.getForkInfo().getFetchTask();
      assert masterTask != null;

      final SlaveFutureTask<DiffInfo> task =
          new SlaveFutureTask<DiffInfo>(
              masterTask,
              new Callable<DiffInfo>() {
                @Override
                public DiffInfo call() throws VcsException {
                  return doLoadDiffInfo(branch);
                }
              });
      branch.setDiffInfoTask(task);

      ApplicationManager.getApplication()
          .executeOnPooledThread(
              new Runnable() {
                @Override
                public void run() {
                  task.run();
                }
              });
    }
  }
  @Nullable
  public DiffInfo getDiffInfo(@NotNull final BranchInfo branch) throws IOException {
    if (branch.getForkInfo().getRemoteName() == null) return null;

    launchLoadDiffInfo(branch);

    assert branch.getDiffInfoTask() != null;
    try {
      return branch.getDiffInfoTask().get();
    } catch (InterruptedException e) {
      throw new GithubOperationCanceledException(e);
    } catch (ExecutionException e) {
      Throwable ex = e.getCause();
      if (ex instanceof VcsException) throw new IOException(ex);
      LOG.error(ex);
      return null;
    }
  }