【问题标题】:Can I clone part of a Mercurial repository?我可以克隆 Mercurial 存储库的一部分吗?
【发布时间】:2010-12-17 05:31:48
【问题描述】:

是否可以克隆 Mercurial 存储库的一部分?假设存储库非常大,或者包含多个项目或多个分支。我可以只克隆存储库的一部分吗?

例如在 Subversion 中,您可能有 trunkbranches。如果我只想获得主干(或其中一个分支),我可以请求[project]/trunk。如果我克隆 hg repo,我会得到树干和所有的分支。这可能是我不想要的很多信息。我可以避免得到这个吗?

或者,如果我想在一个 hg repo 中有多个项目,我应该怎么做? IE。这样我就可能只得到其中一个项目而忽略其他项目。

【问题讨论】:

标签: mercurial dvcs


【解决方案1】:

是的,你可以。我确定你已经继续前进了,但是为了那些以后会在这里闲逛的人,我按照ConvertExtension 的文档,并编写了一个简单的批处理脚本:

@echo off
echo Converting %1
REM Create the file map
echo include %1 > ~myfilemap               
echo rename %1 . >> ~myfilemap 
REM Run the convert process
hg convert --filemap ~myfilemap .\ ..\%1   
REM Delete the file map
del ~myfilemap                             
cd ..\%1
REM update the new repo--to create the files
hg update                                  

将其命名为split.cmd,并将其放在要拆分的存储库的目录中。比如说你有C:\repos\ReallyBigProject,一个子文件夹是C:\repos\ReallyBigProject\small-project。在命令提示符下,运行:

cd\repos\ReallyBigProject
split.cmd small-project

这将创建C:\repos\small-project,其中包含较大项目的相关修订历史记录。

convert 默认不启用。您需要确保 .hg\hgrc 文件中存在以下行(在我的示例中为 c:\repos\ReallyBigProject\.hg\hgrc):

[extensions]
hgext.convert=

【讨论】:

  • 我认为这不会让您推迟任何更改。您可以将本地更改导出到补丁文件,然后将其导入到上游的完整本地副本中,但这首先会破坏部分克隆的要点。此外,OP 没有具体说明他是否想要浅克隆(相同的树,更少的修订)或部分克隆(子树,部分或全部修订)。无论哪种情况,convert 都会改变哈希值。
  • 使用 convert 通常(或总是?:)不会产生 克隆,而是与原始“无关”的衍生副本。这将完全抑制将更改推回源存储库。它很有用,但并不是人们所期望的。
【解决方案2】:

@尼克

“例如,在 Subversion 中,您可能有主干和分支。如果我只想获得主干(或其中一个分支),我可以请求 [project]/trunk。如果我克隆 hg 存储库,我将获得主干和所有分支机构。这可能是我不想要的很多信息。我可以避免得到这些吗?”

当然。只需使用hg clone -r <branch> 并只获取您想要的分支。如果您有很多分支,则每个分支都需要一个-r <branch><branch> 不必是命名分支:您可以简单地拥有多个未命名的头(或使用书签命名的头,尽管这些仍然不完美,因为目前它们没有出现在推/拉/克隆中) .

请记住,在 DVCS 中,包括 Mercurial,分支通常是短暂的,并且经常相互合并。如果你拉一个分支,你仍然会得到它与任何其他分支的共同历史。

【讨论】:

  • 提醒一下,-b 用于指定要克隆的分支(您仍然可以使用多个 -b ),-r 用于指定变更集。
【解决方案3】:

据我所知,这是不可能的。但与 Subversrion 相比,克隆整个 repos 可能并不比仅从 SVN 中克隆一个分支慢。

引用UnderstandingMercurial:

许多 SVN/CVS 用户希望托管 相关项目合二为一 存储库。这真的不是什么hg 是为,所以你应该尝试 不同的工作方式。这 尤其意味着,你不能 只签出一个目录 存储库。

如果您绝对需要托管 多个项目在一种 元存储库虽然,你可以试试 Subrepositories 功能是 Mercurial 1.3 或 老ForestExtension

