加速几十倍 git clone 速度的 --depth 1,它的后遗症怎么解决?
我们经常会用 git clone 来下载项目,但遇到大项目的时候,clone 就很慢,比如 react:要等很久。当然,还有更慢的项目。这类项目可以通过 --depth 1 来加速:gitclone--depth1https://github.com/facebook/react这速度快了有几十倍吧!越大的项目加速效果越明显。原因就是下载的内容更少了。那这样代码还是全的么?当然,代码是最新...
我们经常会用 git clone 来下载项目,但遇到大项目的时候,clone 就很慢,比如 react:
要等很久。
当然,还有更慢的项目。
这类项目可以通过 --depth 1 来加速:
git clone --depth 1 https://github.com/facebook/react
这速度快了有几十倍吧!越大的项目加速效果越明显。
原因就是下载的内容更少了。
那这样代码还是全的么?
当然,代码是最新的完整代码。
那为啥下载的内容少了呢?少了哪一部分呢?
很容易想到,就是历史 commit。
这里要涉及一点 git 的实现原理了:
git 中文件是通过 object 存储不同数据的:
glob 对象存储文件内容
tree 对象存储文件路径
commit 对象存储 commit 信息,关联多个 tree
然后 HEAD、branch、tag 等是指向具体 commit 的指针,可以在 .git/refs 下看到
所以说,每个版本的代码都是从 commit 对象作为入口关联起来的。
指定了 depth 1 的时候,就是只保留了最新的入口,历史入口就没下载了。
这样自然快很多,代码也是完整的。
但这么好的事情也是有代价的,它有一些后遗症。
最容易想到的就是切不到历史 commit。
正常下载的项目的 git log 是这样的:
你可以 git reset 切到任意 commit:
比如:
git reset --hard 4dda96a40
但是 depth 1 下载的项目就不可以,因为本地没有这个 commit 可以切:
你再 git pull 的时候,也下载不了历史 commit 的代码:
就很尴尬。
git 团队自然也想到了这点,于是提供了一个 unshallow 的选项:
加上 --unshallow 再 pull 的时候也会同时拉取历史 commit。(默认没开这个是为了性能)
你完全可以用 depth 1 下载的项目来开发,正常的 pull、push 都没问题,因为都是基于最新 commit 创建的更新的 commit。
当你有一天需要历史 commit 的时候再 pull --unshallow 也不迟。
这样下载项目快,后面也能恢复成完整版代码库,何乐而不为呢?
但 depth 1 还有一个问题,就是切换不了其他 branch。
正常项目是这样的:
git branch -r 可以查看远程分支:
git branch -a 可以查看本地和远程的分支:
但你 depth 1 下载的项目是没有的:
只有一个 main。
有的同学说,fetch 一下就好了呀。
太天真了。
git fetch 的作用是把远程分支的新 commit 下载到本地。
默认下载所有远程分支的新 commit。
也可以单独指定某个分支:
但你会发现 git fetch 了这个分支的代码,也不能看到和切换到它:
这是因为有个 remote.origin.fetch 的配置。
正常下载的项目的 fetch 配置是这样的:
把 remote 的所有分支下载到本地的所有分支。
而 depth 1 下载的项目的 fetch 配置是这样的:
fetch 只会下载 main 分支。
就算你手动 fetch 了其他分支的代码也不会处理。
所以我们可以改下这个配置,我们先指定一个 0.3-stable 分支看看:
git config remote.origin.fetch "+refs/heads/0.3-stable:refs/remotes/origin/0.3-stable"
可以看到 pull 的时候就拉取到新分支了,而且 branch -r 可以看到这个分支了。
这里 pull 或者 fetch 都行。pull 就相当于 git fetch + git merge,把代码下载下来,然后 merge 到本地。fetch 是 pull 的第一步:
接下来再改为 * 试试:
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
再执行 git fetch 或者 git pull,就会拉取全部分支的 commit:
这时候就可以切换到这些分支了:
这样就解决了 --depth 1 的第二个问题。
总结
当 git clone 下载大项目的时候,加个 --depth 1 可以提速几十倍。
下载下来的项目也可以正常的 pull 和 push。
这是因为 git 是通过 commit、tree、blob 的对象存储的,每个 commit 是关联这些对象的入口。
depth 1 只会下载最后一个 commit 关联的 object,下载内容更少,所以速度快很多。
但这种方式有两个问题:
切换不到历史 commit
切换不到别的分支
没有历史 commit 可以通过 git pull --unshallow 解决。
切不到别的分支是因为 fetch 配置导致的,配置成 +refs/heads/*:refs/remotes/origin/* 也就可以了,也就是拉取远程所有分支代码到本地。
这样再 fetch 和 pull 就会拉取所有分支的新 commit,也可以正常的切分支。
--depth 1 在下载大项目的时候,或者 build 时下载代码的时候,都很有意义。它提高下载速度导致的俩后遗症也都可以解决。
- END -
关于奇舞团
奇舞团是 360 集团最大的大前端团队,代表集团参与 W3C 和 ECMA 会员(TC39)工作。奇舞团非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。
更多推荐
所有评论(0)