【问题标题】:Decoupling a Visual Studio solution into multiple (interdependent) git repositories将 Visual Studio 解决方案解耦为多个(相互依赖的)git 存储库
【发布时间】:2017-10-22 17:22:17
【问题描述】:

我正在开发一款游戏及其引擎,并且一直在同时开发它们,因此有一个解决方案文件引用了以下(简化)目录结构中的所有项目:

Root
├───Engine
│   ├───Library1
│   ├───Library2
│   └───Library3
├───Game
│   ├───Game
│   ├───Tool1
│   └───Tool2
└───GlobalSolution.sln

构建过程编译所有引擎库并将它们链接到一个静态库,而游戏是一个可执行文件,它与生成的静态库链接,类似于某些工具。

不幸的是,我将所有内容都放在同一个 git 存储库中,而我希望为引擎和当前游戏分别拥有一个存储库,因为引擎本身并不是很有用(尽管它可以自行编译),但我可能会想要创建另一个我应该能够在其自己的存储库中托管的游戏。

我能想到的唯一结构如下:

Root
├───Engine
│   ├───Library1
│   ├───Library2
│   ├───Library3
│   └───EngineSpecificSolution.sln
├───GameA
│   ├───GameASpecifics
│   ├───ToolA1
│   ├───ToolA2
│   └───GameASpecificSolution.sln
└───GameB
    ├───GameBSpecifics
    ├───ToolB1
    └───GameBSpecificSolution.sln

在这种情况下,我只需要通过将$(SolutionDir)\..\Engine\Build\ 添加到游戏解决方案的库路径来引用引擎库。不幸的是,我失去了在一个 VS 窗口中拥有所有东西(引擎和游戏)的便利性,并且需要在单独的窗口中编码,不是吗?当然,每次我对引擎进行更改时,我都必须手动编译游戏解决方案,而不是让 VS 一次性处理所有项目。

对于如何将项目正确地解耦到多个存储库并尽可能方便地使用这些存储库,有什么建议吗?

【问题讨论】:

    标签: git visual-studio projects-and-solutions


    【解决方案1】:

    这就是 git submodules 的创建目的。

    许多人觉得学习 git 子模块的工作原理并不容易,所以一开始可能会有些痛苦,但一旦你掌握了它,它是一个非常有用的工具。

    我将展示一种方法,不会详细介绍 git-submodule,但请不要犹豫,搜索 git-submodule 问题,提出新问题,如果您需要澄清,请在 cmets 中联系我在某些点上。

    首先,您在特定的 git 存储库中创建一个包含 Engine 项目的解决方案(.git 目录只是为了向您展示什么是 git 存储库,什么不是):

    Root
    ├───Engine
        ├───.git/
        ├───Library1
        ├───Library2
        ├───Library3
        └───EngineSpecificSolution.sln
    

    使用 git:

    $ mkdir Engine && cd Engine
    $ git init
    ** Create the Engine solution **
    $ git commit -a -m "First commit for Engine"
    $ git remote add origin https://github.com/user/engine.git
    $ git push -u origin master
    

    然后您创建游戏目录,并将 Engine 存储库添加为子模块:

    Root
    ├───Engine
    │   ├───.git/
    │   [...]
    ├───GameA
    │   ├───.git/
    │   ├───Engine
    │   │   ├───.git/
    │   │   ├───Library1
    │   │   ├───Library2
    │   │   ├───Library3
    │   │   └───EngineSpecificSolution.sln
    │   ├───GameASpecifics
    │   ├───ToolA1
    │   ├───ToolA2
    │   └───GameASpecificSolution.sln
    └───GameB
        ├───.git/
        ├───Engine
        │   ├───.git/
        │   ├───Library1
        │   ├───Library2
        │   ├───Library3
        │   └───EngineSpecificSolution.sln
        ├───GameBSpecifics
        ├───ToolB1
        └───GameBSpecificSolution.sln
    

    使用 git 为 GameA 创建解决方案:

    $ mkdir GameA && cd GameA 
    $ git init
    
    # The following command creates a link to the Engine submodule
    $ git submodule add https://github.com/user/engine.git Engine
    
    # The following command will clone the submodule's repository in place of Engine directory
    $ git submodule update
    
    ** Create the GameA solution and add Engine projects to solution **
    $ git commit -a -m "First commit for GameA"
    $ git remote add origin https://github.com/user/gamea.git
    $ git push -u origin master
    

    您现在拥有的 GameA 包含除引擎代码之外的所有内容,并且在特定提交时引用了引擎存储库。 当您仅对 GameA 进行更改时,您只需在 GameA 中创建一个提交。当您在 GameA 和 Engine 中进行更改时,您需要先在 Engine 中创建提交,然后在 GameA 中创建。 GameA 中的提交将包括对 Engine 的引用的更改,因为引用的提交将已更改。

    当您对引擎进行更改时,您将能够在Root/EngineRoot/GameA/EngineRoot/GameB/Engine 中进行操作,并使用git pushgit push 同步您的更改。

    【讨论】:

    • 这个我没用过,不过今晚晚些时候我会试试,报告我是否成功。如果我在设置完所有内容后从 GitHub 拉取 GameA 存储库,它会自动拉取 Engine 吗?否则,从您的描述来看,这看起来相当不错。
    • 我建议你不要使用子模块,而是更喜欢构建和发布其他项目使用的 nuget 包。
    • 在阅读了一些关于此的内容后,我注意到这对第三方依赖项很好,但对自己的项目却不是。假设我对引擎进行了更改,那么我需要手动将游戏存储库中的引用更新为引擎的最新提交,这有点不方便。在我的情况下,与第 3 方存储库相比,必须更频繁地更新引擎时,分离游戏和引擎文件夹似乎略胜一筹。
    • 克隆 GameA后,需要运行git submodule update。在 GameA 中拉取新更改后,如果对 Engine 的引用发生了更改,则需要运行 git submodule update
    • 如果您永远不需要在游戏和引擎中进行更改,那么正如@Philippe 建议的那样,NuGet 包应该可以工作。但是仅仅因为一开始有点难而远离 git-submodules 并不是一个公平的论点,而且学习总是很好:)
    猜你喜欢
    • 2017-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多