public ProjectDto getProject(String id) {
    if (cache.isCached(id)) {
      return cache.tryGetCached(id);
    }

    ProjectInfo info = null;

    try {
      info = caller.waitOrCall(() -> api.projects().name(id).get());
    } catch (Exception e) {

      logger.error(Logging.prepare("getProject", id), e);
    }

    if (info != null) {
      ProjectDto project = new ProjectDto(info.id, info.name);

      if (info.parent != null && downloadParents) {
        ProjectDto parent = getProject(info.parent);
        project.parentId = Optional.of(parent.id);
      }

      project = repo.add(project);

      // getProjectBranches(project);
      // getApprovals(project);

      cache.cache(project);

      return project;
    }

    return null;
  }
  public BranchDto getBranch(ProjectDto project, String name) {
    if (project.hasBranch(name) == false) {
      repo.loadProjectBranches(project);
    }

    if (project.hasBranch(name) == false) {
      getProjectBranches(project);
    }
    return project.getBranch(name);
  }
  private void getProjectBranches(ProjectDto project) {
    List<BranchInfo> branches = null;
    try {
      ProjectApi.ListBranchesRequest request = api.projects().name(project.projectId).branches();
      branches = caller.waitOrCall(() -> request.get());
    } catch (Exception e) {
      logger.error(Logging.prepare("getProjectBranches", project.projectId), e);
    }

    if (branches != null) {
      List<BranchDto> projectBranches =
          branches
              .stream()
              .filter(b -> project.hasBranch(b.ref) == false)
              .map(b -> repo.addBranch(project, b.ref, b.revision))
              .filter(b -> b != null)
              .collect(Collectors.toList());

      projectBranches.forEach(project.branches::add);
    }
  }