git - 如何在 JGit 中获取 "git log --follow <path>"? (检索包括重命名在内的完整历史记录)

标签 git 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 通常使用索引来在更短的时间内执行跟随选项。

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 - 如何在 JGit 中获取 "git log --follow <path>"? (检索包括重命名在内的完整历史记录),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11471836/

相关文章:

java - 自定义 apache ant 任务 git-add (jgit) 不起作用

java - 如何在不使用 JGit 下载到本地系统的情况下获取所有提交?

git - 使用 JGit 使现有的 Git 分支跟踪远程分支?

git - 克隆 CodeIgniter 框架来构建我的网站

Git:如何让日志只显示与模式匹配的标签?

git - 我们如何排除 `Notes added by ' git Notes 添加 '` from ` git log`?

git - git log --since 是如何计数的?

python - 是否有任何交叉引用 Python 源代码的 git web 网关

linux - Nginx 配置版本控制策略

ubuntu 20.04 上的 Fish shell 的 git 配置完成困惑