如何“git log - 关注<路径>”在JGit? (要检索包含重命名的完整历史记录) [英] How to "git log --follow <path>" in JGit? (To retrieve the full history including renames)

查看:301
本文介绍了如何“git log - 关注<路径>”在JGit? (要检索包含重命名的完整历史记录)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何扩展下面的logCommand,以获取 git log - follow 选项。命令工作?

  Git git = new Git(myRepository); 
Iterable< RevCommit> log = git.log()。addPath(com / mycompany / myclass.java)。call();

这个选项在jGit中实现,但我不知道如何使用它。 logCommand的方法似乎没有用处。谢谢!

解决方案

在某些午夜工作中,我得到了以下结果:

LogCommand的最后一次提交将针对所有较早的提交进行重命名检查,直到找到重命名操作。这个循环将继续,直到找不到重命名为止。



然而,该搜索可能需要一些时间,特别是如果迭代所有提交直到结束,再也找不到任何重命名操作了。所以,我有任何改进的空间。我猜git通常使用索引在更短的时间内执行后续选项。




$ b

  import org.eclipse.jgit.api.Git; 
import org.eclipse.jgit.api.errors.GitAPIException;
导入org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.RenameDetector;
import org.eclipse.jgit.errors.MissingObjectException;
导入org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
导入org.eclipse.jgit.treewalk.TreeWalk;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/ **
*创建一个启用后续选项的日志命令:git log --follow - <路径>
*用户:OneWorld
*使用示例:ArrayList< RevCommit> commits = new LogFollowCommand(repo,src / com / mycompany / myfile.java)。call();
* /
public class LogFollowCommand {

private final存储库;
私人字符串路径;
private Git git;

/ **
*创建一个启用后续选项的日志命令:git log --follow - <路径>
* @param repository
* @param path
$ / $ b $ public LogFollowCommand(Repository repository,String path){
this.repository = repository;
this.path = path;
}

/ **
*返回一个git日志的结果 - 关注 - <路径>
* @return
* @throws IOException
* @throws MissingObjectException
* @throws GitAPIException
* /
public ArrayList< RevCommit> call()抛出IOException,MissingObjectException,GitAPIException {
ArrayList< RevCommit> commits = new ArrayList< RevCommit>();
git = new Git(repository);
RevCommit start = null;
do {
Iterable< RevCommit> log = git.log()。addPath(path).call(); (RevCommit commit:log){
if(commits.contains(commit)){
start = null;
} else {
start = commit;
commits.add(commit);
}
}
if(start == null)return commits; ((path = getRenamedPath(start))!= null);



返回提交;
}

/ **
*检查某个文件的历史记录中的重命名。如果未找到重命名,则返回null。
*可能需要几秒钟的时间,特别是如果没有发现任何东西......这里可能需要进行一些调整,或者LogFollowCommand必须在一个线程中运行。
* @param start
* @return字符串或空
* @throws IOException
* @throws MissingObjectException
* @throws GitAPIException
* /
private String getRenamedPath(RevCommit start)throws IOException,MissingObjectException,GitAPIException {
Iterable< RevCommit> allCommitsLater = git.log()。add(start).call(); (RevCommit commit:allCommitsLater){

TreeWalk tw = new TreeWalk(repository);

tw.addTree(commit.getTree());
tw.addTree(start.getTree());
tw.setRecursive(true);
RenameDetector rd = new RenameDetector(repository);
rd.addAll(DiffEntry.scan(tw));
列表< DiffEntry> files = rd.compute(); (DiffEntry diffEntry:files){
if((diffEntry.getChangeType()== DiffEntry.ChangeType.RENAME || diffEntry.getChangeType()== DiffEntry.ChangeType.COPY)&& diffEntry.getNewPath()。contains(path)){
System.out.println(Found:+ diffEntry.toString()+return+ diffEntry.getOldPath());
返回diffEntry.getOldPath();
}
}
}
返回null;
}
}


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

Git git = new Git(myRepository);
Iterable<RevCommit> log = git.log().addPath("com/mycompany/myclass.java").call();

This option is implemented in jGit, but I don't know how to use it. The logCommand's methods don't appear to be useful. Thank you!

解决方案

During some midnight work I got the following:

The last commit of a LogCommand will get checked for renames against all older commits until a rename operation is found. This cycle will continue until no rename was found.

However, that search can take some time, especially if it iterates over all commits until the end and doesn't find any rename operation anymore. So, I am open for any improvement. I guess git normally uses indexes to perform the follow option in shorter time.

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.RenameDetector;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.treewalk.TreeWalk;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Create a Log command that enables the follow option: git log --follow -- < path >
 * User: OneWorld
 * Example for usage: ArrayList<RevCommit> commits =  new  LogFollowCommand(repo,"src/com/mycompany/myfile.java").call();
 */
public class LogFollowCommand {

    private final Repository repository;
    private String path;
    private Git git;

    /**
     * Create a Log command that enables the follow option: git log --follow -- < path >
     * @param repository
     * @param path
     */
    public LogFollowCommand(Repository repository, String path){
        this.repository = repository;
        this.path = path;
    }

    /**
     * Returns the result of a git log --follow -- < path >
     * @return
     * @throws IOException
     * @throws MissingObjectException
     * @throws GitAPIException
     */
    public ArrayList<RevCommit> call() throws IOException, MissingObjectException, GitAPIException {
        ArrayList<RevCommit> commits = new ArrayList<RevCommit>();
        git = new Git(repository);
        RevCommit start = null;
        do {
            Iterable<RevCommit> log = git.log().addPath(path).call();
            for (RevCommit commit : log) {
                if (commits.contains(commit)) {
                    start = null;
                } else {
                    start = commit;
                    commits.add(commit);
                }
            }
            if (start == null) return commits;
        }
        while ((path = getRenamedPath( start)) != null);

        return commits;
    }

    /**
     * Checks for renames in history of a certain file. Returns null, if no rename was found.
     * Can take some seconds, especially if nothing is found... Here might be some tweaking necessary or the LogFollowCommand must be run in a thread.
     * @param start
     * @return String or null
     * @throws IOException
     * @throws MissingObjectException
     * @throws GitAPIException
     */
    private String getRenamedPath( RevCommit start) throws IOException, MissingObjectException, GitAPIException {
        Iterable<RevCommit> allCommitsLater = git.log().add(start).call();
        for (RevCommit commit : allCommitsLater) {

            TreeWalk tw = new TreeWalk(repository);
            tw.addTree(commit.getTree());
            tw.addTree(start.getTree());
            tw.setRecursive(true);
            RenameDetector rd = new RenameDetector(repository);
            rd.addAll(DiffEntry.scan(tw));
            List<DiffEntry> files = rd.compute();
            for (DiffEntry diffEntry : files) {
                if ((diffEntry.getChangeType() == DiffEntry.ChangeType.RENAME || diffEntry.getChangeType() == DiffEntry.ChangeType.COPY) && diffEntry.getNewPath().contains(path)) {
                    System.out.println("Found: " + diffEntry.toString() + " return " + diffEntry.getOldPath());
                    return diffEntry.getOldPath();
                }
            }
        }
        return null;
    }
}

这篇关于如何“git log - 关注&lt;路径&gt;”在JGit? (要检索包含重命名的完整历史记录)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