1  版权声明
2 起步
2.1  关于版本控制
2.2  Git 简史
2.3  Git 基础
2.4  命令行
2.5  安装 Git
2.6  初次运行Git前的配置
2.7  获取帮助
2.8  总结
3 Git 基础
3.1  获取 Git 仓库
3.2  记录每次更新到仓库
3.3  查看提交历史
3.4  撤消操作
3.5  远程仓库的使用
3.6  打标签
3.7  Git 别名
3.8  总结
4 Git 分支
4.1  分支简介
4.2  分支的新建与合并
4.3  分支管理
4.4  分支开发工作流
4.5  远程分支
4.6  变基
4.7  总结
5 服务器上的 Git
5.1  协议
5.2  在服务器上搭建 Git
5.3  生成 SSH 公钥
5.4  配置服务器
5.5  Git 守护进程
5.6  Smart HTTP
5.7  GitWeb
5.8  GitLab
5.9  第三方托管的选择
5.10  总结
6 分布式 Git
6.1  分布式工作流程
6.2  向一个项目贡献
6.3  维护项目
6.4  总结
7 GitHub
7.1  账户的创建和配置
7.2  对项目做出贡献
7.3  维护项目
7.4  管理组织
7.5  脚本 GitHub
7.6  总结
8 Git工具
8.1  选择修订版本
8.2  交互式暂存
8.3  储藏与清理
8.4  签署工作
8.5  搜索
8.6  重写历史
8.7  重置揭密
8.8  高级合并
8.9  Rerere
8.10  使用 Git 调试
8.11  子模块
8.12  打包
8.13  替换
8.14  凭证存储
8.15  总结
9 自定义Git
9.1  配置 Git
9.2  Git 属性
9.3  Git 钩子
9.4  使用强制策略的一个例子
10 Git与其他系统
10.1  作为客户端的 Git
10.2  迁移到 Git
10.3  总结
11 Git内部原理
11.1  底层命令和高层命令
11.2  Git 对象
11.3  Git 引用
11.4  包文件
11.5  引用规格
11.6  传输协议
11.7  维护与数据恢复
11.8  环境变量
11.9  总结

打包

2018-06-21 10:20:42
git
1448
最后编辑:GavinHsueh 于 2018-06-21 10:36:30

虽然我们已经了解了网络传输 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
Initialized empty Git repository in /private/tmp/bundle/repo/.git/
$ cd repo
$ git log --oneline
9a466c5 second commit
b1ec324 first commit

如果你在打包时没有包含 HEAD 引用,你还需要在命令后指定一个 -b master 或者其他被引入的分支,否则 Git 不知道应该检出哪一个分支。

现在假设你提交了 3 个修订,并且要用邮件或者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

首先我们需要确认我们希望被打包的提交区间。 和网络协议不太一样,网络协议会自动计算出所需传输的最小数据集,而我们需要手动计算。 当然你可以像上面那样将整个仓库打包,但最好仅仅打包变更的部分 —— 就是我们刚刚在本地做的 3 个提交。

为了实现这个目标,你需要计算出差别。 就像我们在  提交区间 介绍的,你有很多种方式去指明一个提交区间。 我们可以使用 origin/master..master 或者 master ^origin/master 之类的方法来获取那 3 个在我们的 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

可以看到我们已经将提交导入到 other-master 分支,以及在这期间我们自己在 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 很适合用于共享或者网络类型的操作。

发表评论
评论通过审核后显示。