我的Git存储库在根目录下有两个子目录:

/finisht
/static

当这是在SVN中时,/finisht在一个地方签出,而/static在其他地方签出了,如下所示:

svn co svn+ssh://admin@domain.example/home/admin/repos/finisht/static static

有没有办法用Git做到这一点?


当前回答

为了澄清这里的一些好答案,许多答案中概述的步骤假设您在某个地方已经有了远程存储库。

给定:现有的git存储库,例如。git@github.com:some user/fullrepo.git,其中包含一个或多个您希望独立于repo其余部分拉动的目录,例如名为app1和app2的目录

假设您有一个如上所述的git存储库。。。

然后:您可以运行以下步骤,从较大的存储库中仅提取特定目录:

mkdir app1
cd app1
git init
git remote add origin git@github.com:some-user/full-repo.git
git config core.sparsecheckout true
echo "app1/" >> .git/info/sparse-checkout
git pull origin master

我错误地认为必须在原始存储库上设置稀疏签出选项,但事实并非如此:在从远程提取之前,您需要在本地定义所需的目录。远程回购不知道或不关心您只想跟踪回购的一部分。

希望这一澄清对其他人有所帮助。

其他回答

为了澄清这里的一些好答案,许多答案中概述的步骤假设您在某个地方已经有了远程存储库。

给定:现有的git存储库,例如。git@github.com:some user/fullrepo.git,其中包含一个或多个您希望独立于repo其余部分拉动的目录,例如名为app1和app2的目录

假设您有一个如上所述的git存储库。。。

然后:您可以运行以下步骤,从较大的存储库中仅提取特定目录:

mkdir app1
cd app1
git init
git remote add origin git@github.com:some-user/full-repo.git
git config core.sparsecheckout true
echo "app1/" >> .git/info/sparse-checkout
git pull origin master

我错误地认为必须在原始存储库上设置稀疏签出选项,但事实并非如此:在从远程提取之前,您需要在本地定义所需的目录。远程回购不知道或不关心您只想跟踪回购的一部分。

希望这一澄清对其他人有所帮助。

如果您从未计划与从中克隆的存储库交互,则可以执行完整的git克隆并使用

git filter-branch --subdirectory-filter <subdirectory>

这样,至少历史会被保存下来。

编辑:从Git 2.19开始,这终于是可能的,从这个答案中可以看出。

考虑对这个答案投赞成票。

注意:在Git2.19中,只实现了客户端支持,服务器端支持仍然缺失,因此它只在克隆本地存储库时有效。还要注意,大型Git宿主(例如GitHub)实际上并不使用Git服务器,而是使用自己的实现,因此即使Git服务器中显示了支持,也不会自动表示它在Git宿主上运行。(OTOH,因为他们不使用Git服务器,所以在Git服务器出现之前,他们可以在自己的实现中更快地实现它。)


不,这在Git中是不可能的。

在Git中实现这样的东西将是一项巨大的努力,这意味着客户端存储库的完整性将无法再得到保证。如果您感兴趣,请在gitmailinglist上搜索有关“稀疏克隆”和“稀疏获取”的讨论。

一般来说,Git社区的共识是,如果您有几个目录总是独立检出,那么这是两个不同的项目,应该存在于两个不同存储库中。您可以使用Git子模块将它们粘在一起。

下面是我为单个子目录稀疏签出用例编写的shell脚本

co子目录.sh

localRepo=$1
remoteRepo=$2
subDir=$3


# Create local repository for subdirectory checkout, make it hidden to avoid having to drill down to the subfolder
mkdir ./.$localRepo
cd ./.$localRepo
git init
git remote add -f origin $remoteRepo
git config core.sparseCheckout true

# Add the subdirectory of interest to the sparse checkout.
echo $subDir >> .git/info/sparse-checkout

git pull origin master

# Create convenience symlink to the subdirectory of interest
cd ..
ln -s ./.$localRepo/$subDir $localRepo

您正在尝试做的是所谓的稀疏签出,这一功能是在Git1.7.0(2012年2月)中添加的。执行稀疏克隆的步骤如下:

mkdir <repo>
cd <repo>
git init
git remote add -f origin <url>

这将使用远程设备创建一个空的存储库,并获取所有对象,但不会检出它们。然后执行以下操作:

git config core.sparseCheckout true

现在,您需要定义要实际检出的文件/文件夹。这是通过在.git/info/spease checkout中列出它们来完成的,例如:

echo "some/dir/" >> .git/info/sparse-checkout
echo "another/sub/tree" >> .git/info/sparse-checkout

最后但同样重要的是,使用远程状态更新空回购:

git pull origin master

现在,文件系统上的一些/dir和另一个/sub/tree的文件将被“检出”(这些路径仍然存在),而没有其他路径。

您可能想看一下扩展教程,可能应该阅读有关稀疏签出和读取树的官方文档。

作为一项功能:

function git_sparse_clone() (
  rurl="$1" localdir="$2" && shift 2

  mkdir -p "$localdir"
  cd "$localdir"

  git init
  git remote add -f origin "$rurl"

  git config core.sparseCheckout true

  # Loops over remaining args
  for i; do
    echo "$i" >> .git/info/sparse-checkout
  done

  git pull origin master
)

用法:

git_sparse_clone "http://github.com/tj/n" "./local/location" "/bin"

请注意,这仍然会从服务器下载整个存储库–只有签出的大小减小了。目前,仅克隆一个目录是不可能的。但如果您不需要存储库的历史记录,至少可以通过创建浅层克隆来节省带宽。有关如何结合浅层克隆和稀疏检出的信息,请参阅下面的udondan答案。


截至Git 2.25.0(2020年1月),Git中添加了一个实验性稀疏校验命令:

git sparse-checkout init
# same as:
# git config core.sparseCheckout true

git sparse-checkout set "A/B"
# same as:
# echo "A/B" >> .git/info/sparse-checkout

git sparse-checkout list
# same as:
# cat .git/info/sparse-checkout