How to “git log --follow ” in JGit? (To retrieve the full history including renames)

前端 未结 2 379
粉色の甜心
粉色の甜心 2021-01-03 07:20

How do I have to extend the following logCommand, to get the --follow option of the git log command working?

Git git = new Git(myRe         


        
2条回答
  •  耶瑟儿~
    2021-01-03 08:09

    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 diffs = new ArrayList();
    
        @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.

提交回复
热议问题