4 个版本
0.2.2 | 2024年1月30日 |
---|---|
0.2.1 | 2023年6月24日 |
0.2.0 | 2023年2月28日 |
0.1.1 | 2023年2月7日 |
0.1.0 |
|
#1492 在 命令行工具
每月 33 次下载
74KB
1.5K SLoC
git-ibundle
git-ibundle 是一个用于 Git 仓库增量离线镜像的工具。
通过一系列 "ibundle"(增量包)文件,将增量仓库数据从源网络传输到目标网络。两个网络之间不需要交互连接;只需要可靠的单向文件传输能力。
典型传输过程
假设将 repo.git
从源网络镜像到断开连接的目标网络。
首先进行一次设置
-
在源网络上,对仓库执行镜像克隆
git clone --mirror https://github.com/user/repo.git cd repo.git
-
在目标网络上,设置一个空的裸仓库作为镜像
mkdir repo.git cd repo.git git init --bare
接下来,根据需要重复以下步骤,以保持源和目标仓库同步
-
在源网络上,获取任何更改并创建
repo.ibundle
# On source network, within the `repo.git` directory: git fetch git-ibundle create .../path/to/repo.ibundle
-
将
repo.ibundle
文件传输到目标网络。 -
在目标网络上,从
repo.ibundle
获取# On destination network, within the `repo.git` directory: git-ibundle fetch .../path/to/repo.ibundle
变更历史
有关变更列表,请参阅 CHANGES。
许可证
git-ibundle 根据 MIT 许可证许可;请参阅 LICENSE。
需求
git-ibundle
可执行文件- Git v2.31+(在
PATH
上有git
)
注意:Git 版本 2.31 引入了 git-ibundle 所需的 git bundle create --stdin
标志。
开发和大多数测试是在 Linux 上进行的;这是最佳支持的平台。在 Windows 上进行了有限的测试。在 Macos 上没有进行测试。
安装
安装选项包括
-
从发布区域下载预构建的可执行文件用于git-ibundle: https://github.com/drmikehenry/git-ibundle/releases
-
通过
crates.io
安装git-ibundlecargo install git-ibundle
使用git ibundle
进行调用
git-ibundle使用git-
前缀命名,以便它可以作为命令ibundle
集成到Git中。如果找到git-ibundle
可执行文件在PATH
上,那么Git命令git ibundle
将委托给git-ibundle
。这些调用是等效的
git-ibundle <ibundle-arguments>
git ibundle <ibundle-arguments>
这允许git-ibundle继承一些通用的Git功能,其中最有用的是
git -C path/to/repository <command>
这会导致Git在运行<command>
之前更改目录到path/to/repository
。例如
# Create directory and initialize as a bare Git repo:
mkdir repo.git
git -C repo.git init --bare
这对于git-ibundle
来说也是很有用的。考虑有一个仓库和一个ibundle文件在同一个目录下
./
repo.git/
repo.ibundle
要从这个ibundle获取到仓库中,您可以将目录更改为仓库目录并像这样获取
cd repo.git
git ibundle fetch ../repo.ibundle
cd ..
或者您可以使用-C repo.git
在一步中完成这个操作
git -C repo.git ibundle fetch ../repo.ibundle
请注意,更改目录发生在git-ibundle
检查其参数之前,因此如果您使用到repo.ibundle
的相对路径,您必须使该路径相对于仓库的位置(这就是为什么上面的例子使用../repo.ibundle
的原因)。
模型
git-ibundle在离散的时间同步点同步两个仓库。每次通过git-ibundle create
创建ibundle时,就会定义一个新的同步点,并记录当前仓库状态。仓库状态包括HEAD
以及所有分支、标签和相关提交ID。一个自动递增的序列号提供了一种识别同步点并标记相关ibundle文件和当前仓库状态的方法。
ibundle文件包含在先前(基础)状态和当前状态之间发生的源仓库更改。在目标位置,git-ibundle fetch
将应用这些更改到目标位置,同步该仓库与源仓库。git-ibundle验证目标仓库已经应用了ibundle基础上的更改。
默认情况下,使用立即前一个序列号作为基础创建ibundle;您可以通过git-ibundle create --basis <seq_num>
选择不同的基础。如果在将它们获取到目标仓库之前,任何先前的ibundle文件已经丢失,这将很有用。
对于repo.git
仓库,git-ibundle使用目录repo.git/ibundle/
来存储其元数据。该目录对Git来说是透明的,不会干扰或与正常的Git操作重叠。
镜像子集
git-ibundle自身总是创建源存储库的完整镜像。这包括存储库中的所有引用,包括在refs/remotes/<REMOTE>
下找到的任何内容。应使用git clone --mirror
将源存储库克隆到本地repo.git
目录,以防止创建refs/remotes/<REMOTE>
并确保准确的镜像。
可以通过设置负引用规范来镜像原始存储库的子集。例如,为了避免镜像Github拉取请求(这些引用规范的形式为refs/pull/*
),可以使用以下负引用规范:
remote.origin.fetch=^refs/pull/*
这不能通过git clone --mirror --config
来配置,因为负引用规范不会立即生效;相反,手动通过以下方式设置源repo.git
:
mkdir repo.git
cd repo.git
git init --bare
git remote add origin --mirror=push https://github.com/user/repo.git
git config remote.origin.fetch '+refs/*:refs/*'
git config --add remote.origin.fetch '^refs/pull/*'
然后可以抓取并验证引用是否符合预期。
git fetch
git show-ref
命令调用详情
创建ibundle
Usage: git-ibundle create [OPTIONS] <IBUNDLE_FILE>
Arguments:
<IBUNDLE_FILE> ibundle file to create
Options:
--basis <BASIS> Choose alternate basis sequence number
--basis-current Choose basis to be current repository state
--standalone Force ibundle to be standalone
--allow-empty Allow creation of an empty ibundle
-h, --help Print help information
-V, --version Print version information
-v, --verbose... More output per occurrence
-q, --quiet... Less output per occurrence
在第一次创建ibundle时,存储库将分配一个随机的repo_id。这有助于防止将ibundle文件错误地应用到错误的Git存储库目标。在git-ibundle fetch
操作期间将检查repo_id。
基础序列号默认比ibundle的序列号小一;对于第一个ibundle(其序列号为1
),基础序列号将为0
。
使用--basis 0
,创建的ibundle将假设目标没有先决提交;它将包含通过git-ibundle fetch
创建镜像存储库所需的一切。请注意,--basis 0
意味着--standalone
。
如果不使用--standalone
,则ibundle将假设目标已同步到--basis
序列号,因此包含所有先决提交和引用;因此,创建的ibundle文件仅包含用于紧凑性的更改引用,以及包含更新Git对象的Git "PACK"。
使用--standalone
,ibundle将包含完整的命名引用集合和先决提交ID的完整枚举。提交数据仍然是增量且基于由--basis
隐含的提交。这可以用于目标存储库已知具有先决提交但缺少实际基础序列号的情况(例如,在目标网络上使用预存存储库镜像时)。
通常,git-ibundle create
将拒绝在没有自上次创建ibundle以来有任何更改时创建ibundle。在这种情况下,将提供一个退出状态3
(而大多数失败将导致退出状态为1
)。要允许创建空ibundle,请使用--allow-empty
。
使用--basis-current
(这隐含了--standalone
和--allow-empty
),基础设置为当前仓库状态。ibundle将逻辑上为空且独立,适用于将现有目标仓库(已知与当前仓库状态匹配)中的内容提取出来。这为使用git-ibundle对现有镜像仓库对进行初始化提供了方法。例如
# On source network:
cd source.git
git-ibundle create --basis-current ../bootstrap.ibundle
# Transfer `bootstrap.ibundle` to destination network.
# On destination network:
cd destination.git
git-ibundle fetch ../bootstrap.ibundle --force
从ibundle获取
Usage: git-ibundle fetch [OPTIONS] <IBUNDLE_FILE>
Arguments:
<IBUNDLE_FILE> ibundle file to fetch
Options:
--dry-run Perform a trial fetch without making changes to the repository
--force Force fetch operation
-h, --help Print help information
-V, --version Print version information
-v, --verbose... More output per occurrence
-q, --quiet... Less output per occurrence
使用--dry-run
,模拟获取操作,但不会更改仓库。这对于检查ibundle文件的有效性以及测试非常有用。
git-ibundle在从意外捆绑包获取时会非常小心。使用--force
来覆盖此谨慎。以下情况下可以使用--force
:
-
仓库非空,但尚未进行过获取操作,因此不存在git-ibundle repo_id。如果没有使用
--force
,git-ibundle不会冒险覆盖错误仓库的引用。 -
一个带有非零基础序列号的独立ibundle正在应用于缺少该基础的仓库。因为ibundle是独立的,所以引用集和先决条件提交ID在ibundle本身内,因此
fetch
操作可以安全尝试;强制执行不会覆盖所有提交ID都必须存在的需求。
显示ibundle的详细信息
Usage: git-ibundle show [OPTIONS] <IBUNDLE_FILE>
Arguments:
<IBUNDLE_FILE> ibundle file to examine
Options:
-h, --help Print help information
-V, --version Print version information
-v, --verbose... More output per occurrence
-q, --quiet... Less output per occurrence
例如
$ git-ibundle show file.ibundle
standalone: no
repo_id: d64e7f05-9e75-458d-8c3d-9e7380b6d5b5
seq_num: 2
basis_seq_num: 1
head_ref: 'refs/heads/main'
head_detached: no
added_orefs: 1
removed_orefs: 1
moved_orefs: 2
prereqs: 1
使用--verbose
,显示更多详细信息
$ git-ibundle show --verbose file.ibundle
standalone: no
repo_id: d64e7f05-9e75-458d-8c3d-9e7380b6d5b5
seq_num: 2
basis_seq_num: 1
head_ref: 'refs/heads/main'
head_detached: no
added_orefs: 1
4575ca5a540085b2569d714fd449ba7a21b3ebf6 'refs/tags/tag2'
.
removed_orefs: 1
29f7fecbb7c205a4185c59cf50c6ff0d5137979d 'refs/heads/branch1'
.
moved_orefs: 2
4575ca5a540085b2569d714fd449ba7a21b3ebf6 'HEAD'
4575ca5a540085b2569d714fd449ba7a21b3ebf6 'refs/heads/main'
.
prereqs: 1
29f7fecbb7c205a4185c59cf50c6ff0d5137979d 'Initial commit.'
.
报告状态
Report status
Usage: git-ibundle status [OPTIONS]
Options:
-h, --help Print help information
-V, --version Print version information
-v, --verbose... More output per occurrence
-q, --quiet... Less output per occurrence
这提供了给定仓库的git-ibundle状态。例如
$ git-ibundle status
repo_id: 18450f13-4003-474a-a69e-22782ef3848f
max_seq_num: 13
next_seq_num: 14
next_seq_num
字段指示下一个git-ibundle create
操作将使用的序列号。
max_seq_num
字段指示由最近一次git-ibundle create
操作使用的序列号。
使用--verbose
,提供更多详细信息
$ git-ibundle status --verbose
repo_id: 18450f13-4003-474a-a69e-22782ef3848f
max_seq_num: 13
next_seq_num: 14
details:
seq_num num_refs HEAD
1 0 refs/heads/main
2 0 refs/heads/main
3 5 refs/heads/main
4 5 refs/heads/main
5 6 refs/heads/main
6 7 refs/heads/fix1
7 7 refs/heads/main2
8 7 refs/heads/main
9 7 343f8d34eb565c0e97194604fa2c6c3ff8ba4931 (detached)
10 7 refs/heads/main
11 7 refs/heads/main
12 7 refs/heads/main
13 11 refs/heads/main
清理旧序列号
Usage: git-ibundle clean [OPTIONS]
Options:
--keep <KEEP> Number of sequence numbers to retain [default: 20]
-h, --help Print help information
-V, --version Print version information
-v, --verbose... More output per occurrence
-q, --quiet... Less output per occurrence
默认情况下,git-ibundle保留所有序列号的元数据。使用git-ibundle clean
来清理旧序列号。
与Git捆绑包的比较
git-ibundle的大部分工作由Git自身的捆绑功能处理。对于非增量镜像,Git的捆绑包提供了一种完整的解决方案。例如,以下命令将源仓库的全部内容打包成一个捆绑文件
# Run from within the source Git repository:
git bundle create ../repo.bundle --all
同样,在空的目标仓库中,以下命令从捆绑包中获取内容,并复制几乎整个仓库状态
# Run from within the destination Git repository:
git fetch --prune --force repo.bundle "*:*"
唯一缺失的是将HEAD
设置为适当的符号分支名称,因为捆绑文件没有通信该分支名称的方法。但是,一对额外的命令可以处理这个问题。在源仓库中,通过以下方式查询HEAD
:
$ git symbolic-ref HEAD
refs/heads/main
然后,在目标仓库中,手动设置相应的HEAD
,例如
git symbolic-ref HEAD refs/heads/main
Git还提供了一种方法通过在提交前添加一个前导撇号(^
)来排除捆绑包中的提交。在源中main
的单一附加提交后,可以创建一个新的捆绑文件,仅包含附加的提交(假设main
是仓库中唯一的引用)
git bundle create ../repo.bundle --all ^HEAD~
捆绑包可能包含如下头部信息
# v2 git bundle
-9a3bbf283e30565d9ac378cb73c36ca8a417c5e0 Some commit log message
22a3d70042ecc8bce2772bfa85eadf64adb77441 refs/heads/main
22a3d70042ecc8bce2772bfa85eadf64adb77441 HEAD
提交9a3bbf2
已在第一个捆绑包中发送,它已成为此增量捆绑文件的先决条件。Git出色地将所需引用和排除的范围精简到最小的一组先决条件和更改后的引用。
遗憾的是,Git 的先决条件始终是提交。注解标签指向标签对象,然后这些对象再指向提交。包文件没有方法表达标签对象作为先决条件。
此外,Git 将删除任何指向由任何 ^
排除操作排除的对象的引用。假设一个包含大量 main
提交的仓库通过以下方式完全打包:
git bundle create ../repo.bundle --all
现在假设唯一的变化是在 HEAD
几个提交之前添加一个新分支
git branch branch1 HEAD~2
尝试请求将此新分支添加到新的增量包将失败
git bundle create ../repo.bundle branch1 ^main
这是因为 branch1
指向 main
的一个祖先,而 main
已被排除,导致 branch1
也被排除。
为了执行增量镜像,git-ibundle 使用源仓库中的 git bundle create
在每个同步点创建临时包文件。在包中包含了一组先决提交、一组新对象和一组指向新创建对象的引用列表。git-ibundle 然后从包文件中提取此信息,并将其与其他元数据结合起来创建一个 ibundle 文件;在目标仓库中,将 ibundle 与存储的仓库元数据结合,重建写入临时包文件的全套引用;此包使用 git fetch --prune --force temp.bundle "*:*"
应用到目标仓库;最后,根据 ibundle 文件中传达的值适当设置 HEAD
。
依赖关系
~15MB
~350K SLoC