使用稀疏签出改变存储库目录结构

使用 Git1.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

这不是我想要的。

46163 次浏览

您仍然需要克隆整个存储库,它将包含所有文件。您可以使用 --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 '*'来返回所有内容。

简短的回答是否定的。 Git 将所有文件视为一个单元。

我建议您将存储库分解为逻辑块。一个单独的 perl、图像和文档。如果你还需要保持超级回购风格,你可以创建一个由 子模块回购。

您可以尝试编织-它跟踪远程同时匹配他们的路径。 Https://github.com/evilchelu/braid/wiki

现在不需要深入讨论为什么要这样做,您的问题可以(可能)通过符号链接/快捷方式轻松解决。

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

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

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

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

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

Richq 的答案很接近,但是它漏掉了一个步骤:

Git config core.Sparseccheck out true

这篇博文清楚地概述了所有的步骤:

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

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

这里有一个 bash 脚本来完成这个任务。

这将首先制作一个工作副本的原始回购,然后过滤器分支使用子目录过滤器你得到你想要的。

#!/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就可以了。

似乎您正在尝试做的是重命名目录树,使您的文件最终在不同的地方。在我看来,你要做的是一个反模板的代码/项目管理在两个方面: 模块分类(java 节点下的 java 位,perl 节点下的 perl) ,有一个项目与文件在不同的位置从开发人员可视化它们。由于 git 维护目录内容的散列以查看更改了什么内容,因此这也破坏了 git。

Daemeon Reiydelle