阅读更多

0顶
0踩

行业应用

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

2017-03-27 16:19 by 副主编 jihong10102006 评论(0) 有6992人浏览
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是什么?怎么用?

    在C#编程中,当调用C++写的dll时,有时会用到IntPtr,那IntPtr是什么,又怎么用呢?

  • 使用intptr_t和uintptr_t

    今天在看代码时,发现将之一个指针赋值给一个intptr_t类型的变量。由于之前没有见过intptr_t这样数据类型,凭感觉认为intptr_t是int类型的指针。感觉很奇怪,为何要将一个指针这样做呢?如是果断上网查查,发现我的感觉是错误的,所以,任何事情不能凭感觉,要弄清楚来龙去脉。

  • 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

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

  • C#中的IntPtr类型(指针等用)

    c#中无法将类型“int”隐式转换为“System.IntPtr” 这个是我引用了一个api函数时出现的问题,我在声明中把intptr换成了int还是不可以,这是为什么呢?要如何处理呢?   答: 您好,C#中的IntPtr类型称为“平台特定的整数类型”,它们用于本机资源,如窗口句柄。 资源的大小取决于使用的硬件和操作系统,但其大小总是足以包含系统的指针

  • C# IntPtr转byte数组、byte[]转Intptr、IntPtr转byte[]、IntPtr转换为raw数据、Marshal.Copy方法

    C# IntPtr转byte数组、byte[]转Intptr、IntPtr转换为raw数据、Marshal.Copy方法

  • 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类型

    本文转自:http://zhidao.baidu.com/question/22825956.html 问: c#中无法将类型“int”隐式转换为“System.IntPtr” 这个是我引用了一个api函数时出现的问题,我在声明中把intptr换成了int还是不可以,这是为什么呢?要如何处理呢?   答: 您好,C#中的IntPtr类型称为“平台特定的整数类型”

  • 数组指针与指针数组

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

  • IntPtr类型

    IntPtr结构用于表示指针或句柄的平台特定类型。 [SerializableAttribute] [ComVisibleAttribute(true)] public struct IntPtr : ISerializable IntPtr 类型被设计成整数,其大小适用于特定平台。即是说,此类型的实例在 32 位硬件和操作系统中将是 32 位,在 64 位硬件和操...

  • IntPtr是什么,该怎么用

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

  • Python代码学习笔记1

    今天开始写第一篇博客,主要是在学习Python中碰到的一些问题。 学习Python的教程是Mark Lutz 的Learning Python 和 Programming Python。代码大部分都是书上的例子。

  • IntPtr 转 string

    假设有 intPtrpBuffer 方法一: 直接使用Marshal.PtrToStringAnsi方法: string ss = Marshal.PtrToStringAnsi(pBuffer); 但,如果pBuffer中有\0,此方法所获取的字符串会被截断。这种情况要用方法二。 方法二: 先转为byte数组,然后再转string: byte[] cc = ...

  • c++与python 数据类型对应

    c++与python 数据类型对应

  • intptr_t 与指针的区别

    intptr_t在/usr/include/stdint.h文件中定义了 typedef int intptr_t; intptr_t定义的目的是为了保持地址,它与指针保存的值一样 相同点 两者保存的值一样,都是指向某个内存空间的地址值 区别 指针:能访问地址指向的内存空间 intptr_t:只是保持地址值,不能访问地址指向的内存空间 ...

  • 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)的库文件中已经包含了它的功能,于是

Global site tag (gtag.js) - Google Analytics