【问题标题】:Are there any good workarounds to the GitHub 100MB file size limit for text files?文本文件的 GitHub 100MB 文件大小限制有什么好的解决方法吗?
【发布时间】:2016-04-15 21:26:19
【问题描述】:

我想在 github 上跟踪一个 190 MB 的纯文本文件。

文本文件是我们的文本转语音引擎的发音词典文件。我们会定期在文本文件中添加和修改行,并且差异很小,因此从这个意义上说,它非常适合 git。

但是,GitHub 有严格的 100 MB 文件大小限制。我已经尝试过 GitHub 大文件存储服务,但每次更改时都会上传整个 190 MB 文件的新版本 - 所以如果我走这条路,它会迅速增长到许多 GB。

我想将文件保留为 一个 文件而不是拆分它,因为这就是我们当前的工作流程,并且需要一些编码以允许多个文本文件作为我们工具中的输入/输出(而且我们没有太多的开发资源)。

我的一个想法是,也许可以设置一些提交前和提交后挂钩来自动拆分和连接大文件?这可能吗?

其他想法?

编辑:我知道 StackOverflow 上的类似问题中描述的 100 MB 文件大小限制,但我不认为我的问题重复,因为我要求的是具体情况差异小且频繁的地方(我不想上传大的 ZIP 文件或任何东西)。但是,我的理解是 git-lfs 仅适用于 很少 更改的文件,而普通的 git 将非常适合我所描述的那种文件;除了 GitHub 有文件大小限制。

更新:我昨天尝试创建一个小型跨平台程序,该程序使用 git 挂钩将文件拆分和连接成更小的文件。它有点工作,但不是很令人满意。您需要将您的大文本文件排除在 .gitignore 之外,这会使 git 不知道它是否已更改。 git statusgit commit 最初未检测到拆分文件,并导致与此 SO 问题中所述相同的问题,这很烦人:Pre-commit script creates mysqldump file, but "nothing to commit (working directory clean)"? 设置 cron 作业 (linux) 和计划任务 (windows) 以定期自动重新生成拆分文件可能会解决此问题,但自动设置并不容易,可能会导致用户计算机出现性能问题,而且不是很优雅解决方案。可能还需要一些 hacky 解决方案,例如动态修改 .gitignore,而且您绝不会得到实际文本文件的差异,只有拆分文件(尽管这可能是可以接受的,因为它们非常相似)。

所以,睡了之后,今天我认为 git hook 方法毕竟不是一个好的选择,因为它有太多的怪癖。正如@PyRulez 所建议的那样,我认为我将不得不查看 GitHub 以外的其他服务(不幸的是,因为我喜欢 github)。托管解决方案将更可取,以避免必须管理我们自己的服务器。我也希望它可以公开使用...

更新 2:我查看了 GitHub 的一些替代品,目前我倾向于使用 GitLab。我已经联系了 GitHub 支持以了解提高 100MB 限制的可能性,但如果他们不这样做,我会为这个特定项目切换到 GitLab。

【问题讨论】:

  • @Mayuso 我知道这听起来与其他问题相似,但这个问题是关于我有一个文本文件的具体情况,该文件有频繁但小的差异,如果这样可以解决 100 MB 的问题以某种方式限制。我知道二进制文件是不可能的。
  • 我想我没有很好地理解这个问题,已经回答了,对不起:)
  • 没问题:),我应该更清楚。
  • 也许使用 gitHub 以外的东西?

标签: git github large-files pre-commit-hook post-commit-hook


【解决方案1】:

清洁和涂抹

您可以使用 clean 和 smudge 来压缩文件。通常,这不是必需的,因为 git 会在内部压缩它,但由于 gitHub 的行为很奇怪,它可能会有所帮助。主要命令如下:

git config filter.compress.clean gzip
git config filter.compress.smudge gzip -d

GitHub 会将此视为压缩文件,但在每台计算机上,它会显示为文本文件。

更多详情请见https://git-scm.com/book/en/v2/Customizing-Git-Git-Attributes

或者,您可以将干净的帖子发布到在线粘贴箱,然后从粘贴箱中提取数据,例如http://pastebin.com/。清洁和涂抹还有许多其他组合。

