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

时间:2010-06-22 23:57:47

标签: git version-control mercurial dvcs bazaar

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

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

  • 仅克隆存储库的一部分
  • 合并两个存储库(保留其历史记录!)
  • 将一些文件从一个存储库复制到另一个存储库

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

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

7 个答案:

答案 0 :(得分:7)

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

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

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

答案 1 :(得分:5)

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

答案 2 :(得分:5)

  

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

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

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

答案 3 :(得分:3)

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

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

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

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

答案 4 :(得分:3)

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

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

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

答案 5 :(得分:3)

从Git 2.17(2018年第二季度,10年后)开始, 可以执行Mercurial计划实施的任务:" narrow clone",也就是说,您只能检索特定子目录的数据的克隆 这也称为"部分克隆"。

这与当前的

不同
  • shallow clone
  • 从另一个工作文件夹中的克隆仓库中复制您需要的内容。

请参阅commit 3aa6694commit aa57b87commit 35a7ae9commit 1e1e39bcommit acb0c57commit bc2d0c3commit 640d8b7,{{3} (2017年12月8日)commit 10ac85c Jeff Hostetler (jeffhostetler)commit a1c6d7ccommit c0c578bcommit 548719fcommit a174334commit 0b6069f(2017年12月8日)。{
} (由Jonathan Tan (jhowtan)合并于Junio C Hamano -- gitster --,2018年2月13日)

以下是commit 6bed209

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

还有其他tests for a partial clone

特别是other commits involved in that implementation of a narrow/partial clone

  

sha1_file:支持懒洋洋地抓取丢失的对象

     

sha1_file从配置的远程中获取对象   extensions.partialclone每当请求对象但遗失时。{/ p>

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

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

  

upload-pack:当config

禁用时禁用对象过滤      

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

     

但配置项目还远远不够,它控制着是否   ' filter'功能被公布,但如果(自定义)客户端忽略   能力广告并传递过滤器规范,   尽管allowFilter是假的,服务器也会处理它。

     

如果发现安全漏洞,这一点尤为重要   这个新的实验部分克隆代码   没有uploadpack.allowFilter的安装不应该受到影响,因为它们不打算支持部分克隆,但它们会被扫描出来   脆弱的。

Git 2.20(2018年第二季度)增强了这一点,因为" git fetch $repo $object"在部分克隆中没有正确获取promisor packfile中已被修复的对象引用的ask-for对象。

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

  

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

     

将一个称为promisor对象的对象提取到本地时   存储库,commit a1e9dff中的连接检查   成功,导致绕过物体转移。
  但是,如果仅仅承诺并且实际上不存在该对象,则不应该发生这种情况。

     

因为这发生了,当用户调用&#34; git fetch origin <sha-1>&#34;上   在命令行中,甚至可能无法实际获取<sha-1>对象   虽然该命令返回退出代码0.这是一个类似的问题   (但有不同的原因)由quickfetch() in builtin/fetch.c确定的那个   (&#34; upload-pack:发送refs&#39;对象尽管&#34;过滤&#34;&#34;,2018-07-09,Git v2.19.0-rc0)。

     

因此,a0c9016也可以直接检查是否存在   要获取的所有对象。

您可以列出部分克隆的对象,不包括&#34; promisor&#34;对象,update quickfetch()

  

(仅供内部使用。)预滤器对象遍历在promisor边界   这与部分克隆一起使用   这比--missing=allow-promisor强,因为它限制了遍历,而不是仅仅消除有关丢失对象的错误。

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

git rev-list --exclude-promisor-objectscommit 4cf6786(2018年12月5日) (由Matthew DeVore (matvore)合并于Junio C Hamano -- gitster --,2019年1月14日)

  

&#34; git rev-list --exclude-promisor-objects&#34;必须从命令行获取一个本地不存在的对象(并且可以延迟使用)而不进行barfing,但代码解除引用为NULL。

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

  

当在命令行上同时使用--exclude-promisor-objects--objects-edge-aggressive和缺少的对象调用命令时,rev_info.cmdline数组可能会获得&#的值的NULL指针39; item&#39;场。
  在这种情况下防止取消引用NULL指针。

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

commit c333fe7commit bbcde41(2018年12月3日) (由Matthew DeVore (matvore)合并于Junio C Hamano -- gitster --,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看到该选项之前打开,否则它将导致BUG崩溃。以上列表由以下事实支持:没有其他命令被内省调用   通过另一个命令传递--exclude-promisor-object

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

commit 6e5be1f(201年4月5日)和commit 7fbbcb2(2019年3月29日)commit 0f4a4fbJonathan Tan (jhowtan)合并于Junio C Hamano -- gitster --,2019年4月25日)

  

diff:批量抓取丢失的blob

     

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

     

这类似于commit 32dc15d(&#34; unpack-trees:批量抓取缺失   blobs&#34;,2017-12-08,Git v2.17.0-rc0),但是对于另一个命令。

答案 6 :(得分: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.

这是否提供了您正在寻找的东西?