繁体   English   中英

使用 JGit 从最小存储库中检出单个子目录

[英]Check out single subdirectory from minimal repository using JGit

我正在使用 JGit 6.5.x 和 Java 17。我有一个巨大的远程存储库(千兆字节),但我只需要临时访问单个子目录(例如foo/bar/ )进行处理。 单个子目录非常小(数百千字节)。 克隆一个浅的裸存储库也相对较小:

try (final Git git = Git.cloneRepository()
    .setURI(REMOTE_REPOSITORY_URI.toASCIIString())
    .setDirectory(LOCAL_RESPOSITORY_PATH.toFile())
    .setBare(true)
    .setDepth(1)
    .call()) {
  System.out.println("cloned shallow, bare repository");
}

有没有办法克隆一个像这样的浅层裸存储库(或任何其他最小版本的存储库),然后暂时将单个子目录foo/bar签出到其他目录,以便我可以使用正常的方式处理这些文件Java 文件系统 API?

请注意,我刚刚在上面的克隆中取得了成功,还没有开始研究如何从这个裸存储库中检出一个子目录。

尝试以下解决方案:

注意:在应用任何 git 更改之前,请确保您已备份必要的文件。

使用 git object 创建一个 TreeWalk,它允许您遍历存储库的树并找到您感兴趣的子目录。将起始路径指定为存储库的根目录:

try (Git git = Git.open(LOCAL_REPOSITORY_PATH.toFile())) {
    Repository repository = git.getRepository();

    // Get the tree for the repository's HEAD commit
    RevWalk revWalk = new RevWalk(repository);
    RevCommit commit = revWalk.parseCommit(repository.resolve(Constants.HEAD));
    RevTree tree = commit.getTree();

    // Create a TreeWalk starting from the root of the repository
    TreeWalk treeWalk = new TreeWalk(repository);
    treeWalk.addTree(tree);
    treeWalk.setRecursive(true);
    
    // Specify the path of the subdirectory you want to check out
    treeWalk.setFilter(PathFilter.create("foo/bar"));

    if (!treeWalk.next()) {
        throw new IllegalStateException("Subdirectory not found");
    }

    // Get the ObjectId of the subdirectory's tree
    ObjectId subdirectoryTreeId = treeWalk.getObjectId(0);
    treeWalk.close();
    
    // Create a new Git object with the shallow, bare repository
    Git subGit = new Git(repository);

    // Checkout the subdirectory's tree to a temporary directory
    Path temporaryDirectory = Files.createTempDirectory("subdirectory");
    subGit.checkout().setStartPoint(subdirectoryTreeId.getName()).setAllPaths(true).setForce(true).setTargetPath(temporaryDirectory.toFile()).call();

    // Now you can use the Java file system API to process the files in the temporary directory
    
    // Clean up the temporary directory when you're done
    FileUtils.deleteDirectory(temporaryDirectory.toFile());
}

在上面的代码中,我们使用 TreeWalk 遍历存储库的树并找到您指定的子目录 (foo/bar)。 然后我们获取子目录树的 ObjectId,并使用存储库创建一个新的 Git object。 最后,我们使用 checkout() 将子目录的树检出到一个临时目录,您可以使用 Java 文件系统 API 来处理该目录中的文件。 完成后不要忘记清理临时目录。

请注意,该代码假定您已准备好必要的 JGit 和 Java IO 导入。

另一个答案的启发,我能够获得单深度克隆并仅检出单个路径而无需进行裸克隆,同时使用类似的最小文件系统空间。 这种方法的好处是只需要一个顶级目录; 另一方面,裸存储库方法需要手动遍历并保存到单独的下级目录。

关键是使用setNoCheckout(true) (除了setDepth(1) ),然后在克隆后手动执行单独的检查指定请求的路径。 请注意,您必须指定setStartPoint("HEAD")或指定 hash 起点,因为还没有结帐,因此不会有分支。

try (final Git git = Git.cloneRepository()
    .setURI(REMOTE_REPOSITORY_URI.toASCIIString())
    .setDirectory(LOCAL_RESPOSITORY_PATH.toFile())
    .setNoCheckout(true)
    .setDepth(1)
    .call()) {

  gitRepository.checkout()
    .setStartPoint("HEAD")
    .addPath("foo/bar")
    .call();

}

这似乎工作得很好! 我想它使用了类似于Satyajit Bhatt 在幕后的回答的东西。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM