[英]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.