为什么在使用 git_odb_foreach 时会看到重复的对象 ID?

Why do I see duplicate object ids when using git_odb_foreach?

我是 运行 大型 git 存储库(在本例中为 linux-2.6)的简单对象 ID 收集器,准备将所述 ID 存储在 sqlite 数据库中。

伪代码:

// Table holding the SHA1 of each object in the database, ensure ids are unique
CREATE TABLE objs(key INTEGER PRIMARY KEY, id BLOB UNIQUE);

// For each id, insert into objs table, rc can tell us if we violate uniqueness constraint
int callback(const git_oid *oid, void *payload) {
     // note that 'oid' in the following string is really the id value in real code
     int rc = sqlite3_exec("INSERT INTO objs(id) VALUES(oid);");
     if (rc == SQLITE_CONSTRAINT) {
          // code to print type and oid
     }
}

int main() {
    // sqlite and git initialization
    git_odb_foreach(...callback...);
    // cleanup
    return 0;
}

在大约 400 万个物体中,我最终遇到了大约 70000 个非独特物体。有趣的是,当 运行 'git rev-list --objects --all | wc -l' 时,此计数与 foreach 代码中的唯一对象数相匹配。

有人可以解释为什么 git_odb_foreach 函数会产生这些非唯一 ID 吗?

Git 对象除了作为松散对象存在外,还可能存储在多个包文件中。这只是可能发生的事情,git 实施必须处理。

虽然 git/libgit2/whatever 通常会在创建对象之前检查对象是否存在,但当您与远程设备通话时无法做出此决定。

如果远程服务器在您下载的历史记录中有一些相同的对象,但无法通过协商(仅交换一些提交 ID)检测到这一点,那么远程服务器可能会向您发送您已经拥有的对象。这些对象出现在一个包文件中,没有逻辑可以在垃圾收集之外删除重复的对象,这可能需要相当长的时间。

在不同的包文件中拥有相同的对象甚至可以提高性能,因为您可以使用更靠近的对象并共享增量链,而不是打开不同的包文件。

所有 git_odb_foreach 所做的就是遍历每个后端并使用它找到的任何内容调用回调。它不会尝试删除重复数据,因为它不知道那是你想要做的。因此,如果一个对象以松散和打包的形式存在,或者存在于多个包文件中,那么它将是 return.

但是请注意,您的命令 git rev-list --objects --all | wc -l 正在执行与 git_odb_foreach 调用完全不同的操作。该命令要求所有对象可从引用访问,而函数调用正在获取所有现有对象,并且在许多情况下(可能是大多数)这些数字不会匹配。例如。如果您曾经这样做 git add,对象数据库中将有一个无法从任何引用访问的 blob。