Skip to content

git-bundle

通过存档移动对象和引用

概要

bash
git bundle create [-q | --quiet | --progress]
		    [--version=<version>] <file> <git-rev-list-args>
git bundle verify [-q | --quiet] <file>
git bundle list-heads <file> [<refname>...]
git bundle unbundle [--progress] <file> [<refname>...]

描述

创建、解包和操作"bundle"文件。Bundle 用于在没有活动"服务器"位于网络连接另一端的情况下"离线"传输 Git 对象。

它们可用于创建存储库的增量和完整备份(参见"示例"中的"完整备份"示例),并将一个存储库中的引用状态中继到另一个存储库(参见第二个示例)。

通过 ssh://https:// 等协议获取或"读取"的 Git 命令也可以操作 bundle 文件。可以从 bundle 进行 git-clone(1) 新存储库,使用 git-fetch(1) 从中获取,并使用 git-ls-remote(1) 列出其中包含的引用。没有相应的"写入"支持,即不支持 'git push' 到 bundle。

Bundle 格式

Bundle 是 .pack 文件(参见 git-pack-objects(1)),带有指示 bundle 中包含哪些引用的头。

像打包存档格式本身一样,bundle 可以是自包含的,也可以使用排除项创建。请参阅下面的"对象先决条件"部分。

使用修订排除项创建的 bundle 是使用 git-pack-objects(1)--thin 选项创建的"thin pack",并使用 git-index-pack(1)--fix-thin 选项解包。

使用修订排除项时没有创建"thick pack"的选项,用户不必关心这种差异。通过使用"thin pack",使用排除项创建的 bundle 大小更小。它们在底层是"thin"的仅作为好奇在这里提到,并作为其他文档的参考。

有关更多详细信息,请参阅 gitformat-bundle(5),有关"thin pack"的进一步讨论,请参阅 gitformat-pack(5)

选项

create [options] <file> <git-rev-list-args>

用于创建名为 'file' 的 bundle。这需要 '<git-rev-list-args>' 参数来定义 bundle 内容。'options' 包含 'git bundle create' 子命令特定的选项。如果 'file' 是 -,bundle 写入 stdout。

verify <file>

用于检查 bundle 文件是否有效并可干净地应用于当前存储库。这包括检查 bundle 格式本身以及检查先决条件提交是否存在并完全链接在当前存储库中。然后,'git bundle' 打印缺失提交列表(如果有)。最后,打印有关附加功能(如"对象过滤器")的信息。有关更多信息,请参阅 gitformat-bundle(5) 中的"功能"。成功时退出代码为零,但如果 bundle 文件无效则为非零。如果 'file' 是 -,bundle 从 stdin 读取。

list-heads <file>

列出 bundle 中定义的引用。如果后跟引用列表,则仅打印匹配的引用。如果 'file' 是 -,bundle 从 stdin 读取。

unbundle <file>

将 bundle 中的对象传递给 'git index-pack' 以存储在存储库中,然后打印所有定义的引用名称。如果给出了引用列表,则仅打印匹配的引用。此命令确实是管道命令,仅由 'git fetch' 调用。如果 'file' 是 -,bundle 从 stdin 读取。

<git-rev-list-args>

参数列表,'git rev-parse' 和 'git rev-list' 可接受(并包含命名引用,请参阅下面的"指定引用"),指定要传输的特定对象和引用。例如,master~10..master 使当前 master 引用与其第 10 个祖先提交以来添加的所有对象一起打包。可打包的引用和对象数量没有明确限制。

[<refname>...]

引用列表,用于限制报告为可用的引用。这主要用于 'git fetch',它期望仅接收请求的引用而不一定接收包中的所有内容(在这种情况下,'git bundle' 充当 'git fetch-pack')。

--progress

默认情况下,当连接到终端时,进度状态报告在标准错误流上,除非指定了 -q。此标志强制报告进度状态,即使标准错误流未指向终端。

--version=<version>

指定 bundle 版本。版本 2 是旧格式,只能用于 SHA-1 存储库;较新的版本 3 包含允许扩展的功能。默认值是基于使用中的哈希算法的最旧支持格式。

-q, --quiet

此标志使命令不在标准错误流上报告其进度。

指定引用

修订版本必须附有引用名称才能打包到 bundle 中。或者可以使用 --all 来打包所有引用。

可以打包多个引用,并且可以指定多组先决条件对象。打包的对象是那些不包含在先决条件的并集中的对象。

'git bundle create' 命令使用与 git rev-parse --abbrev-ref=loose 相同的规则为你解析引用名称。每个先决条件可以显式指定(例如 ^master~10)或隐式指定(例如 master~10..master--since=10.days.ago master)。

所有这些简单情况都可以(假设我们有 "master" 和 "next" 分支):

bash
$ git bundle create master.bundle master
$ echo master | git bundle create master.bundle --stdin
$ git bundle create master-and-next.bundle master next
$ (echo master; echo next) | git bundle create master-and-next.bundle --stdin

这些也可以(以及相同但省略 --stdin 的示例):

