171

是否可以在 Git 中签出存储库的子目录?

想象一下,我正在设置一个新的 WordPress 安装。我将为我的插件和主题自定义创建两个新目录:

  • wordpress/wp-content/plugins/myplugins/
  • wordpress/wp-content/themes/mytheme/

我想通过 Git 维护这些目录。在 Subversion 中,我将通过拥有目录和签出子目录来实现这trunk/myplugins/一点trunk/mytheme/。Git 是否有办法使用单个存储库完成相同的任务?

作为一个长期接触 Git 的 SVN 用户,我可能只是错过了一些 Git 范例。

编辑:存储不同内容的 多个分支是一种有趣的处理方式。

4

9 回答 9

127

稀疏检出现在在 Git 1.7中。

另请参阅问题“<a href="https://stackoverflow.com/q/4114887/578288">是否可以在不先检查整个存储库的情况下进行稀疏检查?”。

请注意,稀疏签出仍然需要您下载整个存储库,即使 Git 下载的某些文件最终不会出现在您的工作树中。

于 2010-02-20T20:40:42.140 回答
17

在 git 中没有真正的方法可以做到这一点。而且,如果您不会将同时影响两棵树的更改作为一个工作单元进行,那么就没有充分的理由为两者使用一个存储库。我以为我会错过这个 Subversion 功能,但我发现创建存储库的管理精神开销非常小(仅仅是因为存储库存储在它们的工作副本旁边,而不是要求我明确选择工作副本),我习惯于制作许多小型的单一用途存储库。

但是,如果您坚持(或确实需要),您可以创建一个仅包含mythememyplugins目录的 git 存储库,并在 WordPress 安装中对它们进行符号链接。


MDCore 写道:

提交到例如mytheme将增加myplugin的修订号

请注意,如果您决定将两个目录放在一个存储库中,这对 git 来说不是问题,因为 git 完全消除了任何形式的单调增加修订号的概念。

在 git 中将哪些东西放在一个存储库中的唯一标准是它是否构成一个单元,即。在您的情况下,是否存在单独查看每个目录中的编辑没有意义的更改。如果您有更改需要同时编辑两个目录中的文件并且编辑属于一起,则它们应该是一个存储库。如果没有,那么不要将它们放在一起。

Git 真的很想让你为不同的实体使用不同的存储库。

子模块

子模块并没有解决将两个目录都保存在一个存储库中的愿望,因为它们实际上会强制为每个目录拥有一个单独的存储库,然后使用子模块将它们放在另一个存储库中。更糟糕的是,由于 WordPress 安装中的目录不是同一目录的直接子目录,并且也是具有许多其他文件的层次结构的一部分,因此将每个目录的存储库用作统一存储库中的子模块将没有任何好处,因为统一存储库不会反映任何用例/需求。

于 2008-10-07T20:06:48.607 回答
16

我不喜欢稀疏签出的一件事是,如果您想签出一个深度为几个目录的子目录,您的目录结构必须包含通向它的所有目录。

我如何解决这个问题是在不是我的工作区的地方克隆 repo,然后在我的工作区目录中创建一个符号链接到存储库中的子目录。Git 像这样很好地工作,因为像 git status 这样的东西会显示相对于你当前工作目录的更改文件。

于 2011-03-22T16:33:00.960 回答
13

git clone --filter来自 git 2.19 现在可以在 GitHub 上运行(测试 2020-09-18,git 2.25.1)

此选项是与远程协议的更新一起添加的,它确实可以防止从服务器下载对象。

d1要仅克隆此存储库所需的对象: https ://github.com/cirosantilli/test-git-partial-clone我可以这样做:

git clone \
  --depth 1 \
  --filter=blob:none \
  --no-checkout \
  https://github.com/cirosantilli/test-git-partial-clone \
;
cd test-git-partial-clone
git checkout master -- d1

我在以下位置更详细地介绍了这一点:Git:如何仅克隆 Git 存储库的子目录?

于 2018-09-11T07:19:03.610 回答
9

实际上,“窄”或“部分”或“稀疏”检出正在 Git 的当前大量​​开发中。请注意,您仍将拥有完整的存储库.git。因此,其他两篇文章是当前 Git 状态的最新文章,但看起来我们最终将能够进行稀疏检查。 如果您对更多详细信息感兴趣,请查看邮件列表——它们正在迅速变化。

于 2008-10-08T20:17:41.377 回答
1

您不能签出存储库的单个目录,因为整个存储库由项目根目录中的单个 .git 文件夹处理,而不是 subversion 的无数 .svn 目录。

在单个存储库中处理插件的问题是提交到例如mytheme会增加myplugin的修订号,因此即使在颠覆中,最好使用单独的存储库。

子项目的颠覆范式是svn:externals,它在某种程度上转换为git 中的子模块(但不完全是在你之前使用过 svn:externals 的情况下。)

于 2008-10-07T20:20:30.703 回答
1

正如您的编辑指出的那样,您可以使用两个单独的分支来存储两个单独的目录。这确实使它们都在同一个存储库中,但是您仍然不能跨两个目录树进行提交。如果您有一个更改需要更改另一个,则必须将它们作为两个单独的提交进行,并且您打开了两个目录的一对签出可能不同步的可能性。

如果您想将这对目录视为一个单元,您可以使用 'wordpress/wp-content' 作为 repo 的根目录,并在顶层使用 .gitignore 文件来忽略除两个感兴趣的子目录之外的所有内容。这可能是目前最合理的解决方案。

据称,稀疏结账已经出现了两年,但在 git 开发 repo 中仍然没有任何迹象,也没有任何迹象表明必要的更改将会到达那里。我不会指望他们。

于 2010-01-16T03:13:16.410 回答
0

这里有灵感。只需使用shell regexor git regex

git checkout commit_id */*.bat  # *.bat in 1-depth subdir exclude current dir, shell regex  
git checkout commit_id '*.bat'  # *.bat in all subdir include current dir, git regex

使用引号转义 shell 正则表达式解释并将通配符传递给 git。

第一个不是递归的,只有 1-depth 中的文件subdir。但第二个是递归的。

至于您的情况,以下可能就足够了。

git checkout master */*/wp-content/*/*
git checkout master '*/wp-content/*'

只需根据需要修改线路。

于 2019-09-16T14:51:49.477 回答
0

您只能将未提交的更改还原到特定文件或目录:

git checkout [some_dir|file.txt]
于 2019-12-28T17:18:35.917 回答