【问题标题】:How do I mirror an SVN repo dir structure in my working dir without a full root checkout?如何在没有完整根结帐的情况下在我的工作目录中镜像 SVN 存储库目录结构?
【发布时间】:2025-11-23 18:00:01
【问题描述】:

首先,几个操作参数:

  • .NET 开发使用 Visual Studio 2005/2008
  • TortoiseSVN 客户端

我只主要使用 Visual Source Safe 和 SourceGear Vault 源代码控制系统。在每一个中,我将存储库的根映射到本地工作目录。例如:

$/  -->  C:\source

只要本地目录存在,我的“工作副本”(svn)或“工作文件夹”(VSS)就已经设置好了。

要处理已经在源代码存储库中的新项目,我需要“获取该项目目录的最新”(VSS) 版本。

当我进入存储库中的任何子目录并“获取最新”(即 svn checkout)时,客户端将自动为我创建完整的目录层次结构,将结构镜像到我的本地磁盘上。因此,当我得到最新的

$/foo/bar/project1

它是在驱动器上创建的

C:\source\foo\bar\project1

在 subversion 中,当我检出一个目录时,我必须指定工作副本目录位置。如果我想正确地镜像我的工作副本目录结构以匹配存储库,我必须手动构建路径中的每个子目录,或者将存储库根目录检出到工作副本根目录,以获取存储库中的所有内容。

有没有办法在层次结构中获取存储库目录,以便在匹配的本地工作副本目录结构中创建它而无需所有手动干预?

这对于小型存储库不是问题,但在大多数情况下,我不需要很大比例的源存储库。为了不破坏对项目和资源的文件引用,必须维护物理结构。加上 SVN 的磁盘成本是给定文件的所有工作基础副本的实际源大小的两倍。

我目前正在使用 Tortoise。是否有其他 SVN 客户端可以满足我的需求?

