阅读更多

0顶
0踩

行业应用

转载新闻 Git 如何处理大仓库

2017-03-27 16:19 by 副主编 jihong10102006 评论(0) 有6997人浏览
git 是追踪代码库演进的最佳选择,并且它能让你与你的同事间高效协作。当你想要追踪的库非常巨大时会发生什么?

在这篇文章里,我会尝试着给你一些想法和技巧来恰当地处理不同种类的大仓库。

两种大代码库
  • 如果仔细想想,大概会有两种导致仓库大规模增长的原因:
  • 项目累积了非常长的历史(项目成长了很长一段时间并且积累了包袱)。
  • 项目包括了巨大的二进制资产,需要与代码一起跟踪配对。
  • 两者皆有。
因此,仓库的增长有两个维度的方向:工作目录的尺寸——例如:最近一次提交,和整个累积历史的尺寸。

有时第二种问题会与老的过时的二进制生成的东西(artifact)混合,它们都被放在仓库中,不过这类问题是比较容易处理的——如果它们很讨厌,就覆盖它们,见下文。

上述两种场景需要的技巧和解决方案是不同的——尽管有时候需要互补——让我们分别来处理它们吧。

处理拥有大量历史记录的库
将一个库视为大规模库的界线非常高 - 比如 Linux 内核的最后一个版本记录了超过 1500 万行代码,但人们仍然愿意完整阅读 - 由于监管/规定方面的原因,某些很老的项目仍然需要保持完整。

克隆它们是件痛苦的事情(现在通过拆分 Linux 库的方式使其结构清晰,它被拆分为历史库和最近时期的库,需要通过嫁接设置来访问完整的历史记录)。

方法一:浅克隆
为了更快、更节省开发者和系统时间也更节约磁盘空间,第一个解决办法是使用 git 进行浅克隆。通过浅克隆可以只克隆某个库最后的历史记录。

怎么做到?只需要使用 --depth 选项,比如:

想像一下,如果你的项目库中积累了 10 年甚至更长时间的历史记录 - 比如 JIRA 是我们往 git 迁移的一个 11 年的老库 - 累积节约的时间非常显著。

完整的克隆 JIRA 有 677 MB,如果包含工作目录还有另外的 320+ MB,总共超过 47,000 多次提交。通过浅克隆的方式检出 JIRE 需要 29.5 秒,而检出完整的历史记录则需要 4 分 24 秒。

随着时间地推移及项目二进制资产的增长,这个差距也会成比例的增长。任何情况下,构建系统都会大大受益于这种技术(指浅克隆)。

git 改善了对浅克隆的支持
过去浅克隆就像 git 世界里的残障人士一样,某些操作并未得到支持。

不过最近的版本 (1.9+) 对此有着显著的改善,现在甚至可以适当的对浅克隆库使用 pull 和 push 操作。

方法二:过滤分支
巨大的库往往存在着大量错误的提交或无用的资源,对此,使用 filter-branch 是个很好的解决办法。

这个命令可以根据预先定义的模式对项目历史进行过滤、整理、修改,甚至跳过一些文件。

它是 git 工具集中的一个非常强大的工具。目前已经有脚本可以用于识别 git 库中的大型对象,所以它使用起来非常容易。

使用 filter-branch 的示例:

filter-branch 有一个小小的缺点:一旦使用了 filter-branch,实际上已经重写了整个项目历史,因此每次提交的 ID 都会发生变化。

这要求每个开发者都要重新克隆更新后的库。

所以,如果你打算使用 filter-branch 来进行一次清理行动,应该警告你的团队,计划一个短期的冻结来进行操作,然后通知大家重新克隆库。

浅克隆的替代:只克隆一个分支
从 2012 年 4 月发布的 git 1.7.10 开始,你可以通过只克隆某一个分支来限制历史记录的数量,就像这样:

对于长期运行分发的分支,或者你在有很多分支的情况下,这个特殊的技巧都非常有用。如果你只有极少数分支,那这个办法不会带来显著的效果。

处理拥有巨大二进制资产的库
第二类大型仓库中的代码含有巨大的二进制资产。游戏团队要处理巨大的 3D 模型,Web 开发团队需要跟踪图像资产,CAD 团队可能需要操作和跟踪二进制交付物的状态。

所以有各种不同的软件团队在使用 git 的过程中会遇到这样的问题。

git 在处理二进制资产的时候并不是特别差劲,但它也不会干得特别好。默认情况下,git 会完整压缩存储二进制资产的所有后续版本,如果你有很多二进制资产的情况下,这显然不是最佳方案。

