I recall trying OneWorld's solution on a previous occasion, and while it worked, it was very slow. I thought I'd google around to see if there were any other possibilities out there.
Yes, in this Eclipse thread, there was a suggestion of using org.eclipse.jgit.revwalk.FollowFilter and to look for a use-example in RevWalkFollowFilterTest.java.
So thought I'd give that a try, resulting in code like that looks like this:
private static class DiffCollector extends RenameCallback {
List<DiffEntry> diffs = new ArrayList<DiffEntry>();
@Override
public void renamed(DiffEntry diff) {
diffs.add(diff);
}
}
private DiffCollector diffCollector;
private void showFileHistory(String filepath)
{
try
{
Config config = repo.getConfig();
config.setBoolean("diff", null, "renames", true);
RevWalk rw = new RevWalk(repo);
diffCollector = new DiffCollector();
org.eclipse.jgit.diff.DiffConfig dc = config.get(org.eclipse.jgit.diff.DiffConfig.KEY);
FollowFilter followFilter =
FollowFilter.create(filepath, dc);
followFilter.setRenameCallback(diffCollector);
rw.setTreeFilter(followFilter);
rw.markStart(rw.parseCommit(repo.resolve(Constants.HEAD)));
for (RevCommit c : rw)
{
System.out.println(c.toString());
}
}
catch(...
The results were, erm, ok I guess... The RevWalk did manage to walk through a simple rename of a file in the git-repo's history (performed by a "git mv {filename}" action).
However, it was unable to handle messier situations, such as when a colleague performed this set of actions in the repo's history:
- 1st commit: Renamed a file with "git mv"
- 2nd commit: Added a copy of that file in a new sub-folder location
- 3rd commit: Deleted the old location's copy
In this scenario, JGit's follow capabilities will only get me the from the head to that 2nd commit, and stop there.
The real "git log --follow" command, however, seems to have enough smarts to figure out that:
- The file added in the 2nd commit is the same as that in the 1st commit (even though they are in different locations)
- It will give you the entire history:
- from HEAD-to-2nd-commit (added copy of newly-named file in new location)
- skips any mention of the 3rd-commit (delete of old file in old path)
- followed by the 1st-commit and its history (old location and name of file)
So JGit's follow capabilities seem a little weaker compared to real Git. Ah well.
But anyway, I can confirm that using JGit's FollowFilter technique did work a lot faster than the previously suggested technique.