是否有支持部分结账/克隆的分布式版本控制系统?

问题描述 投票:15回答:7

据我所知,所有分布式版本控制系统都要求您克隆整个存储库。因此,将大量内容放入一个存储库是不明智的(感谢this answer)。我知道这不是一个bug而是一个功能,但我想知道这是否是所有分布式版本控制系统的要求。

在分布式rcs中,文件(或一大块内容)的历史记录是有向非循环图,那么为什么不能克隆这个单个DAG而不是存储库中所有图形的集合?也许我想念一些东西,但以下用例很难做到:

  • 克隆只是存储库的一部分
  • 合并两个存储库(保留它们的历史!)
  • 将一些文件从一个存储库复制到另一个存储库

如果我从多个项目中重用其他人的代码部分,我无法保留其完整的历史记录。至少在git中我可以想到一个(相当复杂的)解决方法:

  1. 克隆完整的存储库
  2. 删除我不感兴趣的所有内容
  3. 重写历史记录以删除主文件中没有的所有内容
  4. 将剩余的存储库合并到现有存储库中

我不知道Mercurial或Bazaar是否也可以这样做,但至少它根本不容易。那么是否有任何支持部分检出/克隆的分布式rcs?它应该支持一个简单的命令,从一个存储库获取包含其历史记录的单个文件,并将其合并到另一个存储库这样您就不需要考虑如何将内容构建到存储库和子模块中,但您可以根据需要快乐地拆分和合并存储库(极端情况是每个文件的一个存储库)。

git version-control mercurial dvcs bazaar
7个回答
7
投票

从版本2.0开始,不可能使用Mercurial制作所谓的"narrow clone",也就是说,只能检索特定子目录的数据的克隆。当你只检索部分历史记录时,我们称之为“浅层克隆”,例如,最后100次修订。

正如您所说,基于DAG的常见历史模型中没有任何内容排除此功能,我们一直在努力。 Mercurial撰稿人Peter Arrenbrecht对窄克隆实施了两种不同的方法,但这两种方法尚未合并。

顺便说一下,您当然可以将现有的Mercurial存储库拆分成多个部分,其中每个较小的存储库只包含原始存储库的特定子目录的历史记录。 convert extension就是这个的工具。但是,每个较小的存储库都与较大的存储库无关 - 棘手的部分是使拆分无缝,以便更改集保持其身份。


5
投票

git有一个子树模块,允许您将存储库的一部分拆分为新的存储库,然后将更改合并到原始子树和子树。这是关于github的自述文件:http://github.com/apenwarr/git-subtree/blob/master/git-subtree.txt


5
投票

在分布式rcs中,文件(或一大块内容)的历史记录是有向非循环图,那么为什么不能克隆这个单个DAG而不是存储库中所有图形的集合?

至少在Git中,表示存储库历史的DAG适用于整个存储库,而不仅仅是单个文件。每个提交对象都指向一个“树”对象,该对象表示当时存储库的整个状态。

Git 1.7支持"sparse checkouts",它允许您限制工作副本的大小。但是,仍然克隆了整个存储库数据。


3
投票

在集市中,您可以拆分和连接存储库的各个部分。

split-command允许您将存储库拆分为多个存储库。 join-command允许您合并存储库。两者都保持着历史。

然而,这并不像SVN模型那样方便,您可以在其中签出/提交子树。

有一个名为Nested-Trees的计划功能用于集市,可能允许部分结账。


3
投票

我希望其中一个RCS能够增加窄克隆功能。我的理解是GIT的架构(在整个回购中跟踪的变化/移动)使得这非常困难。

Bazaar以支持许多不同类型的工作流程而自豪。缺乏狭窄的克隆功能禁止像bzr / hg / git中的SVN / CVS工作流,所以我希望他们有动力找到一些方法来做到这一点。

新功能不应以牺牲基本功能为代价,例如从repo获取单个文件/目录的功能。现代rcs的“分布式”功能“很酷”,但我认为不鼓励良好的开发实践(频繁的合并/持续集成)。这些新的RCS似乎都缺乏非常基本的功能。即使没有真正的分支/标记支持的SVN似乎也是CVS imo的倒退。


3
投票

从Git 2.17(2018年第二季度,10年后)开始,可以执行Mercurial计划实施的工作:“narrow clone”,即只检索特定子目录数据的克隆。 这也称为“部分克隆”。

这与目前不同

  • shallow clone
  • 在另一个工作文件夹中克隆的repo所需的副本。