可以通过一些基本的调整来改善情况,比如运行垃圾回收 git gc,或者在 .gitattributes 中对部分二进制类型进行调整,以使用 delta 方式的提交。

不过有一点很重要,对项目中不同性质的二进制资产可能需要不同的方法。例如,这里需要检查三个方面(感谢 Stefan Saasen 的评论):
  • 对于变化显著的二进制文件 - 这是指不仅只有元数据头变化 - 这时增量压缩可能没什么作用,建议对这些文件关闭 delta 选项,以避免不必要的增量压缩并重新打包
  • 对于上述情形,就像某些文件通过 zlib 压缩并不会有多好的效果,你使用 core.compression 0 或 core.loosecompression 0 来关闭压缩功能一样;这是一个全局设置,它会对其它压缩效果不错的非二进制文件带来负面影响。因此建议你把二进制资产放在单独的库中。
  • 一定要记住 git gc 将“重复的”松散的对象变成一个单独的包文件,除非以任何方式压缩文件都不会使生成的包文件有显著差异。
  • 探索调整 core.bigFileThreshold 带来的效果。任何大于 512 MiB 都不会采用 delta 压缩 - 如果没有设置 .gitattributes 的话 - 所以这样的调整值得一试。

技巧1: 稀疏检出
一个温和的管理二进制资产问题的方法是稀疏检出(从 Git 1.7.0 之后可用)。我们可以通过显式地详细说明要填充的文件夹来保持工作目录的清洁。

不幸的是,它并不能影响整个本地存储库的大小,但如果你有一个巨大的树形文件夹,这可能是有用的。

涉及到哪些命令呢? 示例如下(credit):
  • 仅克隆全部存储库一次::git clone <repository-address>
  • 激活以下功能:git config core.sparsecheckout true
  • 添加那些需要显式依赖的文件夹,忽略 assets 文件夹:
  • 读取指定的树目录:git read-tree -m -u HEAD
之后,你可以使用正常的 git 命令了,但你的工作目录将只包含你指定的文件夹。

技巧2:使用子模块
git 中处理二进制资产的第3个选择依靠第三方扩展。

我要说的第一个扩展是 git-annex,它可以使用 git 管理二进制文件,但不需要把文件内容检入库中。

git-annex 使用一个特殊的键值库来保存文件,然后将符号链接像普通文件一样检入 git 库中进行版本管理。这种用法非常直接,还有一看就能明白的例子。

第二个扩展是 git-bigfiles,一个 git 分支,适合于使用 git 分享项目大文件的人。

总结
不要因为你的库有着巨大的历史记录或巨大的资产就放弃 git。这两个问题都可以得到解决。

原文:How to Handle Big Repositories With Git
  • 大小: 1.5 KB
  • 大小: 3.9 KB
  • 大小: 2.3 KB
  • 大小: 2.1 KB