【问题讨论】:

    标签: svn tortoisesvn visual-sourcesafe


    【解决方案1】:

    Subversion“签出”操作创建一个工作副本。你可能想要做的是检查你的整个项目(它会自动创建正确的目录结构,就像它在存储库中一样),然后使用 Subversion“更新”操作。该更新将更新指定目录和子目录中的所有内容。

    这可能是由于 VSS 和 Subversion 之间的术语不同。 Subversion Book 值得一读,尤其是关于Basic Usage 的章节。

    更新:我想我不太了解您的预期用例是什么。听起来您可能需要的 Subversion 1.5 新功能之一是sparse checkouts。这使您可以有选择地获取存储库的一部分,而不必获取全部内容。它为您提供管理所需数量的选项非常灵活。

    由于稀疏结帐相对较新,我认为 SVN 书没有更新以包含有关此功能的信息。已更新,请参阅 cmets。

    更新 2:听起来您可以通过使用 --depth=empty 选项将存储库的顶层检出到 c:\source 中来构建所需的内容。然后,对于您想要的每个子目录,根据需要使用 --depth=empty 或 --depth=infinity 更新该子目录。

    我相信这一切都源于 Subversion 的设计目标,即能够在您的系统上同时拥有多个独立的源代码树。使用 VSS,$/ 被全局配置为引用特定目录 (c:\source),因此您只能进行一次检出(每次切换时都不会弄乱全局配置)。

    【讨论】:

    • Greg - 我查看了稀疏结帐功能。虽然它看起来确实有用,但它仍然不是我所需要的。我需要的是一种组合:就像一个带有完整节点的稀疏分支。 IE。只是父目录,但目标目录的所有子目录。
    • 彼得——你想要的东西看起来很奇怪。您可能需要调整使用 Subversion 的方式。我看不出你想用你的使用模式解决什么问题......
    • Dave - 我希望我的本地源代码工作副本与源代码控制中相同的层次结构相匹配,这有多奇怪和奇怪?
    【解决方案2】:

    简短地回答您的粗体打印问题:无法在项目位置上方创建所有文件夹

    原因略长:

    您正在考虑 VSS 工作流程,其中您有 1 个工作文件夹,在您的本地目录中有一个固定路径。因此,您所能做的就是检查另一个项目,该项目将在您的工作文件夹内的本地 HD 上创建整个目录结构。

    在 SVN 中,您有 浮动 工作副本,您可以将存储库中的特定位置检出到您想要的任何位置。您甚至可以将您的工作副本移动到不同的地方!您的工作副本不需要在 HD 上固定位置。

    因此您不需要重新创建项目上方的文件夹结构。对于您的项目,它也不应该有任何区别。通过使用 floating 工作副本的 SVN 工作流程,您会更加灵活,其中绝对路径并不重要。

    但是,如果您对使用旧的基于 VSS 的工作流程感到更自在,您可以使用 --sparse-checkout 参数检查并手动重新创建结构或编写一个简单的批处理文件来执行此操作。我看不出这有什么好处,如果你继续使用 SVN 并忘记旧的生锈的 VSS 工作流程,你肯定会忘记这样做

    【讨论】:

      【解决方案3】:
      1. 首先使用 Repo Browser 浏览您的 Subversion 存储库。
      2. 向下导航到您想要的目录;你应该得到一个显示类似https://subversion:8443/svn/BranchMerge/Branches/TestWeb的URL
      3. 在左侧导航窗格中右键单击该目录,然后选择 Checkout...
      4. 从存储库文本框的 URL 复制(到剪贴板)目录路径“BranchMerge/Branches/TestWeb”。
      5. 将其粘贴到 Checkout directory 文本框中,与现有路径混合匹配,这样它就可以显示本地驱动器所需的层次结构。 "C:\source\BranchMerge/Branches/TestWeb"
      6. 点击“确定”后,应该会出现一个对话框,要求自动创建那些缺失的目录。
      7. 当然同意。

      【讨论】:

        【解决方案4】:

        我似乎找到了解决问题的合适方法。

        使用 TortoiseSVN,repo 浏览器中的“将项目更新到修订版”操作可用于在本地为任意 repo 路径重建存储库的文件夹结构。

        详细步骤为:

        1. 创建一个本地文件夹作为您需要为其维护物理文件夹结构的最高存储库文件夹的工作副本根
        2. 对存储库根目录进行浅层签出(签出,选择任何除了“完全递归”的“签出深度”)
        3. 从工作副本文件夹启动 repo 浏览器
        4. 找到你想要获取的 repo 路径
        5. 右键单击所需文件夹,选择“将项目更新到修订版”
        6. 保留 HEAD 修订和“工作副本”更新深度的默认值,点击确定

        这将使用所选 repo 路径的内容更新您的工作副本,包括直到结帐工作副本开头的所有父目录,从而在您的工作副本中镜像存储库的文件夹层次结构。

        关于“将项目更新到修订版”上下文菜单选项的说明:

        • 此选项仅出现在本地工作副本中尚不存在的存储库路径上
        • 看起来将“更新深度”保留为默认的“工作副本”对于获取所选路径的所有内容来说是可行的。 (而不必显式选择“完全递归”。)

        【讨论】:

          【解决方案5】:

          但问题的重点是,我不希望仅仅为了在初始结帐时创建目录结构而获取整个存储库。

          抱歉,如果我不清楚我是从一个干净、空的工作副本位置开始的。

          我已经阅读了 SVN 书籍的大部分内容。但是,它不包括这类问题。

          【讨论】:

            【解决方案6】:

            ankhsvn(开源)和VisualSVN(商业)是与 Visual Studio 集成的产品,可能更适合您的开发模型。

            【讨论】:

            • Ken - 我试过ankh。当提示输入本地路径时,它的行为很像乌龟。似乎仍然没有任何存储库根相对性的感觉。我打开了一个 VS sln,里面有 5 个项目,只签出了 sln 目录中的项目。并且没有创建父分支目录。
            • 对不起,彼得。我用过ankh,但方式与你描述的不同。不记得它是否会按照你的要求做。我相信 icelava 或 Peter Parker 发布的答案可能是您最好的选择。 Greg Hewgill 说了一些好话,但我仍然认为他没有理解这个问题。
            【解决方案7】:

            我大体上理解你们所说的“SVN 是如何工作的”。也许问题不是我不清楚,而是我正在成为更高代码组织问题的受害者。

            问题的根源在于项目依赖。我有许多具有许多依赖项的应用程序。由于 .NET 项目的层次结构,依赖项应位于某些物理位置。所以如果我要开始做这个项目:

            http://mysvn/svn/foo/bar/project1
            

            该项目将进入

            C:\source\foo\bar\project1
            

            现在该项目依赖于另一个项目。在.NET项目文件中,项目引用相对“后向引用”:

            ..\..\..\bar\foo\project2
            

            所以依赖项应该在本地工作副本中

            C:\source\bar\foo\project2
            

            因此,父目录结构至关重要。

            我不能将依赖项目存储为任何特定应用程序/项目的子项目,因为它们在许多项目之间共享。因此,他们住在一个特定项目树之外的自己的位置。因此,我确实需要确保将任何给定项目(及其依赖项)签出到相对于源树根的特定树位置,以确保对项目的引用不会中断或不会中断开发人员之间没有区别。否则,我们每个人都会不断更新引用以使它们工作,从而在源历史记录中产生大量噪音,并在开发人员之间不断中断。此外,构建服务器也不会将它们放在正确的位置。

            我还没有找到任何关于使用 SVN 进行 .NET 开发的好信息。 .NET 中有大量使用 SVN 或 CVS 的开源项目。然而,我看过的那些似乎总是处于一个相当孤立的结构中,以至于所有不同的项目都属于一个单一的源树位置。这使得获取所需的一切变得微不足道,因为您可以简单地递归地检查一条路径并获得所需的一切。

            如果有人使用 SVN 在 .NET 中进行企业开发,并且有许多跨项目存储位置边界的共享项目,我将非常感兴趣。

            开始感觉在团队中唯一可行的解​​决方案是简单地检查整个存储库以确保结构正确且一致。这对于拥有大量源代码的存储库来说是不幸的。

            【讨论】:

            • 对您的问题的回答存在明确的沟通问题。我很少从事 Visual Studio 工作,但我知道您对其他项目的引用以及它们的创建方式是什么意思。是否有任何方法可以使基本目录成为属性或变量,例如 IDE 中的 ${base}\project1?
            • Ken - 不幸的是,我不知道如何为引用的项目指定基本位置。 VS 为我们做这一切。通常,它们是反向引用,但我已经看到它们是明确的完整路径。但我还没有看到用户控制它的任何方法。
            【解决方案8】:

            好吧,首先,你的工作方式最终会导致问题。

            您寻找的原则是每个项目都应该有一个独立于任何其他项目的主干/分支/标签结构。签出trunk会自动获取所有代码,包括依赖项,这足以构建您的项目。

            你显然不处于那种位置,要移到它需要一些努力。但是,您可以使用一种变通方法来让您随心所欲地使用外部设备。

            1. 在 Repo-browser 中,在根目录下创建一个新的树文件夹,可能是“Projects”。
            2. 在此 Projects 文件夹中,为您的项目“MyProject”创建一个文件夹。
            3. 在此文件夹上,右键单击它并编辑属性,添加一个名为“svn:externals”的新属性 - 它会在列表中。
            4. 使用此属性定义项目所需的树。
            5. 结帐http://svnserver/svn/Projects/MyProject 将检索整个树。
            6. 正常工作。

            svn:externals 属性的一个例子可能是:

            http://mysvn/svn/foo/bar/project1 foo/bar/project1
            http://mysvn/svn/bar/foo/project2 bar/foo/project2
            

            虽然最好使用红皮书中详述的相对引用。

            【讨论】:

            • 感谢吉姆的建议。当我最近将我们的开发团队从 VSS 转换为 SVN 时,我不得不再次考虑这个问题(一次又一次)。我想出了一个类似的想法。我想为“项目”创建一个 repo 路径,它基本上只是一组空的目录(每个应用程序解决方案一个),其中包含构成每个解决方案的所有必要项目的外部,基本上导致项目的扁平树。然而,这将需要打破所有项目间的引用以支持扁平结构。也许我可以接受你的建议。
            【解决方案9】:

            不知道你为什么要按照你的要求去做。大多数人只是创建一个工作的本地副本,然后在他们想要的任何目录上工作。这是因为 Subversion 的工作方式。它不会锁定源代码。我通过使用 SourceSafe 开始了源代码控制,所以我对您正在经历的事情有一点了解。

            您可能想要的是使用 svn:externals 属性。这里有几个帖子讨论这个问题。这是其中之一:

            How to make SVN only update files but not add new ones

            【讨论】:

            • svn:externals 属性不会创建他正在寻找的中间目录结构。
            最近更新 更多