开源中国

我们不支持 IE 10 及以下版本浏览器

It appears you’re using an unsupported browser

为了获得更好的浏览体验,我们强烈建议您使用较新版本的 Chrome、 Firefox、 Safari 等,或者升级到最新版本的IE浏览器。 如果您使用的是 IE 11 或以上版本,请关闭“兼容性视图”。
使用 Libgit2 实现在数据库中存储 Git 仓库 - 技术翻译 - 开源中国社区

使用 Libgit2 实现在数据库中存储 Git 仓库 【已翻译100%】

oschina 推荐于 4年前 (共 10 段, 翻译完成于 03-02) 评论 3
收藏  
59
推荐标签: libgit2 待读

Git有一个出名的定义明确的数据存储结构。在每一个Git仓库的.git目录下,你都可以找到下面几个目录:用于存储数据的objects目录,refs目录,用于分支以及标记指针等等。除此之外,Git仓库中所有的信息都采用平面文件的方式存储,只是有些文件会涉及多一点格式

然而,我们发现,在Git仓库中存储数据并不只有上述一种方式。实际上,你可以使用下面几种方式存储:关系或者非关系型数据库,一个内存中的数据结构,或者类似亚马逊S3的东西。

这可以通过libgit2库提供的灵活的后端来实现。


艾柯
 翻译得不错哦!

这意味着什么

使用可选择的Git存储解决方案可能是最有趣的,对于提供的Git托管服务或产品来说 – 就像我们在 Deveo 做的一样. 托管服务提供商的用例,包括:

  • 缓存的Git数据快速的访问,通过使用一个内存备份或Memcached或Redis的备份与回退,可以是传统的文件存储。

  • 构建一个容错的解决方案, 甚至是一个多点复制的解决方案, 通过在设计用于此目的现代数据库系统中存储数据. 至少 Voldemort, Riak, 或者 Cassandra 都可行.

在此之外,我还希望当我们访问GIT时,有一套完备的可拔插存储的用例。

Mike-Tang
 翻译得不错哦!

Git仓库的两种数据储存

虽然当我们不深入研究Git的用户接口,怎么也想不到它的内部结构,但是实际上Git仓库特别简单。Git仓库的核心仅仅由两种主要的结构组成:object数据库和ref数据库,其它都是基于此的。

object数据库

object数据库存储着所有的数据。包括所有文件的内容,目录结构,提交,一切都在object数据库中。然而,值得注意的是object数据库本质上只是一个键值存储。

在object数据库中,Git采用基于散列检索的方式存储数据,这意味着存储中的键是值的散列(SHA1)。

这也带来更一步的有趣的影响:在object数据库中的值本质上是不变的,因此并不需要更新操作。

剩下的就是一个能够进行四步操作的基本数据结构:

get_keys()
read(key_or_prefix)
add(key,value)
delete(key)

很容易可以看出,类似上面的结构并不一定要通过平面文件存储的方式来实现!Git默认的,基于文件的object数据库仅仅是其抽象概念的一种实现方式。

艾柯
 翻译得不错哦!

Ref 数据库

ref 数据库储存了一个Git库的references - branches、tags以及HEAD.

就像对象数据库,ref数据库基本上也是一个键值存储。键引用的参考标识符,值是SHA1哈希值,它们按提交对象的次序存在于对象数据库中。

ref数据库的值是可变的,这是和对象数据库相比时的一个主要差异。master指示的提交点随着时间改变而改变。这意味在具体操作时ref数据库需提供一些差异:

get_keys()
read(key)
write(key, value)
rename(old_key, new_key)
delete(key)
Garfielt
 翻译得不错哦!

Libgit2

Libgit2是用纯C写的一个Git实现。它被设计作为Git reference实现的一个替代,其提供了与其他的库和应用程序的简便连接。它实际上是Git绑定到其他许多编程语言的基础。

libgit2的一个不太为人知的特性是它有一个可插拔的后端,这意味着除了像Git常规的将对象数据库和ref数据库存储在平面文件中外,你还可以提供自己的后端实现,并且可以做任何你想做的。让我们看看它是如何工作的。

Garfielt
 翻译得不错哦!

libgit2对象数据库后端实现

libgit2对象数据库实现代码是通过C结构git_odb_backend里的函数来访问数据的, git2/sys/odb_backend.h里定义了这个结构。它的基本功能上面已经给予了说明,为了便于使用,它还具有其他几个功能(比如仅读取对象头,访问流数据,写文件包等)。
在libgit2里,内置两个这种C结构的实现。这两个实现都支持传统Git所具有的两种对象存储格式:

  • odb_loose是以松散文件格式访问对象数据库的后端实现。它访问的每个对象都位于objects目录下的对应的单个文件里,而且每个文件的名字对应的是文件内容的SHA1结果。

  • odb_pack是以文件包格式访问对象数据库的后端实现。它访问的对象位于Git的文件包内,Git文件包是一种文件格式,这种文件格式既节省了对象存储空间,又便于推送或者拉取对象时对象的传送。

