-
1. 起步
-
2. Git 基础
-
3. Git 分支
-
4. 服务器上的 Git
- 4.1 协议
- 4.2 在服务器上部署 Git
- 4.3 生成 SSH 公钥
- 4.4 架设服务器
- 4.5 Git Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 第三方托管服务
- 4.10 小结
-
5. 分布式 Git
-
A1. 附录 A: Git 在其他环境
- A1.1 图形界面
- A1.2 Visual Studio 中的 Git
- A1.3 Visual Studio Code 中的 Git
- A1.4 IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine 中的 Git
- A1.5 Sublime Text 中的 Git
- A1.6 Bash 中的 Git
- A1.7 Zsh 中的 Git
- A1.8 PowerShell 中的 Git
- A1.9 小结
-
A2. 附录 B: 在应用程序中嵌入 Git
-
A3. 附录 C: Git 命令
7.12 Git 工具 - 打包
打包
尽管我们已经介绍了通过网络传输 Git 数据的常用方法(HTTP、SSH 等),但实际上还有一种不常用但却非常实用的方法。
Git 能够将其数据“打包”成一个单一文件。这在各种场景中都非常有用。例如,你的网络可能中断了,但你想把更改发送给同事。或者你正在异地工作,出于安全原因无法访问本地网络。又或者你的无线/以太网卡坏了。再或者你暂时无法访问共享服务器,想通过电子邮件发送更新,但又不想通过 format-patch
传输 40 个提交。
这就是 git bundle
命令的用武之地。bundle
命令会将通常通过 git push
命令在网络上传输的所有内容打包成一个二进制文件,你可以将其通过电子邮件发送给他人或放入闪存盘中,然后再解包到另一个仓库中。
让我们看一个简单的例子。假设你有一个包含两个提交的仓库
$ git log
commit 9a466c572fe88b195efd356c3f2bbeccdb504102
Author: Scott Chacon <schacon@gmail.com>
Date: Wed Mar 10 07:34:10 2010 -0800
Second commit
commit b1ec3248f39900d2a406049d762aa68e9641be25
Author: Scott Chacon <schacon@gmail.com>
Date: Wed Mar 10 07:34:01 2010 -0800
First commit
如果你想把这个仓库发送给某人,而你又无法访问可推送的仓库,或者根本不想设置一个,你可以使用 git bundle create
命令将其打包。
$ git bundle create repo.bundle HEAD master
Counting objects: 6, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (6/6), 441 bytes, done.
Total 6 (delta 0), reused 0 (delta 0)
现在你有一个名为 repo.bundle
的文件,其中包含了重新创建仓库 master
分支所需的所有数据。使用 bundle
命令时,你需要列出所有要包含的引用或特定提交范围。如果打算将其克隆到其他地方,你应该像我们在这里做的那样,将 HEAD 也添加为一个引用。
你可以将这个 repo.bundle
文件通过电子邮件发送给其他人,或者将其放入 U 盘中随身携带。
另一方面,假设你收到了这个 repo.bundle
文件,并想在这个项目上工作。你可以像从 URL 克隆一样,从这个二进制文件克隆到一个目录中。
$ git clone repo.bundle repo
Cloning into 'repo'...
...
$ cd repo
$ git log --oneline
9a466c5 Second commit
b1ec324 First commit
如果你没有在引用中包含 HEAD,则还必须指定 -b master
或包含的任何分支,否则它将不知道要检出哪个分支。
现在假设你对此进行了三次提交,并希望通过 U 盘或电子邮件将新的提交打包发送回去。
$ git log --oneline
71b84da Last commit - second repo
c99cf5b Fourth commit - second repo
7011d3d Third commit - second repo
9a466c5 Second commit
b1ec324 First commit
首先,我们需要确定要包含在包中的提交范围。与网络协议不同,网络协议会自动为我们计算出要在网络上传输的最小数据集,而我们需要手动计算。当然,你也可以像之前那样打包整个仓库,这也能行,但最好只打包差异——即我们刚刚在本地进行的三个提交。
为此,你需要计算差异。正如我们在提交范围中所述,你可以通过多种方式指定提交范围。要获取我们 master
分支中但原始克隆分支中没有的三个提交,我们可以使用 origin/master..master
或 master ^origin/master
。你可以使用 log
命令进行测试。
$ git log --oneline master ^origin/master
71b84da Last commit - second repo
c99cf5b Fourth commit - second repo
7011d3d Third commit - second repo
既然我们已经有了要包含在包中的提交列表,那么就让我们将它们打包吧。我们使用 git bundle create
命令来完成此操作,指定我们想要的包文件名以及要包含在其中的提交范围。
$ git bundle create commits.bundle master ^9a466c5
Counting objects: 11, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (9/9), 775 bytes, done.
Total 9 (delta 0), reused 0 (delta 0)
现在我们的目录中有一个 commits.bundle
文件。如果我们将其发送给我们的伙伴,她就可以将其导入到原始仓库中,即使在此期间原始仓库中又进行了更多工作。
当她收到包时,在将其导入到她的仓库之前,她可以检查包以查看其中包含什么。第一个命令是 bundle verify
命令,它将确保文件确实是一个有效的 Git 包,并且你拥有所有必要的祖先来正确地重构它。
$ git bundle verify ../commits.bundle
The bundle contains 1 ref
71b84daaf49abed142a373b6e5c59a22dc6560dc refs/heads/master
The bundle requires these 1 ref
9a466c572fe88b195efd356c3f2bbeccdb504102 second commit
../commits.bundle is okay
如果打包者只打包了他们最近的两个提交,而不是全部三个,那么原始仓库将无法导入它,因为它缺少所需的历史记录。verify
命令的结果会是这样:
$ git bundle verify ../commits-bad.bundle
error: Repository lacks these prerequisite commits:
error: 7011d3d8fc200abe0ad561c011c3852a4b7bbe95 Third commit - second repo
然而,我们的第一个包是有效的,所以我们可以从中抓取提交。如果你想查看包中有哪些可以导入的分支,还有一个命令可以列出所有头:
$ git bundle list-heads ../commits.bundle
71b84daaf49abed142a373b6e5c59a22dc6560dc refs/heads/master
verify
子命令也会告诉你头信息。重点是查看可以拉取哪些内容,因此你可以使用 fetch
或 pull
命令从这个包中导入提交。在这里,我们将包的 master
分支抓取到我们仓库中名为 other-master
的分支:
$ git fetch ../commits.bundle master:other-master
From ../commits.bundle
* [new branch] master -> other-master
现在我们可以看到,除了我们自己的 master
分支中同时进行的任何提交外,other-master
分支上也有导入的提交。
$ git log --oneline --decorate --graph --all
* 8255d41 (HEAD, master) Third commit - first repo
| * 71b84da (other-master) Last commit - second repo
| * c99cf5b Fourth commit - second repo
| * 7011d3d Third commit - second repo
|/
* 9a466c5 Second commit
* b1ec324 First commit
因此,当你不具备合适的网络或共享仓库来进行共享或网络类型操作时,git bundle
会非常有用。