70

使用 Git 1.7.0 中新的稀疏签出功能,是否可以像在 SVN 中那样获取子目录的内容?我找到了这个例子,但它保留了完整的目录结构。想象一下,我只想要“perl”目录的内容,而没有名为“perl”的实际目录。

- 编辑 -

例子:

我的 git 存储库包含以下路径

repo/.git/
repo/perl/
repo/perl/script1.pl
repo/perl/script2.pl
repo/images/
repo/images/image1.jpg
repo/images/image2.jpg
repo/doc/
repo/doc/readme.txt
repo/doc/help.txt

我想要的是能够从上面的存储库中生成这个布局:

repo/.git/
repo/script1.pl
repo/script2.pl

但是,使用当前的稀疏结帐功能,似乎只能获得

repo/.git/
repo/perl/script1.pl
repo/perl/script2.pl

这不是我想要的。

4

7 回答 7

27

您仍然需要克隆整个存储库,其中将包含所有文件。您可以使用该--depth标志仅检索有限数量的历史记录。

克隆存储库后,读取树技巧会将存储库的“视图”限制为仅文件中的那些文件或目录.git/info/sparse-checkout

我写了一个快速脚本来帮助管理稀疏性,因为目前它有点不友好:

#!/bin/sh
echo > .git/info/sparse-checkout
for i in "$@"
do
    echo "$i" >> .git/info/sparse-checkout
done
git read-tree -m -u HEAD

如果将此脚本保存git-sparse.sh到调用报告的路径中git --exec-path,则可以运行git sparse foo/ bar/以仅“签出” foo 和 bar 目录,或者git sparse '*'重新获取所有内容。

于 2010-02-26T10:23:29.820 回答
16

最简洁的答案是不。Git 将所有文件视为一个单元。

我建议您将存储库分解为逻辑块。perl、图像和文档的单独一个。如果您还需要维护 uber repo 样式,您可以创建一个由 Submodules 组成的repo

于 2010-03-16T22:58:27.137 回答
6

Richq 的答案很接近,但它错过了一步。您需要显式启用稀疏结帐:

git config core.sparsecheckout true

这篇博文清楚地列出了所有步骤:

http://blog.quilitz.de/2010/03/checkout-sub-directories-in-git-sparse-checkouts/comment-page-1/#comment-3146

于 2012-01-07T23:00:05.020 回答
5

现在,无需详细说明您为什么要这样做,您的问题可以(可能)通过符号链接/快捷方式轻松解决。

回答这个问题 - 不,并且有一个有意义的理由。即使使用“稀疏结帐”,也会下载回购的整个历史记录。澄清为什么这是必要的 - 否则跟踪重命名的文件将是一个痛苦的......脖子。想象一下,您将文件移动/repo_root/asd/file1.cpp/repo_root/fgh/file1.cpp- 现在如果您只下载了/repo_root/fghdelta,您将不会知道 file1.cpp。所以这意味着你必须下载所有的增量。但是你有一个完整的存储库;不仅仅是文件夹的一部分,因此/rero_root/fgh文件夹本身不是回购。这在您结帐时可能听起来并不重要,但是当您提交时,git 可能没有足够的知识来正常工作。

解决方法:如果你真的想要,你可以创建一个以这种方式调用 git-checkout 的脚本(对于 sh shell,windows 的批处理应该不难产生):

!/bin/sh
curDir=`pwd`
cd $2
git-checkout $1
cp -R $3/* $4
cd $curDir

这里第一个参数是结帐的分支,第二个 - 当前存在 repo 的文件夹,第三个 - 你想要真正使用的子目录,第四个 - 你想要它复制到的位置。

警告:我的shell技能几乎不存在,所以在测试后使用它。重新创建这个脚本的反向应该不难,它复制回来的东西,以便它可以提交到 repo。

于 2011-08-07T01:10:42.450 回答
3

git filter-branch --subdirectory-filter是您需要的,请参阅将子目录分离(移动)到单独的 Git 存储库中。

这是一个小 bash 脚本来做到这一点。

这将首先制作原始 repo 的工作副本,然后使用子目录过滤器过滤分支以获得所需的内容。

#!/bin/bash
#
# git-subdir.sh
#
git clone --no-hardlinks $1 $2

cd $2

git filter-branch --subdirectory-filter $2 --prune-empty --tag-name-filter cat HEAD -- --all

git reset --hard

git remote rm origin

refbak=$(git for-each-ref --format="%(refname)" refs/original/)

if [ -n "$refbak" ];then
    echo -n $refbak | xargs -n 1 git update-ref -d
fi

git reflog expire --expire=now --all

git repack -ad

git gc --aggressive --prune=now

用于问题中的示例,git-subdir.sh repo perl将起作用。

于 2012-03-01T05:09:49.203 回答
2

您可以尝试编织 - 它在将遥控器与路径匹配的同时跟踪遥控器。 https://github.com/evilchelu/braid/wiki

于 2010-12-30T23:04:56.367 回答
0

看来您要做的是重命名目录树,以便您的文件最终位于不同的位置。在我看来,您要求做的是代码/项目管理的反模板,主要有两个方面:模块分类(java 节点下的 java 位,perl 节点下的 perl),以及在不同位置有一个包含文件的项目开发人员从哪里可视化它们。由于 git 维护目录内容的哈希值以查看更改的内容,因此这也破坏了 git。

戴蒙·赖德尔

于 2015-03-05T19:29:05.833 回答