我正在一个大型git repo(在本例中为linux-2.6)上运行一个简单的对象id gatherer,准备将所述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吗?
答案 0 :(得分:1)
除了作为松散对象存在之外,Git对象可能存储在多个packfile中。这只是可能发生的事情,而git实现必须处理。
虽然git / libgit2 /在创建对象之前通常会检查某个对象是否存在,但在与远程对话时无法做出此决定。
如果某个遥控器在历史记录中有一些相同的对象正在下载但是没有办法通过协商检测到这个(只交换一些提交ID),那么遥控器可能会向您发送已有的对象。这些对象包含在一个packfile中,没有逻辑可以去除垃圾收集之外的重复文件,这可能需要一段时间。
在不同的文件夹中使用相同的对象甚至可以提高性能,因为您可以使用更靠近的对象并共享增量链而不是打开不同的包文件。
所有git_odb_foreach
都会通过每个后端并使用它找到的任何内容调用回调。它不会尝试进行重复数据删除,因为它无法知道您想要做什么。因此,如果一个对象同时存在于松散和包装中,或者存在于多个包文件中,那么它将返回它。
但请注意,您的命令git rev-list --objects --all | wc -l
正在执行与git_odb_foreach
调用完全不同的操作。该命令要求所有可从参考访问的对象,而函数调用正在获取所有现有的对象,并且在许多情况下(可能是大多数)这些数字不匹配。例如。如果你曾经git add
,那么对象数据库中将会有一个blob无法从任何引用中获得。