在你创建Git对象数据库的时候,你可以使用git_odb_backend结构的任意一种实例,包括用户自定义。这就允许你插入自己编写的代码实现,在这篇文章的后一部分我们将会看到怎么做到这些。

几点人
 翻译得不错哦!

libgit2 Ref数据库的后端实现

同样,你也可以使用用户自定义的ref数据库的后端实现,最终就会形成一个完全由普通的文本文件组成的Git仓库。libgit2为了达到这个目的而使用的这项技术与其在对象数据库所使用的技术本质上是相同的。这里所使用的结构是git_refdb_backend,定义在git/sys/refdb_backend.h里,而且对于不同的访问操作提供了不同的函数。

libgit2里对ref数据库后端仅提供了一种实现:文件系统后端实现 refdb_fs,它是通过访问Git仓库的 refs目录的refs来实现的。

几点人
 翻译得不错哦!

其它对象数据库后端实现

除了上面已经提到的内置后端实现外,由libgit2团队维护的 libgit2-backends仓库还提供了几个用户自定义的对象数据库后端实现:

这些对象数据库后端不但可以使用,而且还是你编写自己的后端实现的非常好的起点。

几点人
 翻译得不错哦!

设置

让我们来看看如何实际使用这些替代后端。 

通常,当我们使用内置的后端时会使用usual.gitdirectory中包含的文件系统路径调用git_repository_open,比如松散对象数据库、packfiles和ref路径。 

当使用自定义的后端时我们需要做的是调用git_repository_wrap_odb并提供我们自己的数据库对象和一个自定义的后端。 

比方说,我们有一个为Voldemort数据库编写的自定义后端,使用下面的构造函数:

int git_odb_backend_voldemort(git_odb_backend **backend_out, git_repository *repo, const char *repo_id, const char *bootstrap_url, const char *store_name);
int git_refdb_backend_voldemort(git_refdb_backend **backend_out, git_repository *repo, git_refdb *refdb, const char *bootstrap_url, const char *store_name);

下面是我们使用这些后端创建一个Git仓库的方法:

git_repository    *repo;
git_odb           *odb;
git_odb_backend   *voldemort_odb_backend;
git_refdb         *refdb;
git_refdb_backend *voldemort_refdb_backend;
int               error = 0;

error = git_odb_new(&odb);
if (!error)
  error = git_repository_wrap_odb(&repo, odb);
if (!error)
  error = git_odb_backend_voldemort(&voldemort_odb_backend, repo, "my_repo", "tcp://localhost:6666", "git_odb");
if (!error)
  error = git_odb_add_backend(odb, voldemort_odb_backend, 1);
if (!error)
  error = git_refdb_new(&refdb, repo);
if (!error)
  error = git_refdb_backend_voldemort(&voldemort_refdb_backend, refdb, "my_repo", "tcp://localhost:6666", "git_refdb");
if (!error)
  error = git_refdb_set_backend(refdb, voldemort_refdb_backend);
if (!error)
  git_repository_set_refdb(repo, refdb);

  • 第8行我们构造了一个不涉及任何后端的对象数据库。

  • 第10行我们构造了一个基于这个数据库的一个Git仓库。

  • 第12行我们构造了Voldemort对象数据库后端。

  • 第14行我们将voldemort对象数据库后端挂到对象数据库。对象书库支持多后端,顺序看起来基于一个属性数字。我们设定Voldemort后端的属性为1.

  • 第16行我们构造了一个不涉及任何后端的ref数据库。

  • 第18行我们构造了Voldemort ref数据库后端,就像我们创建对象数据库那样。

  • 第20行我们将Voldemort ref数据库后端挂到ref数据库。

  • 第22行我们最终将ref数据库挂到仓库上,这样我们有了一个可读写的可正常运转的仓库。

Garfielt
 翻译得不错哦!

在替换Voldemort后端时,你自然可以使用一个自己的实现,或使用libgit2-backends中的一个已存在实现。你甚至可以通过在添加多种自定义对象数据库时使用多种不同的优先级来提供多种后端。举例来说,这样在实施高速缓存时是非常便捷的。 

如果你不使用原始的C,你可以看看所有libgit2绑定的语言来确认下用你的编程语言如何实现。举例来说,我已经使用了Rugged用Ruby绑定了一下,这样我可以在Ruby代码中自定义插入一个后端。

Garfielt
 翻译得不错哦!
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们
评论(3)
Ctrl/CMD+Enter

很有趣!
学知识了
nice
顶部