拆分 git 捆绑文件
Splitting git bundle file
有什么方法可以拆分 git 捆绑文件吗?例如,repo.bundle1 和 repo.bundle2,每个都包含一半的 repo。便携式捆绑包太大,无法传输。
假设不能更改允许传输的最大大小,我还能如何处理这个问题。
捆绑包可以是增量的。
它们不能有悬而未决的提交,因此如果您想逐步捆绑现有分支,则必须玩一些游戏。
它们必须被应用 "in order" 这样当你应用一个 bundle 时,它的根提交的父级可以被锁定。 (可能有一种方法可以通过浅层回购来解决这个问题,但如果您试图最终重建整个回购,那么您就不必担心了。)
当然,如果任何单个提交太大(例如,由于提交一个非常大的文件),那将是一个问题。
假设你有
x -- x -- x <--(branch1)
/
A -- B -- C -- D -- E -- F -- G -- H -- I -- J <--(master)
\ /
o -- o <--(branch2)
并假设您想将其分成不超过 3 个提交的包。因此,让我们从根开始。我们将逐步移动 master
分支,所以让我们跟踪它的当前位置。
git checkout master
git tag real_master
现在我们查找 C
的 SHA ID(或查找其他引用 C
的名称,例如本例中的 master~7
),然后查找
git reset --hard master~7
请注意,我正在使用硬重置;这可能不是必需的,但我假设你可以从一个干净的工作树的回购中做到这一点,在这种情况下,进行硬重置可以使一切保持良好、简单的状态(无论如何,正如我所看到的)。
我们已准备好创建我们的第一个包
git bundle create 0.bundle master
此捆绑包括 B
,它是 branch1
的根,因此我们现在可以捆绑 branch1
。
git bundle create 1.bundle master..branch1
这相当于
git bundle create 1.bundle ^master branch1
无论哪种方式,我们都假设接收回购已经具有可从 master
访问的 ocmmits,因此 只有 x
提交将放在这个包里。
D
、E
、F
似乎是下一个合乎逻辑的步骤;但是 F
取决于 o
在 brnach2
中的提交。所以下一个合乎逻辑的事情是将 branch2
与 D
捆绑在一起。由于我们在 C
处仍然有 master
,我们可以说
git bundle create 2.bundle master..branch2
现在我们需要将 master
移动到 G
,以便我们可以捆绑 E
、F
和 G
。确保我们在 master
和
git reset --hard real_master~3
git bundle create 3.bundle ^branch2 ^master~3 master
这里我注意到旧的主线历史和 branch2
历史都可以从 master
访问(通过 F
处的合并),但是因为它们都是已经捆绑我排除了他们两个。
最后,
git reset --hard real_master
git tag -d real_master
git bundle create 4.bundle master~3..master
在实践中,您可能会在每个包中使用超过 3 个提交。如果你有一个本身太大的侧分支,你可以使用我们在这个例子中用来分割 master
的相同技术来分解它。
现在您可以独立传输它们,并从中获取(或拉取)它们以便在另一端重建存储库。
更新
两个补充说明:
首先,与ElpieKay建议使用dd
和cat
相比,上述方法有利有弊。
它仅依赖于 git 本身(尽管 dd
/cat
方法所需的实用程序通常随 git 一起提供)。
单独的包文件各自都有用,而如果您用 dd
分割文件,则必须重建所有部分以确保您有一个可用的包。这也意味着您可以保存捆绑包并将它们与您稍后创建的其他捆绑包组合(随着更多更改的发生);但这只有在您需要从头开始创建另一个新的远程仓库时才重要。
实际上,只是来回传送增量更改,双方已经有了共同的提交基线,这是捆绑包的基本用例。因此,您可能决定使用 dd
/cat
方法来最初创建远程存储库,然后使用增量捆绑包进行后续更新共享。
dd
/cat
方法的最大优点是它非常 死记硬背/可编写脚本(即简单假设工具在手边),而您必须考虑如何为上述方法划分提交;而且 dd
方法可以拆分单个令人讨厌的大提交,如果结果是一个的话。
我一开始也忘了提到,您可以列出要包含在一个包中的多个分支。因此,例如,如果您的阈值更像是每个捆绑包 8 次提交,您可以
1) 将master
移动到E
2) 捆绑 master
和 branch1
作为 0.bundle
3) 将 master
移回 J
4) 捆绑 master
排除 master~5
作为 1.bundle
完成。
命令dd
可以将一个文件分割成多个部分。 cat
可以将零件组合成一个整体。
假设我们发现repo.bundle
是1466712k,约1.4g,一直到du repo.bundle
。并假设限制为 1g。我们可以把repo.bundle
拆分成2个文件,一个700m,一个700多一点,这样就可以传输了。
dd if=repo.bundle bs=1048576 count=700 skip=0 of=repo.bundle1
dd if=repo.bundle bs=1048576 skip=700 of=repo.bundle2
bs
的单位是字节所以1048576
是1m
。 700
表示700块。 skip
是要跳过的块数。所以第一个 dd
将 repo.bundle
的前 700*1048576 个字节写入 repo.bundle1
而第二个 dd
跳过第一个 700*1048576 然后将其余字节写入 repo.bundle2
.
这两个文件转移到另一台机器后,用cat
合并:
cat repo.bundle1 repo.bundle2 > repo.bundle
请注意 cat
之后的文件顺序很重要。我们可以使用 md5sum
来检查合并后的 repo.bundle
是否与原点相同。如果两个文件仍然太大,我们可以将原始文件拆分成更多部分。小心每个 dd
中的 skip
。
dd
、cat
、du
、md5sum
也可用于 git-bash
。
有什么方法可以拆分 git 捆绑文件吗?例如,repo.bundle1 和 repo.bundle2,每个都包含一半的 repo。便携式捆绑包太大,无法传输。
假设不能更改允许传输的最大大小,我还能如何处理这个问题。
捆绑包可以是增量的。
它们不能有悬而未决的提交,因此如果您想逐步捆绑现有分支,则必须玩一些游戏。
它们必须被应用 "in order" 这样当你应用一个 bundle 时,它的根提交的父级可以被锁定。 (可能有一种方法可以通过浅层回购来解决这个问题,但如果您试图最终重建整个回购,那么您就不必担心了。)
当然,如果任何单个提交太大(例如,由于提交一个非常大的文件),那将是一个问题。
假设你有
x -- x -- x <--(branch1)
/
A -- B -- C -- D -- E -- F -- G -- H -- I -- J <--(master)
\ /
o -- o <--(branch2)
并假设您想将其分成不超过 3 个提交的包。因此,让我们从根开始。我们将逐步移动 master
分支,所以让我们跟踪它的当前位置。
git checkout master
git tag real_master
现在我们查找 C
的 SHA ID(或查找其他引用 C
的名称,例如本例中的 master~7
),然后查找
git reset --hard master~7
请注意,我正在使用硬重置;这可能不是必需的,但我假设你可以从一个干净的工作树的回购中做到这一点,在这种情况下,进行硬重置可以使一切保持良好、简单的状态(无论如何,正如我所看到的)。
我们已准备好创建我们的第一个包
git bundle create 0.bundle master
此捆绑包括 B
,它是 branch1
的根,因此我们现在可以捆绑 branch1
。
git bundle create 1.bundle master..branch1
这相当于
git bundle create 1.bundle ^master branch1
无论哪种方式,我们都假设接收回购已经具有可从 master
访问的 ocmmits,因此 只有 x
提交将放在这个包里。
D
、E
、F
似乎是下一个合乎逻辑的步骤;但是 F
取决于 o
在 brnach2
中的提交。所以下一个合乎逻辑的事情是将 branch2
与 D
捆绑在一起。由于我们在 C
处仍然有 master
,我们可以说
git bundle create 2.bundle master..branch2
现在我们需要将 master
移动到 G
,以便我们可以捆绑 E
、F
和 G
。确保我们在 master
和
git reset --hard real_master~3
git bundle create 3.bundle ^branch2 ^master~3 master
这里我注意到旧的主线历史和 branch2
历史都可以从 master
访问(通过 F
处的合并),但是因为它们都是已经捆绑我排除了他们两个。
最后,
git reset --hard real_master
git tag -d real_master
git bundle create 4.bundle master~3..master
在实践中,您可能会在每个包中使用超过 3 个提交。如果你有一个本身太大的侧分支,你可以使用我们在这个例子中用来分割 master
的相同技术来分解它。
现在您可以独立传输它们,并从中获取(或拉取)它们以便在另一端重建存储库。
更新
两个补充说明:
首先,与ElpieKay建议使用dd
和cat
相比,上述方法有利有弊。
它仅依赖于 git 本身(尽管 dd
/cat
方法所需的实用程序通常随 git 一起提供)。
单独的包文件各自都有用,而如果您用 dd
分割文件,则必须重建所有部分以确保您有一个可用的包。这也意味着您可以保存捆绑包并将它们与您稍后创建的其他捆绑包组合(随着更多更改的发生);但这只有在您需要从头开始创建另一个新的远程仓库时才重要。
实际上,只是来回传送增量更改,双方已经有了共同的提交基线,这是捆绑包的基本用例。因此,您可能决定使用 dd
/cat
方法来最初创建远程存储库,然后使用增量捆绑包进行后续更新共享。
dd
/cat
方法的最大优点是它非常 死记硬背/可编写脚本(即简单假设工具在手边),而您必须考虑如何为上述方法划分提交;而且 dd
方法可以拆分单个令人讨厌的大提交,如果结果是一个的话。
我一开始也忘了提到,您可以列出要包含在一个包中的多个分支。因此,例如,如果您的阈值更像是每个捆绑包 8 次提交,您可以
1) 将master
移动到E
2) 捆绑 master
和 branch1
作为 0.bundle
3) 将 master
移回 J
4) 捆绑 master
排除 master~5
作为 1.bundle
完成。
命令dd
可以将一个文件分割成多个部分。 cat
可以将零件组合成一个整体。
假设我们发现repo.bundle
是1466712k,约1.4g,一直到du repo.bundle
。并假设限制为 1g。我们可以把repo.bundle
拆分成2个文件,一个700m,一个700多一点,这样就可以传输了。
dd if=repo.bundle bs=1048576 count=700 skip=0 of=repo.bundle1
dd if=repo.bundle bs=1048576 skip=700 of=repo.bundle2
bs
的单位是字节所以1048576
是1m
。 700
表示700块。 skip
是要跳过的块数。所以第一个 dd
将 repo.bundle
的前 700*1048576 个字节写入 repo.bundle1
而第二个 dd
跳过第一个 700*1048576 然后将其余字节写入 repo.bundle2
.
这两个文件转移到另一台机器后,用cat
合并:
cat repo.bundle1 repo.bundle2 > repo.bundle
请注意 cat
之后的文件顺序很重要。我们可以使用 md5sum
来检查合并后的 repo.bundle
是否与原点相同。如果两个文件仍然太大,我们可以将原始文件拆分成更多部分。小心每个 dd
中的 skip
。
dd
、cat
、du
、md5sum
也可用于 git-bash
。