我正在使用 R 包git2r与libgit2接口。我想获取每次提交中更新的文件列表,类似于git log --stat
or的输出git log --name-only
。但是,我无法获取初始提交中包含的文件。下面我提供了设置示例 Git 存储库的代码以及基于我的研究尝试的解决方案。
可重现的例子
下面的代码在 中创建一个临时目录/tmp
,创建空文本文件,然后分别提交每个文件。
# Create example Git repo
path <- tempfile("so-git2r-ex-")
dir.create(path)
setwd(path)
# Set the number of fake files
n_files <- 3
file.create(paste0("file", 1:n_files, ".txt"))
library("git2r")
repo <- init(".")
for (i in 1:n_files) {
add(repo, sprintf("file%d.txt", i))
commit(repo, sprintf("Added file %d", i))
}
选项 1 - 比较两棵树的差异
这篇SO 帖子建议您执行比较所需提交的树对象及其父提交的差异。这很好用,除了初始提交,因为没有父提交可以比较它。
get_files_from_diff <- function(c1, c2) {
# Obtain files updated in commit c1.
# c2 is the commit that preceded c1.
git_diff <- diff(tree(c1), tree(c2))
files <- sapply(git_diff@files, function(x) x@new_file)
return(files)
}
log <- commits(repo)
n <- length(log)
for (i in 1:n) {
print(i)
if (i == n) {
print("Unclear how to obtain list of files from initial commit.")
} else {
files <- get_files_from_diff(log[[i]], log[[i + 1]])
print(files)
}
}
选项 2 - 解析提交摘要
This SO post建议通过解析提交摘要来获取提交信息,例如更改的文件。这与 非常相似git log --stat
,但同样的例外是初始提交。它不列出任何文件。查看源码,commit summary中的文件是通过上面相同的方法获得的,这就解释了为什么初始提交没有显示文件(它没有父提交)。
for (i in 1:n) {
summary(log[[i]])
}
更新
这应该是可能的。Git 命令diff-tree
有一个标志--root
,用于将根提交与 NULL 树(source)进行比较。从手册页:
--root When --root is specified the initial commit will be shown as a big creation event. This is equivalent to a diff against the NULL tree.
此外,libgit2 库具有函数git_diff_tree_to_tree,它接受 NULL 树。不幸的是,我不清楚是否可以通过git-tree objects的 git2r diff 方法将 NULL 树传递给 git2r C 函数git2r_diff。有没有办法用 git2r 创建一个 NULL 树对象?
> tree()
Error in (function (classes, fdef, mtable) :
unable to find an inherited method for function ‘tree’ for signature ‘"missing"’
> tree(NULL)
Error in (function (classes, fdef, mtable) :
unable to find an inherited method for function ‘tree’ for signature ‘"NULL"’