如何在git历史记录中查找/识别大型提交?

633

我有一个300MB的git仓库。当前检出文件的总大小为2MB,剩余git仓库的总大小为298MB。这基本上是一个仅包含代码的仓库,不应该超过几MB。

我怀疑有人意外提交了一些大文件(视频、图片等),然后将它们删除……但没有从git中删除,因此历史记录仍包含无用的大文件。如何在git历史中找到这些大文件?由于有400多个提交,逐个查找不太实际。

注意:我的问题不涉及如何删除文件,而是如何首先找到它。


6
@raphinesse 的那个一行代码的回答应该被标记为答案,因为它非常快。 - soloturn
14个回答

3

使用 --analyze 特性,就像下面这样使用git-filter-repo

$ cd my-repo-folder
$ git-filter-repo --analyze
$ less .git/filter-repo/analysis/path-all-sizes.txt

3
我无法使用最流行的答案,因为我必须使用的Git 1.8.3命令行开关--batch-check不接受任何参数。下面的步骤在CentOS 6.5和Bash 4.1.2上尝试过。
关键概念
在Git中,“blob”一词意味着文件的内容。请注意,提交可能会更改文件或路径名的内容。因此,同一文件根据提交的不同可能指代不同的blob。某个文件在一个提交中可能是目录层次结构中最大的文件,而在另一个提交中则不是。因此,寻找大型提交而不是大型文件将问题放在正确的角度。
对于心急的人
按大小降序打印blob列表的命令是:
git cat-file --batch-check < <(git rev-list --all --objects  | \
awk '{print $1}')  | grep blob  | sort -n -r -k 3

输出示例:

3a51a45e12d4aedcad53d3a0d4cf42079c62958e blob 305971200
7c357f2c2a7b33f939f9b7125b155adbd7890be2 blob 289163620

要删除这些 blob,可以使用其他答案中提到的 BFG Repo Cleaner。假设有一个名为 blobs.txt 的文件,其中仅包含 blob 哈希值,例如:
3a51a45e12d4aedcad53d3a0d4cf42079c62958e
7c357f2c2a7b33f939f9b7125b155adbd7890be2

请做:

java -jar bfg.jar -bi blobs.txt <repo_dir>

这个问题是关于查找提交记录的,比查找Blobs工作量更大。想要了解,请继续阅读。

进一步工作

给定一个提交记录哈希值,一个打印与其相关联的所有对象哈希值(包括Blobs)的命令为:

git ls-tree -r --full-tree <commit_hash>

因此,如果我们能够对存储库中的所有提交进行这样的输出,那么给定一个 blob hash,一堆提交是与任何输出相匹配的。这个想法被编码在以下脚本中:

#!/bin/bash
DB_DIR='trees-db'

find_commit() {
    cd ${DB_DIR}
    for f in *; do
        if grep -q $1 ${f}; then
            echo ${f}
        fi
    done
    cd - > /dev/null
}

create_db() {
    local tfile='/tmp/commits.txt'
    mkdir -p ${DB_DIR} && cd ${DB_DIR}
    git rev-list --all > ${tfile}

    while read commit_hash; do
        if [[ ! -e ${commit_hash} ]]; then
            git ls-tree -r --full-tree ${commit_hash} > ${commit_hash}
        fi
    done < ${tfile}
    cd - > /dev/null
    rm -f ${tfile}
}

create_db

while read id; do
    find_commit ${id};
done

如果内容保存在名为find-commits.sh的文件中,则典型的调用方式如下:
cat blobs.txt | find-commits.sh

如前所述,文件blobs.txt列出了每行一个的blob哈希值。函数create_db()在当前目录下的一个子目录中保存了所有提交列表的缓存。

以下是我在一台安装了两个Intel(R) Xeon(R) CPU E5-2620 2.00GHz处理器且被操作系统表示为24个虚拟核心的系统上进行实验得到的一些统计数据:

  • 仓库中的提交总数 = 近11,000个
  • 文件创建速度 = 126个文件/秒。该脚本每次提交都会创建单个文件,这只会在首次创建缓存时发生。
  • 缓存创建开销 = 87秒
  • 平均搜索速度 = 522个提交/秒。缓存优化导致运行时间缩短了80%。

请注意,该脚本是单线程的。因此,在任何时候只能使用一个核心。


0
我和其他人一样,也是因为同样的原因偶然发现了这个。但是引用的脚本对我来说并不完全有效。我制作了一个更加混合的脚本,它现在存放在这里 - https://gitlab.com/inorton/git-size-calc

-2

为了感受 git 历史中最后几次提交的“差异大小”

git log --stat

这将显示行数的差异大小:添加的行,删除的行


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接