同步与多仓库

包(bundle)与归档

把一个仓库塞进单个文件,有两种办法。它们看上去可以互换,其实不能,而挑错了那一个,正是这一页存在的全部理由。

一个包(bundle) 一个归档
装的是 历史:提交、分支、标签 某一个提交上的那些文件
用什么打开 git clone / git fetch——它就是一个远程 任何解压工具
之后 你还能再从它获取、合并、继续干活 什么也没有。它是一张快照
用在 把工作搬到一台没有网络的机器上 「把 v2.1 的源码发我」

⌘K → 打包仓库或导出归档。

把一个仓库打包成单个文件,范围选项就位

包

包(bundle)是 git 对一道任何网络都跨不过去的沟壑给出的答案:一台物理隔离的机器、一支 U 盘、一个邮件附件、飞机上的一台笔记本。接收的那一端跑一句 git clone work.bundle myrepo,就得到一个真正的仓库,带着你的历史和你的分支,并且能从那个文件里获取,仿佛它是一台服务器。

三种范围:

范围 什么会被带走 大小
全部 每一个分支和标签,完整历史 整个仓库
某一个分支或标签 那个 ref 以及它能到达的一切 通常是其中的大部分
一段提交区间 只有两端之间的东西 很小

区间包是一块历史的补丁,不是一个仓库。 它把远的那一端记为前置条件:git 拒绝在一个还没有那个提交的仓库里打开它,因为那样新的提交就无处可挂。这是正确的行为,也是头一回遇上时的意外。当对方已经拿到了你到某个点为止的工作时——他们上次收到的那个标签、你们共同分出来的那个提交——就该用区间。

收到一个包

导入包… 会读取这个文件,列出它装了什么,并且一上来就告诉你这个仓库能不能用它——如果缺少前置条件,它会告诉你缺几个,而不是等到后面用 git 自己的措辞失败。

导入进来的 ref 落在 bundle/… 下面,也就是远程跟踪的命名空间里。本地什么都不动:没有分支被快进,没有工作被覆盖。然后你按自己的节奏去合并、变基或检出 bundle/main,跟对待任何别的远程上的分支完全一样。

如果你想从一个包新建一个仓库,那就在终端里从这个文件克隆:git clone work.bundle myrepo。Gitcito 是导入到一个已打开的仓库里;它不从文件克隆。

归档

git archive 会把某一个提交上的那棵树写成一个 zip 或者一个 tarball。没有 .git,没有历史,也没法从它获取——而当接收方该拿到的是源代码、不是仓库时,这恰恰就是重点。

选项 它做什么
引用 要导出的分支、标签或提交。通常答案是一个标签
格式 zip、tar.gz 或 tar
包进一个目录 加一层顶层文件夹,这样解包时就不会把文件撒得到处都是
只要这个路径 只导出一个子目录,而不是整棵树

export-ignore 才是用它的理由

一个仓库可以在 .gitattributes 里标记路径:

.github/     export-ignore
test/        export-ignore
*.psd        export-ignore

这些路径会被排除在每一个归档之外,同时仍然留在仓库里。一个项目就是这样发出一个不含 CI 配置、不含测试夹具、不含那 200 MB 设计文件的发布 tarball 的,而且这条规则住在仓库里,不住在某个人的发布脚本里。

值得知道的限制

  • 包是一份完整副本,除非你用区间。给一个 2 GB 的仓库打包会写出一个 2 GB 的文件,耗时和一次克隆差不多。
  • 空的包会被拒绝,拒绝它的是 git 而不是 Gitcito:两端之间什么都没有的区间会产生一个错误,而不是一个没用的文件。
  • 导入不做合并。 ref 到达 bundle/… 之后就待在那儿,直到你拿它们做点什么。
  • 归档没有历史,所以它变不回一个仓库。如果接收方之后还需要提交,那就发一个包。
  • export-ignore 只影响归档。 它不会对克隆、对包、对历史藏起任何东西——要做那件事,见从历史中移除一个文件。

另请参阅:同步 · 安全分享 · 从历史中移除一个文件

在 GitHub 上改进这份翻译