Git 中检出(Checkout)子目录?

是否可以在 Git 中检出代码仓库的子目录?

假设我正在安装一个新的 WordPress 安装程序。我将为我的插件和主题定制创建两个新目录:

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

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

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

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

156470 次浏览

在 Git 中没有真正的方法可以做到这一点。如果您不能作为一个单独的工作单元对两个树进行同时影响的更改,那么就没有理由对两个树使用单独的存储库。我原以为我会怀念 Subversion 的这个特性,但是我发现创建存储库的管理思维开销非常小(仅仅是因为存储库存储在工作副本旁边,而不是要求我明确地选择工作副本之外的某个地方) ,所以我已经习惯了只创建大量的小型单用途存储库。

如果你坚持(或者真的需要它) ,你可以创建一个只有 mythememyplugins目录的 git 仓库,并在 WordPress 安装中对这些目录进行符号链接。


MDCore 写道:

提交,例如,我的主题将增加 我的插件的修订号

请注意,如果您确实决定将两个目录放在一个存储库中,那么这与 git 无关,因为 git 完全摒弃了单调增加任何表单的修订数量的概念。

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

Git 真的希望您为单独的实体使用单独的存储库。

子模组

子模块并不满足将两个目录保存在一个存储库中的需求,因为它们实际上将 执行为每个目录提供一个单独的存储库,然后使用子模块将这些目录放在 另一个存储库中。更糟糕的是,由于 WordPress 安装中的目录不是同一目录的直接子目录,而且也是包含许多其他文件的层次结构的一部分,在统一存储库中使用每个目录存储库作为子模块将不会带来任何好处,因为统一存储库不会反映任何用例/需求。

您不能签出存储库的单个目录,因为整个存储库由单个。Git 文件夹中的项目根,而不是颠覆的无数。Svn 目录。

在单个存储库中使用插件的问题在于,提交,例如,我的主题将增加 我的插件的修订号,所以即使在 subversion 中也最好使用单独的存储库。

子项目的颠覆范例是 Svn: 外部,它在 git 中可以转换为 子模组(但是如果您以前使用过 svn: foreign,则不完全是这样)

实际上,“狭窄的”、“部分的”或“稀疏的”签出目前正处于 Git 的大规模开发阶段。注意,在 .git下仍然有完整的存储库。因此,其他两个帖子是当前的 Git 状态,但它的 看起来像我们将能够做稀疏签出最终。如果您对更多细节感兴趣,请参阅 看看邮件列表——它们正在迅速变化。

正如您的编辑所指出的,您可以使用两个独立的分支来存储两个独立的目录。这确实使它们保持在同一个存储库中,但是您仍然不能同时提交这两个目录树。如果一个目录中有一个更改需要另一个更改,则必须作为两个单独的提交执行这些更改,并且可能导致两个目录的一对签出不同步。

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

稀疏结帐据说已经进行了两年了,但是在 git 开发报告中仍然没有任何迹象,也没有任何迹象表明必要的改变将会到来。我可不指望他们。

稀疏校验是 现在在 Git 1.7中

还可以看到问题“ 有没有可能在不首先检出整个存储库的情况下进行稀疏检出?”。

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

我不喜欢稀疏签出的一点是,如果你想签出一个只有几个目录深度的子目录,你的目录结构必须包含所有指向它的目录。

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

来自 git 2.19的 git clone --filter现在可以在 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 存储库的子目录?上更详细地讨论了这个问题

这里有一个灵感。只要利用 shell regexgit 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深度的 subdir文件,而第二种是递归的。

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

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

按要求黑进线路就行了。

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

git checkout [some_dir|file.txt]