参见commit 3aa6694commit aa57b87commit 35a7ae9commit 1e1e39bcommit acb0c57commit bc2d0c3commit 640d8b7commit 10ac85cJeff Hostetler (jeffhostetler)(2017年12月08日)。 参见commit a1c6d7ccommit c0c578bcommit 548719fcommit a174334commit 0b6069fJonathan Tan (jhowtan)(2017年12月08日)。 (由Junio C Hamano -- gitster --合并于commit 6bed209,2018年2月13日)

这是tests for a partial clone

git clone --no-checkout --filter=blob:none "file://$(pwd)/srv.bare" pc1 

还有其他other commits involved in that implementation of a narrow/partial clone

特别是,commit 8b4c010

sha1_file:支持懒惰地获取丢失的对象

无论何时请求对象但缺少对象,都要教sha1_fileextensions.partialclone中配置的远程中获取对象。


关于Git 2.17 / 2.18的警告:最近添加的“部分克隆”实验功能在它不应该启动时,即,即使设置了extensions.partialclone也没有定义部分克隆过滤器。

commit cac1137(2018年6月11日)Jonathan Tan (jhowtan)。 (由Junio C Hamano -- gitster --合并于commit 92e1bbc,2018年6月28日)

upload-pack:配置禁用时禁用对象过滤

upload-pack获得部分克隆支持(v2.17.0-rc0~132 ^ 2~12,2017-12-08)时,它被uploadpack.allowFilter配置项保护,以允许服务器操作员控制何时开始支持它。

但是,配置项目还远远不够:它控制是否广告'filter'功能,但如果(自定义)客户端忽略功能广告并且仍然传递过滤器规范,尽管allowFilter为false,服务器仍会处理。

如果在此新的实验性部分克隆代码中发现安全性错误,这一点尤为重要。 没有uploadpack.allowFilter的安装不应该受到影响,因为它们不打算支持部分克隆,但它们会被卷入易受攻击的状态。


这是通过Git 2.20(2018年第二季度)得到增强的,因为部分克隆中的“git fetch $repo $object”没有正确获取promisor packfile中已修复的对象引用的ask-for对象。

commit 35f9e3ecommit 4937291Jonathan Tan (jhowtan)(2018年9月21日)。 (由Junio C Hamano -- gitster --合并于commit a1e9dff,2018年10月19日)

fetch:在部分克隆中,检查目标的存在

当将一个称为promisor对象的对象提取到本地存储库时,quickfetch() in builtin/fetch.c中的连接检查会成功,从而导致绕过对象传输。 但是,如果仅仅承诺并且实际不存在该对象,则不应该发生这种情况。

因为这种情况发生,当用户在命令行上调用“git fetch origin <sha-1>”时,即使命令返回退出代码0,也可能实际上不会获取<sha-1>对象。这是一个类似的问题(但有不同的原因)一个由a0c9016修复(“upload-pack:发送refs'对象,尽管”过滤器“,2018-07-09,Git v2.19.0-rc0)。

因此,update quickfetch()还要直接检查是否存在要提取的所有对象。


您可以使用git rev-list --exclude-promisor-objects列出部分克隆的对象,不包括“promisor”对象

(仅供内部使用。)Prefilter对象在promisor边界处遍历。 这与部分克隆一起使用。 这比--missing=allow-promisor强,因为它限制了遍历,而不仅仅是对丢失对象的沉默。

但请务必使用Git 2.21(2019年第一季度)以避免段错误。

参见commit 4cf6786撰写的Matthew DeVore (matvore)(2018年12月5日)。 (由Junio C Hamano -- gitster --合并于commit c333fe7,2019年1月14日)

git rev-list --exclude-promisor-objects”必须在没有barfing的情况下从命令行获取本地不存在的对象(并且可以延迟使用),但代码取消引用NULL。

list-objects.c:不要丢失cmdline对象的段错误

当使用--exclude-promisor-objects--objects-edge-aggressive和命令行上缺少的对象调用命令时,rev_info.cmdline数组可以获得'item'字段值的NULL指针。 在这种情况下防止取消引用NULL指针。


请注意,Git 2.21(2019年第一季度)修复了一个错误:

参见commit bbcde41撰写的Matthew DeVore (matvore)(2018年12月3日)。 (由Junio C Hamano -- gitster --合并于commit 6e5be1f,2019年1月14日)

exclude-promisor-objects:在允许选项时声明

--exclude-promisor-objects选项在至少两个命令中引起一些有趣的行为:logblame。 它导致BUG崩溃:

$ git log --exclude-promisor-objects
BUG: revision.c:2143: exclude_promisor_objects can only be used
when fetch_if_missing is 0
Aborted
[134]

修复此问题,以便将该选项视为任何其他未知选项。 必须支持它的命令是有限的,因此在这些命令中声明支持该标志。 特别是:

pack-objects
prune
rev-list

通过搜索在--exclude-promisor-objects之外解析revision.c的逻辑找到命令。 需要在revision.c之外的额外逻辑,因为在fetch_if_missing看到选项之前必须打开revision.c,否则它将崩溃。上面的列表得到以下事实的支持:传递--exclude-promisor-object的另一个命令不会内省地调用其他命令。


Git 2.22(2019年第二季度)优化了窄克隆: 在懒惰的克隆中运行“git diff”时,我们可以预先知道我们需要哪些丢失的blob,而不是等待按需机制逐个发现它们。 旨在通过批量处理这些承诺blob的请求来实现更好的性能。

参见commit 7fbbcb2commit 0f4a4fb(2019年4月5日)和Jonathan Tan (jhowtan)(2019年3月29日)。 (由Junio C Hamano -- gitster --合并于commit 32dc15d,2019年4月25日)

diff:批量获取丢失的blob

在部分克隆中运行“git show”或“git diff”等命令时,将所有缺失的blob批处理为一个请求。

这类似于c0c578b(“unpack-trees:批量获取丢失的blob”,2017-12-08,Git v2.17.0-rc0),但是对于另一个命令。


Git 2.23(2019年第3季度)将保证批量丢失blob部分。

commit 31f5256Derrick Stolee (derrickstolee)(2019年5月28日)。 (由Junio C Hamano -- gitster --合并于commit 5d5c46b,2019年6月17日)

sha1-file:拆分OBJECT_INFO_FOR_PREFETCH

OBJECT_INFO_FOR_PREFETCH位标记被添加到sha1-file.c中的0f4a4fbsha1-file:support OBJECT_INFO_FOR_PREFETCH,2019-03-29,Git v2.22.0-rc0),用于在启用时阻止fetch_objects()方法。

