12

I want to get the last commit metadata (the youngest one by date) in a repository using JGit.

I know that I can get the commit metadata using:

try (RevWalk walk = new RevWalk(repository))
{
    RevCommit commit = walk.parseCommit(repository.resolve(commitHash));
}

But how to get the latest commit hash?

Is there any other way to get the youngest by date RevCommit in a repository directly?

Nathan
  • 8,093
  • 8
  • 50
  • 76
Master Mind
  • 3,014
  • 4
  • 32
  • 63

4 Answers4

10

You could make use of git log and set it to only return the top most commit:

RevCommit latestCommit = new Git(repository).
   log().
   setMaxCount(1).
   call().
   iterator().
   next();

String latestCommitHash = latestCommit.getName();
Nathan
  • 8,093
  • 8
  • 50
  • 76
jet457
  • 211
  • 2
  • 5
4

Compare by dates of last commits in all branches. ListMode.ALL can be changed to ListMode.REMOTE to compare only remote branches. Or... the fluent setter .setListMode(whatever) can be omitted to read from the local repository.

RevCommit youngestCommit = null;
Git git = new Git(repository);
List<Ref> branches = git.branchList().setListMode(ListMode.ALL).call();
try {
    RevWalk walk = new RevWalk(git.getRepository());
    for(Ref branch : branches) {
        RevCommit commit = walk.parseCommit(branch.getObjectId());
        if(youngestCommit == null || commit.getAuthorIdent().getWhen().compareTo(
           youngestCommit.getAuthorIdent().getWhen()) > 0)
           youngestCommit = commit;
    }
} catch (...)
Nicolas
  • 1,106
  • 11
  • 25
Grzegorz Górkiewicz
  • 4,496
  • 4
  • 22
  • 38
  • Would it return the youngest commit by date in the whole repo regardless of the branches? – Master Mind Mar 15 '17 at 21:06
  • No, it will return the commit to which `HEAD` points to (usually the current branch). – Rüdiger Herrmann Mar 15 '17 at 21:21
  • The snippet assumes that the newest commit is among the branch heads, which may, at least in theory, not be the case. Or am I missing something? Another issue is that the author timestamp is compared. Use `getCommiterIdent().getWhen()` instead. – Rüdiger Herrmann Mar 17 '17 at 19:03
3

Below you can find a Java 8 Stream API solution:

final List<Ref> branches = git.branchList().setListMode(ListBranchCommand.ListMode.ALL).call();
final RevWalk revWalk = new RevWalk(git.getRepository());

branches.stream()
        .map(branch -> {
            try {
                return revWalk.parseCommit(branch.getObjectId());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        })
        .sorted(Comparator.comparing((RevCommit commit) -> commit.getAuthorIdent().getWhen()).reversed())
        .findFirst()
        .ifPresent(commit -> {
            System.out.printf("%s: %s (%s)%n", commit.getAuthorIdent().getWhen(), commit.getShortMessage(), commit.getAuthorIdent().getName());
        });

It iterates over all branches and picks recent commits in those branches, then it sorts list of commits by date in descendant order and picks the first one. If it exists it prints to console output something like this:

Wed Aug 30 09:49:42 CEST 2017: test file added (Szymon Stepniak)

Of course the behavior on last commit existence is exemplary and it can be easily replaced with any additional business logic. I hope it helps.

Szymon Stepniak
  • 40,216
  • 10
  • 104
  • 131
2

To find the newest commit within a repository, configure a RevWalk to start from all known refs and sort it descending by commit date. For example:

Repository repo = ...
try( RevWalk revWalk = new RevWalk( repo ) ) {
  revWalk.sort( RevSort.COMMIT_TIME_DESC );
  Map<String, Ref> allRefs = repo.getRefDatabase().getRefs( RefDatabase.ALL );
  for( Ref ref : allRefs.values() ) {
    RevCommit commit = revWalk.parseCommit( ref.getLeaf().getObjectId() );
    revWalk.markStart( commit );
  }
  RevCommit newestCommit = revWalk.next();
}

Depending on your use case, you may also want to mark start points from refs from repo.getRefDatabase().getAdditionalRefs() which includes refs like FETCH_RESULT, ORIG_HEAD, etc. If you find that there are still untracked refs, use repo.getRefDatabase().getRef().

Rüdiger Herrmann
  • 20,512
  • 11
  • 62
  • 79
  • I don't get this. The loop over refs does nothing but overwrite the `RevWalk` starting point at each iteration. Why didn't you use the last ref instead? – Abhijit Sarkar Oct 22 '20 at 06:56
  • 1
    `markStart` does not override but adds a starting point. After the `for` loop, the `RevWalk` is configured to sort commits by time and include commits from all refs returned by `getRefs(...)` – Rüdiger Herrmann Oct 23 '20 at 12:22