bash
$ git bundle create recent-master.bundle master~10..master
$ git bundle create recent-updates.bundle master~10..master next~5..next

右侧无法解析为引用的修订名称或范围不被接受:

bash
$ git bundle create HEAD.bundle $(git rev-parse HEAD)
fatal: Refusing to create empty bundle.
$ git bundle create master-yesterday.bundle master~10..master~5
fatal: Refusing to create empty bundle.

对象先决条件

创建 bundle 时,可以创建可以在没有共同历史的存储库中解包的自包含 bundle,以及提供负修订以排除历史早期部分所需的对象。

new 等修订提供给 git bundle create 将创建包含从修订 new 可访问的所有对象的 bundle 文件。该 bundle 可以在任何存储库中解包以获取导致修订 new 的完整历史:

bash
$ git bundle create full.bundle new

old..new 这样的修订范围将产生一个 bundle 文件,需要修订 old(以及从中可访问的任何对象)存在才能使 bundle 可"解包":

bash
$ git bundle create full.bundle old..new

没有任何先决条件的自包含 bundle 可以在任何地方提取,甚至可以克隆(即 new,但不是 old..new)。

偏向谨慎是可以的,导致 bundle 文件包含目标中已有的对象,因为这些在目标解包时会被忽略。

如果你想提供与直接从源存储库克隆相同的引用集,请对 <git-rev-list-args> 使用 --branches --tags

'git bundle verify' 命令可用于检查你的接收者存储库是否具有 bundle 所需的先决条件提交。

示例

我们讨论两种情况:

  1. 获取存储库的完整备份
  2. 当两台机器没有直接连接时,将存储库的历史传输到另一台机器

首先让我们考虑存储库的完整备份。以下命令将获取存储库的完整备份,其中所有引用都包含在 bundle 中:

bash
$ git bundle create backup.bundle --all

但请注意,这仅用于引用,即你将只包含引用和从这些引用可访问的提交。你不会包含其他本地状态,例如索引、工作树、stash、每个存储库的配置、钩子等的内容。

你可以稍后使用例如 git-clone(1) 恢复该存储库:

bash
$ git clone backup.bundle <new directory>

对于下一个示例,假设你想将存储库 R1 在机器 A 上的历史传输到机器 B 上的另一个存储库 R2。由于某种原因,A 和 B 之间不允许直接连接,但我们可以通过某种机制(CD、电子邮件等)将数据从 A 移动到 B。我们想用 R1 的 master 分支上的开发更新 R2。

要引导该过程,你可以首先创建一个没有任何先决条件的 bundle。你可以使用标签记住你上次处理到哪个提交,以便以后使用增量 bundle 轻松更新另一个存储库:

bash
machineA$ cd R1
machineA$ git bundle create file.bundle master
machineA$ git tag -f lastR2bundle master

然后你将 file.bundle 传输到目标机器 B。因为此 bundle 不需要任何现有对象来提取,你可以通过从中克隆在机器 B 上创建新存储库:

bash
machineB$ git clone -b master /home/me/tmp/file.bundle R2

这将在结果存储库中定义一个名为 "origin" 的远程,让你可以从中获取和拉取。R2 中的 $GIT_DIR/config 文件将有这样的条目:

[remote "origin"]
    url = /home/me/tmp/file.bundle
    fetch = refs/heads/*:refs/remotes/origin/*

要更新结果的 mine.git 存储库,你可以在将 /home/me/tmp/file.bundle 处存储的 bundle 替换为增量更新后进行 fetch 或 pull。

在原始存储库中再工作一段时间后,你可以创建增量 bundle 来更新另一个存储库:

bash
machineA$ cd R1
machineA$ git bundle create file.bundle lastR2bundle..master
machineA$ git tag -f lastR2bundle master

然后你将 bundle 传输到另一台机器以替换 /home/me/tmp/file.bundle,并从中拉取。

bash
machineB$ cd R2
machineB$ git pull

如果你知道目标存储库应该拥有哪些提交的必要对象,你可以使用该知识来指定先决条件,给出一个截止点来限制结果 bundle 中的修订和对象。上一个示例使用 lastR2bundle 标签用于此目的,但你可以使用你会给 git-log(1) 命令的任何其他选项。

讨论

进行存储库完整备份的天真方式是使用类似 cp -r <repo> <destination> 的东西。不鼓励这样做,因为在复制操作期间可能会写入存储库。反过来,<destination> 中的某些文件可能会损坏。

这就是为什么建议使用 Git 工具进行存储库备份,无论是使用此命令还是例如 git-clone(1)。但请记住,这些工具不会帮助你备份引用和提交以外的状态。换句话说,它们不会帮助你备份索引、工作树、stash、每个存储库的配置、钩子等的内容。

另请参阅 gitfaq(7) 中的"传输"部分,了解有关跨系统文件同步相关问题的讨论。

文件格式

请参阅 gitformat-bundle(5)

Git

git(1) 套件的一部分

基于 CC BY-NC-SA 3.0 许可发布