是否可以在Git中检出存储库的子目录?
想象一下,我正在设置一个新的WordPress安装.我将为我的插件和主题自定义创建两个新目录:
wordpress/wp-content/plugins/myplugins/
wordpress/wp-content/themes/mytheme/
我想通过Git维护这些目录.在Subversion中,我将通过拥有trunk/myplugins/
和trunk/mytheme/
目录并检查子目录来实现这一目标.Git是否有办法使用单个存储库完成相同的任务?
我可能只是在一些Git范例中错过了这条船,因为很长一段时间的SVN用户很少接触Git.
编辑: 存储不同内容的多个分支是处理此问题的有趣方式.
稀疏检出是现在的Git 1.7.
另请参阅问题" 是否可以在不先检出整个存储库的情况下进行稀疏检出?".
请注意,稀疏检出仍然需要您下载整个存储库,即使Git下载的某些文件不会在您的工作树中结束.
在git中没有真正的方法可以做到这一点.如果您不会将同时影响两个树的更改作为单个工作单元进行更改,则没有充分的理由为这两个树使用单个存储库.我以为我会想念这个Subversion功能,但是我发现创建存储库的管理心理开销很小(仅仅是因为存储库存储在工作副本旁边,而不是要求我明确地选择一些位置.工作副本)我习惯于制作许多小型单用途存储库.
但是,如果你坚持(或者真的需要它),你可以在WordPress安装中使用just mytheme
和myplugins
目录以及符号链接创建一个git存储库.
MDCore写道:
提交,例如,mytheme将增加myplugin的修订号
请注意,如果您决定将两个目录放在单个存储库中,这不是git的问题,因为git完全不使用任何形式的单调增加修订号的概念.
将什么东西放在git中的单个存储库中的唯一标准是它是否构成一个单元,即.在您的情况下,是否存在更改,在单独查看每个目录中的编辑时没有意义.如果您需要一次更改两个目录中的文件并且编辑属于一起的更改,则它们应该是一个存储库.如果没有,那么不要把它们放在一起.
Git真的希望你为不同的实体使用单独的存储库.
子模块
子模块没有解决将两个目录保存在一个存储库中的愿望,因为它们实际上会强制为每个目录建立一个单独的存储库,然后使用子模块将它们放在另一个存储库中.更糟糕的是,由于WordPress安装中的目录不是同一目录的直接子目录,并且也是包含许多其他文件的层次结构的一部分,因此使用每个目录存储库作为统一存储库中的子模块将不会带来任何好处,因为统一存储库不会反映任何用例/需求.
关于稀疏检出,我不喜欢的一件事是,如果要检查深度为几个目录的子目录,则目录结构必须包含通向它的所有目录.
我如何解决这个问题是在一个不是我的工作区的地方克隆repo,然后在我的工作区目录中创建一个符号链接到存储库中的子目录.Git工作得非常好,因为像git status这样的东西会显示相对于当前工作目录的更改文件.
实际上,对于Git来说,"狭窄"或"部分"或"稀疏"的结账是当前的重大发展.请注意,您仍将拥有完整的存储库.git
.所以,其他两个帖子对于当前的Git状态是最新的,但看起来我们最终能够进行稀疏检查. 如果您对更多细节感兴趣,请查看邮件列表 - 它们正在快速变化.
git clone --filter
从Git 2.19
此选项实际上将跳过从服务器获取不需要的对象的操作:
git clone --depth 1 --no-checkout --filter=blob:none \ "file://$(pwd)/server_repo" local_repo cd local_repo git checkout master -- mdir/
服务器应配置为:
git config --local uploadpack.allowfilter 1 git config --local uploadpack.allowanysha1inwant 1
从v2.19.0开始,没有服务器支持,但是已经在本地进行了测试。
file://$(path)
需要克服git clone
协议的技巧:如何用相对路径浅克隆本地git存储库?
请记住,这--depth 1
已经暗示了--single-branch
,另请参见:如何在Git中克隆单个分支?
TODO:--filter=blob:none
跳过所有blob,但仍获取所有树对象。但是在正常的仓库中,与文件本身相比,它应该很小,所以已经足够了。在以下位置询问:https: //www.spinics.net/lists/git/msg342006.html开发人员回答说,--filter=tree:0
正在为此做准备。
的格式--filter
记录在上man git-rev-list
。
对Git远程协议进行了扩展以支持此功能。
Git树上的文档:
https://github.com/git/git/blob/v2.19.0/Documentation/technical/partial-clone.txt
https://github.com/git/git/blob/v2.19.0/Documentation/rev-list-options.txt#L720
https://github.com/git/git/blob/v2.19.0/t/t5616-partial-clone.sh
测试一下
#!/usr/bin/env bash set -eu list-objects() ( git rev-list --all --objects echo "master commit SHA: $(git log -1 --format="%H")" echo "mybranch commit SHA: $(git log -1 --format="%H")" git ls-tree master git ls-tree mybranch | grep mybranch git ls-tree master~ | grep root ) # Reproducibility. export GIT_COMMITTER_NAME='a' export GIT_COMMITTER_EMAIL='a' export GIT_AUTHOR_NAME='a' export GIT_AUTHOR_EMAIL='a' export GIT_COMMITTER_DATE='2000-01-01T00:00:00+0000' export GIT_AUTHOR_DATE='2000-01-01T00:00:00+0000' rm -rf server_repo local_repo mkdir server_repo cd server_repo # Create repo. git init --quiet git config --local uploadpack.allowfilter 1 git config --local uploadpack.allowanysha1inwant 1 # First commit. # Directories present in all branches. mkdir d1 d2 printf 'd1/a' > ./d1/a printf 'd1/b' > ./d1/b printf 'd2/a' > ./d2/a printf 'd2/b' > ./d2/b # Present only in root. mkdir 'root' printf 'root' > ./root/root git add . git commit -m 'root' --quiet # Second commit only on master. git rm --quiet -r ./root mkdir 'master' printf 'master' > ./master/master git add . git commit -m 'master commit' --quiet # Second commit only on mybranch. git checkout -b mybranch --quiet master~ git rm --quiet -r ./root mkdir 'mybranch' printf 'mybranch' > ./mybranch/mybranch git add . git commit -m 'mybranch commit' --quiet echo "# List and identify all objects" list-objects echo # Restore master. git checkout --quiet master cd .. # Clone. Don't checkout for now, only .git/ dir. git clone --depth 1 --quiet --no-checkout --filter=blob:none "file://$(pwd)/server_repo" local_repo cd local_repo # List missing objects from master. echo "# Missing objects after --no-checkout" git rev-list --all --quiet --objects --missing=print echo echo "# Git checkout fails without internet" mv ../server_repo ../server_repo.off ! git checkout master echo echo "# Git checkout fetches the missing directory from internet" mv ../server_repo.off ../server_repo git checkout master -- d1/ echo echo "# Missing objects after checking out d1" git rev-list --all --quiet --objects --missing=print
GitHub上游。
Git v2.19中的输出:
# List and identify all objects c6fcdfaf2b1462f809aecdad83a186eeec00f9c1 fc5e97944480982cfc180a6d6634699921ee63ec 7251a83be9a03161acde7b71a8fda9be19f47128 62d67bce3c672fe2b9065f372726a11e57bade7e b64bf435a3e54c5208a1b70b7bcb0fc627463a75 d1 308150e8fddde043f3dbbb8573abb6af1df96e63 d1/a f70a17f51b7b30fec48a32e4f19ac15e261fd1a4 d1/b 84de03c312dc741d0f2a66df7b2f168d823e122a d2 0975df9b39e23c15f63db194df7f45c76528bccb d2/a 41484c13520fcbb6e7243a26fdb1fc9405c08520 d2/b 7d5230379e4652f1b1da7ed1e78e0b8253e03ba3 master 8b25206ff90e9432f6f1a8600f87a7bd695a24af master/master ef29f15c9a7c5417944cc09711b6a9ee51b01d89 19f7a4ca4a038aff89d803f017f76d2b66063043 mybranch 1b671b190e293aa091239b8b5e8c149411d00523 mybranch/mybranch c3760bb1a0ece87cdbaf9a563c77a45e30a4e30e a0234da53ec608b54813b4271fbf00ba5318b99f root 93ca1422a8da0a9effc465eccbcb17e23015542d root/root master commit SHA: fc5e97944480982cfc180a6d6634699921ee63ec mybranch commit SHA: fc5e97944480982cfc180a6d6634699921ee63ec 040000 tree b64bf435a3e54c5208a1b70b7bcb0fc627463a75 d1 040000 tree 84de03c312dc741d0f2a66df7b2f168d823e122a d2 040000 tree 7d5230379e4652f1b1da7ed1e78e0b8253e03ba3 master 040000 tree 19f7a4ca4a038aff89d803f017f76d2b66063043 mybranch 040000 tree a0234da53ec608b54813b4271fbf00ba5318b99f root # Missing objects after --no-checkout ?f70a17f51b7b30fec48a32e4f19ac15e261fd1a4 ?8b25206ff90e9432f6f1a8600f87a7bd695a24af ?41484c13520fcbb6e7243a26fdb1fc9405c08520 ?0975df9b39e23c15f63db194df7f45c76528bccb ?308150e8fddde043f3dbbb8573abb6af1df96e63 # Git checkout fails without internet fatal: '/home/ciro/bak/git/test-git-web-interface/other-test-repos/partial-clone.tmp/server_repo' does not appear to be a git repository fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. # Git checkout fetches the missing directory from internet remote: Enumerating objects: 1, done. remote: Counting objects: 100% (1/1), done. remote: Total 1 (delta 0), reused 0 (delta 0) Receiving objects: 100% (1/1), 45 bytes | 45.00 KiB/s, done. remote: Enumerating objects: 1, done. remote: Counting objects: 100% (1/1), done. remote: Total 1 (delta 0), reused 0 (delta 0) Receiving objects: 100% (1/1), 45 bytes | 45.00 KiB/s, done. # Missing objects after checking out d1 ?8b25206ff90e9432f6f1a8600f87a7bd695a24af ?41484c13520fcbb6e7243a26fdb1fc9405c08520 ?0975df9b39e23c15f63db194df7f45c76528bccb
结论:d1/
缺少来自外部的所有斑点。
请注意,root/root
并且mybranch/mybranch
也丢失了,但是--depth 1
将其从丢失的文件列表中隐藏了。如果删除--depth 1
,则它们将显示在丢失文件的列表中。