3

我对使用 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 文件中,但如果项目是,比如说,一个网站 - 这可能意味着数百个文件会在我的存储库根目录中混乱。

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

编辑:在谷歌上搜索了一段时间后,我发现了这个类似的问题,但它只涉及 PHP 项目。虽然自动加载器可能允许您在 PHP 环境中屏蔽底层文件系统,但您将如何将类似的方法应用于 C++ 项目?还是 Python 项目?还是 Java 项目?

当我今天更多地考虑这个项目时,我想到了一些其他的想法,这可能需要一个新的思路方向。首先是非常深的库嵌套问题。如果项目 A 依赖于项目 B,而项目 B 又依赖于项目 C,而项目 C 又依赖于项目 D,那么您将具有如下目录结构:

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

4 回答 4

3

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

有专门的工具专注于各种堆栈中的依赖管理 -

等等

这些工具负责冗余管理。

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

  1. 使用子模块跨项目共享的 Powershell 构建脚本。Buildscript 存储库包含部署我们的任何 .net 应用程序和相应的包装器 powershell 脚本所需的所有第 3 方可执行文件,以及一些用于加载约定、配置等的脚本。
  2. Nuget 服务器(通过 Teamcity)托管用于跨项目共享的通用二进制文件的 nuget 包。Nuget Package restore 是一项允许在构建过程中获取包的功能。
于 2013-03-08T15:47:35.750 回答
2

虽然统一工作流程很好,但你必须尊重你试图驯服的野兽。对于不同的项目,您应该有不同的目录结构。从 3D 动画项目到 PHP 项目再到 C++ 项目以及介于两者之间的任何地方,我发现从长远来看,挤压它们以符合相同的工作流程只会增加工作量和头痛。大多数 IDE 都有一个开箱即用的良好“新项目”结构,它是其他开发人员立即知道和理解的结构。

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

于 2013-03-10T19:59:34.903 回答
0

您问了一个一般性问题,但也专门询问了几个实例。我将倾向于更一般。简短的回答:这是一个构建系统问题,而不是版本控制系统问题。

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

据我所知,这在 C++ 中并不容易。CMake似乎支持构建外部项目。我最近才开始玩这个,看看有什么可能,所以我不想误导你说“它很容易做到”,但按理说它可以做到,问题是只有你必须投入多少工作。因此,无论您是否调用文件夹/libs,都应该使构建将依赖项视为可传递的(然后祝您好运)。

于 2013-03-08T15:48:06.373 回答
0

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

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

对于 unix 之类的操作系统(linux/bsd/solaris/etc.)让用户通过他们的包管理器单独安装它们,如果你发布你的软件,包管理器会知道你的依赖项并在安装你的应用程序之前安装必要的依赖项,所以没有手册行动是必要的。

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

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

于 2013-03-13T07:27:27.920 回答