【讨论】:

  • 有趣的解决方案,谢谢!这可能会使 190MB 小于 100MB。我假设 gzip 压缩的文件不会是可区分的,所以每次文件更改时,都会创建一个新文件。如果 gzip 从 190MB 压缩到大约 50MB,那么每次提交仍然是 50 新 MB。
  • @josteinaj 请参阅 git-scm.com/book/en/v2/… 了解如何正确区分它们。
  • @josteinaj git-scm.com/docs/gitattributes 对此答案有更深入的材料。
  • +1 这绝对是一个绝妙的答案!我只有一个 116MB 的文件。我添加了两个过滤器,然后将我需要压缩的单个文件命名为.gitattributes。优雅!
  • @pyrulez 你能提供更多关于你添加到 .gitattributes 文件的信息吗?
【解决方案2】:

一个很好的解决方案是使用:

https://git-lfs.github.com/

它是一个开放源代码,旨在处理大文件。

【讨论】:

  • 是的,我已经尝试过了,但是我经常对文本文件进行更改,因此它会经常在 LFS 中创建一个新的 190MB 文件。据我了解 LFS,它最适合很少更改的文件。
  • 我同意 GitHub 中的 git-lfs 运行良好。我遇到的问题是它有一个带宽限制,对于企业系统来说,它很快就会被超过和/或变得非常昂贵。他们不仅收取存储文件的费用,而且在带宽方面,每次让开发人员拉下您的 LFS 存储库或每次拉取时,您都需要付费。更糟糕的是,如果你有一个 CIS。想象一个构建系统,其二进制文件大小为 300MB,在发布之前您有 1300 个构建。每个构建都会拉下 Git LFS 存储库。你最终会让 GitHub 变得有点贵。
  • 很好,这正是我想要的!
【解决方案3】:

您可以创建任何语言的脚本/程序来分割或合并文件。

这里是分割用 Java 编写的文件的示例(我使用 Java 是因为我在 Java 上比其他任何方式都更舒服,但任何其他方式都可以,有些也会比 Java 更好)。

public static void main(String[] args) throws Exception
{
    RandomAccessFile raf = new RandomAccessFile("test.csv", "r");
    long numSplits = 10; //from user input, extract it from args
    long sourceSize = raf.length();
    long bytesPerSplit = sourceSize/numSplits ;
    long remainingBytes = sourceSize % numSplits;

    int maxReadBufferSize = 8 * 1024; //8KB
    for(int destIx=1; destIx <= numSplits; destIx++) {
        BufferedOutputStream bw = new BufferedOutputStream(new FileOutputStream("split."+destIx));
        if(bytesPerSplit > maxReadBufferSize) {
            long numReads = bytesPerSplit/maxReadBufferSize;
            long numRemainingRead = bytesPerSplit % maxReadBufferSize;
            for(int i=0; i<numReads; i++) {
                readWrite(raf, bw, maxReadBufferSize);
            }
            if(numRemainingRead > 0) {
                readWrite(raf, bw, numRemainingRead);
            }
        }else {
            readWrite(raf, bw, bytesPerSplit);
        }
        bw.close();
    }
    if(remainingBytes > 0) {
        BufferedOutputStream bw = new BufferedOutputStream(new FileOutputStream("split."+(numSplits+1)));
        readWrite(raf, bw, remainingBytes);
        bw.close();
    }
        raf.close();
}

static void readWrite(RandomAccessFile raf, BufferedOutputStream bw, long numBytes) throws IOException {
    byte[] buf = new byte[(int) numBytes];
    int val = raf.read(buf);
    if(val != -1) {
        bw.write(buf);
    }
}

这几乎不需要任何成本(时间/金钱)。

编辑:您可以创建一个 Java 可执行文件并将其添加到您的存储库中,或者更简单的是,创建一个 Python(或任何其他语言)脚本来执行此操作,并将其保存为纯文本您的存储库。

【讨论】:

  • 谢谢!你知道是否可以在提交前自动运行它并在签出后自动合并?
  • 查看 Unix/Linux splitcat 命令。 split -b 100M big-file big-file- ... cat big-file-* &gt; big-file
  • @KeithThompson 谢谢。我知道这些,但放弃了这个想法,因为我希望它也能在 Windows 中工作。但是,似乎 git 即使在 Windows 中也在 bash 环境中运行它的 git 钩子,所以这些命令也可能在那里工作,我不确定。它们肯定比我自己实现一些东西要简单得多(我在 golang 中创建了一个小程序进行测试)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-13
  • 2010-11-04
  • 1970-01-01
  • 2017-09-12
  • 1970-01-01
相关资源
最近更新 更多