来自: 开源中国
0
0
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • C#学习(十一)——IntPtr类型

    1.C#中的IntPtr类型被称之为“平台特定的整数类型”,用于本机资源,例如窗口句柄。 2.资源的大小取决于使用的硬件和操作系统,即此类型的实例在32位硬件和操作系统中将是32位,在64位硬件和操作系统中将是64位;但其大小总是足以包含系统的指针(因此也可以包含资源的名称)。 3.在调用API函数时,类似含有窗口句柄参数(HANDLE)的原型函数,应显示地声明为IntPtr类型。 4.IntPtr类型对多线程操作是安全的。 5. int 和IntPtr互转 int i=1; IntPtr p=new I

  • C#学习之IntPtr类型

    C#中的IntPtr类型称为“平台特定的整数类型”,它们用于本机资源,如窗口句柄。资源的大小取决于使用的硬件和操作系统,但其大小总是足以包含系统的指针(因此也可以包含资源的名称)。 所以,在您调用的API函数中一定有类似窗体句柄这样的参数,那么当您声明这个函数时,您应该将它显式地声明为IntPtr类型。 例如,在一个C#程序中调用Win32API mciSendString函数控制光盘驱动

  • C# 中的 IntPtr

    这两个示例展示了如何在 C# 和 C++ 中分别创建和释放IntPtr。在示例1中,IntPtr是在托管环境中创建并释放的,而在示例2中,IntPtr是在非托管环境中创建并释放的。

  • 初识IntPtr

    一:什么是IntPtr 先来看看MSDN上说的:用于表示指针或句柄的平台特定类型。这个其实说出了这样两个事实,IntPtr 可以用来表示指针或句柄、它是一个平台特定类型。对于它的解释,这个哥们写的比较好:It's a classthat wraps a pointer that is used when calling Windows API functions. The underlying pointer may be 32 bit or 64 bit, depending on the platf.

  • C#中IntPtr

    System.Object System.ValueType System.IntPtr 1.C#中的IntPtr类型被称之为“平台特定的整数类型”,用于本机资源,例如窗口句柄。 2.资源的大小取决于使用的硬件和操作系统,即此类型的实例在32位硬件和操作系统中将是32位,在64位硬件和操作系统中将是64位;但其大小总是足以包含系统的指针...

  • C++ intptr_t类型

    一、intptr_t类型 intptr_t 和uintptr_t 类型用来存放指针地址。它们提供了一种可移植且安全的方法声明指针,而且和系统中使用的指针长度相同,对于把指针转化成整数形式来说很有用,下面是这个类型的声明 #if __WORDSIZE == 64 # ifndef __intptr_t_defined typedef long int intptr_t; # define __intptr_t_defined # endif typedef unsigned l

  • C# IntPtr类型转换

    C#调用C++DLL,指针

  • C#指针(内存地址)IntPtr

    IntPtr结构体全称为Integer Pointer,指针变量,主要用来保存寄存器起始地址的指针,如分配大内存的代码,并且可以进行指针偏移处理

  • intptr_t 其实不是指针类型

    最近在看nginx源码,看到有一个类型intptr_t,没有见过,google了一下,有人说是指针类型,但是看nginx源码中对该类型变量的使用,好像不是指针类型。 static ngx_int_t 667 ngx_get_options(int argc, char *const *argv) 668 { 669 u_char *p; 670 ngx_int

  • 数组指针与指针数组

    数组指针与指针数组 0.开篇语 &nbsp;&nbsp;是不是傻傻分不清数组指针与指针数组?请耐心看完这篇博客,或许可以帮助你理解指针数组与数组指针。 1.预备知识 一维数组的定义与初始化 二维数组的定义与初始化 typedef的使用实例 1.1 一维数组的定义与初始化 //定义一个整型的一维数组 //方式1:不指定元素个数,直接进行初始化,数组的大小由初始化数字个数确定 int arr...

  • IntPtr是什么,该怎么用

      IntPtr用于表示指针或句柄的平台特定类型,此类型对多线程操作是安全的。C#中的IntPtr类型称为“平台特定的整数类型”,它们用于本机资源,如窗口句柄。资源的大小取决于使用的硬件和操作系统,但其大小总是足以包含系统的指针(因此也可以包含资源的名称)。 所以,在调用的API函数中一定有类似窗体句柄这样的参数,那么当声明这个函数时,应该将它显式地声明为IntPtr类型。  IntPtr 类型被

  • IntPtr与自定义结构互转

    //IntPtr转自定义结构 struct onlydata { IntPtr hwnd; }; onlydata pd=new onlydata(); IntPtr pd; pd=Marshal.PtrToStructure(pd,typeof(onlydata)); //自定义结构转IntPtr Marshal.StructureToPtr(data,pd,true);

  • C++调用python程序报错:error C2371: intptr_t重定义;不同的基类型

    1.报错信息 环境配置:VS2012+Anaconda3(python3.7.0) error C2371: intptr_t重定义;不同的基类型 error C2371: uintptr_t重定义;不同的基类型 报错头文件为:inttypes.h 2.问题分析 怀疑是软件版本的问题,于是安装了VS2015,同样的程序没有报错,还真是版本匹配的问题。 再搜索inttypes.h文件发现VS2015的库目录下面并没有这个文件,应该是在新版本软件(VS2015或python3)的库文件中已经包含了它的功能,于是

  • C#中的IntPtr

    IntPtr是一个类,用于包装调用WindowsAPI函数的指针,根据平台的不同,底层指针可以是32位或64位;它用以表示指针或句柄的平台特定类型,C#中主要用它调用C++\C封装的DLl库;下面主要介绍IntPtr的常见用法 1.int类型与IntPtr类型之间的转换 using System; using System.Collections.Generic; using Syst...

  • C#中的IntPtr使用

     C#中的IntPtr类型称为“平台特定的整数类型”,它们用于本机资源,如窗口句柄。 资源的大小取决于使用的硬件和操作系统,但其大小总是足以包含系统的指针(因此也可以包含资源的名称)。 所以,在您调用的API函数中一定有类似窗体句柄这样的参数,那么当您声明这个函数时,您应该将它显式地声明为IntPtr类型。 例如,在一个C#程序中调用Win32API mciSendString函数控制光盘驱动

Global site tag (gtag.js) - Google Analytics