Git Bundle
今天我们来认识一下 git bundle
这个命令。
¶作用
先来简单了解一下这个命令是干嘛的,在官方文档中对这个命令名称的描述翻译过来为:
git-bundle:通过归档移动对象和引用
听起来有点抽象,那我们就不用纠结官方对这个命令的描述了,通俗点讲就是:
用于将本地数据或分支打包到一个文件中,然后共享给别人。
¶使用场景
那么有哪些使用场景呢,比如:
- 在网络不通畅时(网络断了或无法直连公司内网),你希望将你的提交通过U盘或邮件等方式传给你项目的协作开发者们。
- 又或者你现在没有共享服务器的权限,你又希望通过邮件将更新发送给别人,却不希望通过
git format-patch
的方式传输 30 个提交。
像最近由于疫情原因,时不时就需要在家办公,而又不方便直连公司内网拉取代码,直接将整个项目打包成zip
又显得笨重还不灵活,一个人开发还好,多个人协作时就不能方便的记录互相之间的修改了。有了 git bundle
,我们就可以变得灵活方便了,下面就来看看怎么玩~
¶命令概要
git bundle create <file> <git-rev-list-args> |
这是命令支持的基本操作,下面我们一个个来看。
¶创建 - Create
这个操作可以将整个分支或指定区间内的提交打包成文件。
file:指生成的文件名;
git-rev-list-args:用于指定打包的引用或提交的区间;
¶整个分支
$ git bundle create repo_test.bundle master |
该命令会生成 repo_test.bundle
文件,该文件中包含了生成 master
分支所需要的所有数据。
¶指定区间
$ git bundle create repo_test.bundle HEAD dev_v1.0.0 ^master |
该命令只打包在 dev_v1.0.0
分支而不在 master
分支的 commits
。
也可以像这样:$ git bundle create repo_test.bundle HEAD HEAD~2..HEAD
该命令会将 HEAD~2 (不含) 与 HEAD(含) 之间的提交节点生成文件。
¶取用 - pull/clone/fetch
通过 git bundle create
命令创建的 bundle
文件我们可以通过 pull/clone
等方式去拉取。
想一下,在正常修改完代码 提交 后,我们是通过 git push
推送到远端仓库,而现在我们因为网络原因而无法直连仓库,所以其实我们可以把这个 bundle
文件当做一个「离线可移动的中转仓库」, git bundle
在这种情况下就相当于 git push
操作,而推送的目标就是生成的这个 bundle
文件,然后将文件发给你的项目协作者,对方通过 git pull repo_test.bundle
来获取你的更新。
¶clone
通过 clone 命令,可以从 bundle 文件生成一个 git 库。
来看看示例,命令如下:$ git clone repo_test.bundle test
Cloning into 'bundle'...
Receiving objects: 100% (6/6), done.
warning: remote HEAD refers to nonexistent ref, unable to checkout.
上述命令会从 repo_test.bundle
文件中生成一个 git
仓库,同时解压出的文件会存储于名为 test
的文件夹下。
但上述操作有个 warning
,表示 解压失败,因为我们在 git bundle create
打包时没有指定 HEAD
引用,解压出来后不知道该检出(checkout)到哪个分支。可以通过以下两种方式解决:
¶第一种:在打包时添加 HEAD 选项:
$ git bundle create repo_test.bundle HEAD master |
再次执行 clone
操作就可以成功解压,这样解压后,会在本地仓库自动创建一个 master
分支。
¶第二种:在 clone 时添加 -b 选项:
$ git clone -b master repo_test.bundle dev |
注意:此处 -b 新建的分支名,必须与生成 bundle 文件时的分支名一致。
¶pull
不只是 clone
,我们也可以通过 pull/fetch
来操作。
通过 pull 或 fetch 可以从文件中拉取相应的数据,这时候 bundle 文件就相当于远程仓库。
假如你的队友已经有现成的仓库了,只需要拉取你的更新,可以执行:$ git pull repo_test.bundle
¶fetch
来看看 fetch
的操作示例:$ git fetch repo_test.bundle master:other-branch
From repo_test.bundle
* [new branch] master -> other-branch
此操作会从 repo_test.bundle
文件中的 master
分支导出到本地的 other-branch
分支中。
执行 git branch,你会发现多了一个 other-branch 分支:$ git branch
* master
other-branch
基本的使用其实了解以上操作就可以应对我们开头提到的那些场景了,为了知识的完整性,继续来了解一下其他几个操作。
¶校验 - verify
用来校验生成的包是否合法,也就是说能否正常解压出来。
操作示例:$ git bundle verify repo_test.bundle
The bundle contains this ref:
1faebfab3ef4e001b032c0c5c96f400c19565076 HEAD
The bundle requires this ref:
506f9bae79d1b82ba245dfa2b24dd8e76d3dc3c6
repo_test.bundle is okay
如上提示 okay
表示是 合法的 bundle
文件。
如果不合法会有以下类似的提示:$ git bundle verify file.bundle
error: 'file.bundle' does not look like a v2 or v3 bundle file
在上述操作中,随便弄了个文件将后缀名改成 .bundle
,所以 不是一个合法的 bundle
文件。
¶列出引用 - list-heads
列出
bundle
包中定义的引用。
比如:$ git bundle list-heads repo_test.bundle
506f9bae79d1b82ba245dfa2b24dd8e76d3dc3c6 HEAD
506f9bae79d1b82ba245dfa2b24dd8e76d3dc3c6 refs/heads/master
¶存储引用 - unbundle
将包中的对象传递给 git index-pack 以存储在存储库中,然后打印所有已定义引用的名称。如果给出了引用列表,则仅打印与列表中的引用匹配的引用。
看描述有点抽象,来看看操作示例:$ git bundle unbundle repo_test.bundle
506f9bae79d1b82ba245dfa2b24dd8e76d3dc3c6 HEAD
506f9bae79d1b82ba245dfa2b24dd8e76d3dc3c6 refs/heads/master
看起来好像和 list-heads
操作一样,但其实 unbundle
给当前仓库 进行了存储索引的操作。
一般用来配合其他命令操作,比如我们执行 unbundle
操作后再执行如下命令:$ git checkout -b dev_v1.0.0 506f9bae79d1b82ba245dfa2b24dd8e76d3dc3c6
此时会根据我们指定的 SHA-1
值创建一个 dev_v1.0.0
分支,而如果你是执行 list-heads
操作后便去执行上述命令则会提示:fatal: reference is not a tree:506f9bae79d1b82ba245dfa2b24dd8e76d3dc3c6
¶结语
简单来说,git bundle
的使用场景其实可以理解为:
在网络受限无法直连仓库的情况下,将本地数据推送(打包)到一个 bundle
文件,然后通过邮件或IM软件等方式传送给你的协作者,对方在更新的时候,拉取更新的来源是你的 bundle
文件而不是远端仓库,因为此时 bundle
文件就相当于一个离线的中转仓库。