【讨论】:

  • 这是一个很大的遗漏,因为很多托管网站只提供一个 repo。使用 svn,我只需从主分支中提取一个分支,就可以有效地拥有尽可能多的 repos。 subrepos 听起来像个 hack。
  • 从中心化的角度来看,这是有道理的。但是 Mercurial 和 Git 是去中心化的。 1 个项目 = 1 个 repos,这就是它的工作方式。
  • @Nick:不,听起来那些托管服务提供商不了解分布式版本控制。
  • 这可能不再正确。 hg help clone 显示 -b --branch BRANCH [+] clone only the specified branch。当我输入 hg branches 以这种方式克隆一个 repo 时,它会显示唯一请求的。
  • OP 询问 repo 中的指定目录,而不是指定的分支。
【解决方案4】:

@尼克说:

“这是一个很大的遗漏,因为很多托管站点只提供一个 repo。使用 svn,我可以有效地拥有尽可能多的 repo,只需从主分支中获取一个分支。subrepos 听起来像一个 hack。”

Subrepos(又名子模块)并不像“狭义克隆”那么理想。但至少对于在一个托管站点的存储库中有许多不同的项目,您可以在一个存储库中拥有多个代码库。这不允许您分割一个存储库的不同部分/项目的子目录,但它让您管理多个项目。您所做的是有许多命名分支,每个分支都植根于空(或空)变更集(即它们没有共同的根修订版)。跟踪分支可能会有点混乱,但它确实有效。

例如:

hg init
hg branch project-1
# Changes, commits, repeated as needed
hg update null
hg branch project-2
# Changes, commits, repeated as needed

您现在可以查看所有项目:

> hg branches
project-2                      5:42c2beffe780
project-1                      2:43fd60024328

这些项目是不相关的(尽管您可以合并它们):

> hg debugancestors
-1:000000000000 

最有用的是:你可以只克隆你想要的项目,其他的不会混进去:

> hg clone <repository> -r project-1

这个图表看起来像这样 (hg log -qG):

@  5 | project-2 | {tip}
|
o  4 | project-2
|
o  3 | project-2

o  2 | project-1
|
o  1 | project-1
|
o  0 | project-1

您可以根据需要对任意数量的项目执行此操作,使用hg branches 列出每个项目,并使用hg update 在它们之间跳转。这需要一些注意,因为命名分支支持并不完美。一方面它并不总是直观的(阅读 Mercurial 1.4 中的 hg clone -u —— 克隆时 1.4 之前的行为令人惊讶)。但它确实有效。

【讨论】:

  • 是的,很酷的是,您可以随时通过更新到修订版 0 并从此处提交到新分支来创建新项目。但是 clone 命令仍然会克隆整个 repos,对吗?
  • @Savageman:没必要。使用hg clone -r &lt;branch&gt; 你只会得到给定的分支。如果你想要整套项目,hg clone 会做你想做的,是的。
【解决方案5】:

Mercurial 和 Git 只允许对整个存储库进行克隆。因此建议每个项目都有自己的存储库。

Mercurial 有一个 forest extension 以方便为项目存储库创建一个“森林”。该扩展将每个项目保存在一个单独的存储库中,但提供了将所有林存储库一起更新/推送/拉取的选项。

【讨论】:

  • 但即使是 subrepos 在 1.3 中似乎也是实验性的。这对我来说是一个很大的遗漏。
  • @Nick:听起来你是在与 DVCS 作斗争,而不是在使用它。花一些时间了解它的工作原理,您会很快意识到它的好处。
【解决方案6】:

可以要求 Mercurial 使用 hg clone -r branchname 仅克隆一个分支(请参阅 Mercurial clone from a branch)。

借助 Google 的 NarrowHG extension 扩展,可以执行窄克隆(有关类似问题,请参阅 How do I clone a sub-folder of a repository in Mercurial?)。

【讨论】:

    【解决方案7】:

    我知道在这个问题被问到近 10 年后,我偶然发现 这个问题是偶然的。

    有一个新的 mercurial 扩展 call sparse 允许您执行此操作。

    【讨论】:

    • sparse.py 扩展仅使 窄检出 成为可能(这不会影响获取的历史记录),而问题是关于不获取分支。更多讨论请参见*.com/a/40355673/2732969
    【解决方案8】:

    这是对 Vadim Kotov 解决方案的可能改进,它支持 small-project 名称/子文件夹中的空格:

    @echo off
    echo Converting "%~1"
    REM Create the file map
    echo include "%~1" > ~myfilemap               
    echo rename "%~1" . >> ~myfilemap 
    REM Run the convert process
    hg convert --filemap ~myfilemap .\ "..\%~1"
    REM Delete the file map
    del ~myfilemap                             
    cd ".\%~1"
    REM update the new repo--to create the files
    hg update
    

    【讨论】: