docs: @Get("regex:/projects/(?<projectName>[^/]+)/repos/(?<repoName>[^/]+)/commits(?<revision>(|/.*))$")
      public CompletableFuture<?> listCommits(@Param("revision") String revision,
                                              @Param("path") @Default("/**") String path,
                                              @Param("to") Optional<String> to,
                                              @Param("maxCommits") Optional<Integer> maxCommits,
                                              Repository repository) {
          final Revision fromRevision;
          final Revision toRevision;
  
          // 1. only the "revision" is specified:       get the "revision" and return just one commit
          // 2. only the "to" is specified:             get from "HEAD" to "to" and return the list
          // 3. the "revision" and "to" is specified:   get from the "revision" to "to" and return the list
          // 4. nothing is specified:                   get from "HEAD" to "INIT" and return the list
          if (isNullOrEmpty(revision) || "/".equalsIgnoreCase(revision)) {
              fromRevision = Revision.HEAD;
              toRevision = to.map(Revision::new).orElse(Revision.INIT);
          } else {
              fromRevision = new Revision(revision.substring(1));
              toRevision = to.map(Revision::new).orElse(fromRevision);
          }
  
          final RevisionRange range = repository.normalizeNow(fromRevision, toRevision).toDescending();
          final int maxCommits0 = maxCommits.map(integer -> Math.min(integer, Repository.DEFAULT_MAX_COMMITS))
                                            .orElse(Repository.DEFAULT_MAX_COMMITS);
          return repository
                  .history(range.from(), range.to(), normalizePath(path), maxCommits0)
                  .thenApply(commits -> {
                      final boolean toList = isNullOrEmpty(revision) || "/".equalsIgnoreCase(revision) ||
                                             to.isPresent();
                      return objectOrList(commits, toList, DtoConverter::convert);
                  });
      }