git中的子模块库可以最大限度地减少冗余

时间:2013-03-06 04:48:17

标签: git directory project-management organization

我使用git非常新手,以前没有真正尝试过组织"我所做的任何项目。我刚刚购买了一个供个人使用的开发服务器,我想开始组织我的所有项目并使用版本控制。

我花了8个小时研究了在项目中组织文件的不同推荐方法,我意识到这是一个非常主观的问题。但是我已经开发了一个系统,我认为这个系统可以解决任何原因,对于如何使用目录结构完成某个任务,我有一个非常客观的问题。

目前,我正在寻找类似于以下内容的结构:

src/ - All deliverables in an uncompiled form (PHP files, c source files, etc)
data/ - Crucial but unrelated data (SQL databases, etc.)
lib/ - Dependencies -- THIS IS WHERE MY QUESTION LIES
docs/ - Documentation
build/ - Scripts to aide in the build process
test/ - Unit tests
res/ - Not version controlled. Contains PSD files and non-diff-able stuff
.gitignore
README
output.zip - Ready-to-install finished product (just unzip and go)

正如我所提到的 - 我的真正问题围绕着这个lib/目录。这需要包含我的项目需要运行的所有文件和程序,但这些文件和程序不在我的项目范围内,我不会编辑。我需要此文件夹的一些功能:

  • 由于我的最终产品需要运行,因此必须将它们包含在output.zip
  • 我希望此文件夹受版本控制,以便下载我的git存储库的任何人都可以访问所有依赖项
  • 如果多个项目具有相同的依赖关系,我不希望在我的服务器上有18个相同文件的冗余副本
  • 我希望能够从我的其他项目中提取这些依赖项(一个项目应该可以作为单独项目的库)

我可以通过使用虚拟目录(符号链接)来避免同一文件的18个冗余副本,但是根据我的理解,git会将此符号链接原样复制到存储库中而不复制文件。因此,如果其他人提取了我的存储库,他们会有一个悬空指针而没有库。

起初看起来我可以使用git-submodule做我想做的事情。但是根据我的理解,这将获取另一个存储库的全部内容并将其视为子目录。因此,如果我包括"依赖A"我的库文件夹看起来像:

/lib/A/src/
/lib/A/data/
...
/lib/A/test/
.gitignore
README
output.zip

在脚本(PHP,Perl等)的情况下,我可能使用require('lib/A/src/dependency.php')加载依赖项,但在DLL或二进制文件的情况下,我没有简单的方法来读取输出来自output.zip的文件。我可以将完成的项目直接存储在根级别而不是包含在一个漂亮的zip文件中,但如果项目是一个网站 - 这可能意味着数百个文件混乱了我的存储库根目录。

如何将另一个存储库作为我自己的库包含在内,轻松引用我自己项目中的库文件,将库有意义地复制到提取存储库的任何人,并防止我的开发服务器上的相同文件的冗余副本?

编辑:在Google上搜索了一段时间后,我找到了this similar issue,但它只针对PHP项目。虽然自动加载器可能允许您在PHP环境中屏蔽底层文件系统,但您如何对C ++项目应用类似的方法?还是一个Python项目?还是一个Java项目?

当我今天更多地考虑这个项目时,我想到了一些其他的想法,这可能需要一个新的思路。首先是非常深的图书馆巢穴的问题。如果项目A依赖于项目B,项目B依赖于依赖于项目D的项目C,那么你将拥有如下目录结构:

A/lib/
A/lib/B/
A/lib/B/lib/
A/lib/B/lib/C/
A/lib/B/lib/C/lib/
A/lib/B/lib/C/lib/D/

显然,这不仅会令人烦恼,而且会以自己的方式多余。

在执行git存储库时,普通人如何处理依赖关系?

4 个答案:

答案 0 :(得分:3)

在我所参与的项目中,子模块仅适用于涉及依赖关系管理的某些情况,在其他情况下,这是由其他框架补充的。大多数情况下,我更喜欢在需要完整存储库时使用子模块,例如我有一个可以跨项目共享的公共构建脚本。

有各种特定工具专注于各种堆栈中的依赖关系管理 -

这些工具负责冗余管理。

目前,我在一个.net项目中,我们有这个设置 -

  1. 使用子模块跨项目共享的Powershell构建脚本。 Buildscript存储库包含部署任何.net应用程序和相应的包装程序PowerShell脚本所需的所有第三方可执行文件,以及一些用于加载约定,配置等的脚本。
  2. Nuget服务器(通过Teamcity)托管nuget包,用于跨项目共享的公共二进制文件。 Nuget包还原是一种允许在程序包中提取包的功能。

答案 1 :(得分:2)

虽然统一工作流程很好,但你必须尊重你想要驯服的野兽。您应该为不同的项目使用不同的目录结构。从3D动画项目到PHP项目再到C ++项目以及中间的任何地方,我发现挤压它们以符合相同的工作流程只会增加长期工作和头痛。大多数IDE都有一个开箱即用的好“新项目”结构,而且是其他开发人员可以立即了解和理解的结构。

关于依赖问题,尝试实现超级项目方法: http://git-scm.com/book/en/Git-Tools-Submodules

答案 2 :(得分:0)

您已经提出了一般性问题,但也特别询问了一些情况。我会倾向于更加普遍。简短的回答:这是一个构建系统问题,而不是版本控制系统问题。

对于Java,您可以使用一些不同的依赖关系管理/解析工具。构建系统应该了解如何在构建时获取这些依赖项并使它们可用。但是,它们是瞬态的 - 您不会将它们检入版本控制。此外,Maven - 例如 - 使用一个/target文件夹,它们都包含你的输出(例如output.zip - 我也推荐它,因为它使清理输出更容易。如果你有多个输出文件怎么办?关于变体?等)以及其他项目,如静态分析输出 - 它还使用外部目录来本地缓存依赖关系,但这可能是短暂的,它不会关心。底线:它不会持久存储在版本控制中。

据我所知,这在C ++中并不那么容易。 CMake seems to support建立外部项目。我最近才开始玩这个,看看有什么可能,所以我不想误导你说“它可以很容易地完成”,但是有理由认为它可以做到,问题是只需要投入多少工作。因此,无论您是否调用文件夹/libs,您都应该将构建处理依赖项视为传递(然后通过传递依赖项获得好运)。

答案 3 :(得分:0)

不要嵌入库,这是一场安全噩梦! 当您在应用程序中嵌入一些图像格式库(如libpng,libjpeg或libtiff)时,因为您想要使用它的图像格式,您可以将应用程序打开到这些库可能包含的任何安全漏洞,并且用户无法轻易知道他们需要更新您的程序以解决安全问题。当您将依赖项留在应用程序范围之外时,程序包管理器会知道该库,并且可以在暴露安全漏洞时采取措施。

将您依赖的库留在项目范围之外。如果您亲自开发了在多个项目中使用的库,请将其放在自己的存储库中并单独发布它。

对于像操作系统(linux / bsd / solaris /等)这样的unix,用户可以通过他们的软件包管理器单独安装它们,如果你发布软件,软件包管理器会在安装你的应用程序之前知道你的依赖关系并安装必要的依赖项。所以不需要手动操作。

对于Windows,使用单独的捆绑过程将您依赖的库捆绑到便捷安装程序中,该安装程序将库安装到共享系统目录,而不是程序目录。

顺便说一句,没有技术手段可以在没有大量重复的情况下做你想做的事情。