但是,目前的使用存在问题。 OBJECT_INFO_FOR_PREFETCH的定义是通过向OBJECT_INFO_QUICK添加32来给出的。 这清楚地在定义(在评论中)上面说明,这是如此OBJECT_INFO_FOR_PREFETCH暗示OBJECT_INFO_QUICK。 问题是使用“flag & OBJECT_INFO_FOR_PREFETCH”意味着OBJECT_INFO_QUICK也意味着OBJECT_INFO_FOR_PREFETCH

OBJECT_INFO_FOR_PREFETCH中的单个位拆分为新的OBJECT_INFO_SKIP_FETCH_OBJECT作为单个位,并将OBJECT_INFO_FOR_PREFETCH保持为两个标志的并集。

并且“git fetch”进入一个懒惰的克隆忘记获取在瘦包文件中完成增量所必需的基础对象,这已被更正。

参见commit 810e193commit 5718c53(2019年6月11日)和commit 8a30a1ecommit 385d1bf(2019年5月14日)Jonathan Tan (jhowtan)。 (由Junio C Hamano -- gitster --合并于commit 8867aa8,2019年6月21日)

index-pack:预取缺少REF_DELTA基地

在获取时,客户端发送“have”提交ID,指示服务器不需要发送这些提交引用的任何对象,从而减少网络I / O. 当客户端是部分克隆时,客户端仍然以这种方式发送“have”,即使它没有将它作为“have”发送的提交引用的每个对象。

如果服务器省略了这样的对象,那很好:客户端可以在此获取之前懒惰地获取该对象,之后它仍然可以这样做。

问题是当服务器发送一个包含一个REF_DELTA对象的瘦包时,这个丢失的对象:index-pack无法修复瘦包。 当8b4c010(“sha1_file:支持懒洋洋地抓取丢失的对象”,2017-12-08,Git v2.17.0-rc0)中添加了对延迟提取丢失对象的支持时,index-pack中的支持因为相信它访问了repo而被关闭只做哈希冲突检查。 然而,事实并非如此:它还需要访问repo以解析REF_DELTA基础。

仍然应该在index-pack中关闭对延迟提取的支持,因为它被用作延迟提取过程本身的一部分(如果不是,可能会发生无限循环),但我们确实需要获取REF_DELTA基础。 (当获取REF_DELTA基地时,它们不太可能是REF_DELTA本身,因为我们在进行此类提取时不会发送“have”。)

要解决此问题,请在尝试解决之前预取所有缺少的REF_DELTA碱基。 这两者都确保尝试获取所有基础,并确保每个索引包调用只发出一个请求,而不是每个丢失对象发出一个请求。


0
投票

来自git help clone

--depth <depth> Create a shallow clone with a history truncated to the specified number of revisions. A shallow repository has a number of limitations (you cannot clone or fetch from it, nor push from nor into it), but is adequate if you are only interested in the recent history of a large project with a long history, and would want to send in fixes as patches.

这提供了你想要的东西吗?

© www.soinside.com 2019 - 2024. All rights reserved.