每个分支的Git磁盘使用情况

时间:2012-12-05 11:17:59

标签: git diskspace

您知道是否有办法列出每个分支的git存储库的空间使用情况? (例如dfdu

对于分支的“空间使用”,我指的是“尚未与存储库的其他分支共享的提交所使用的空间”。

7 个答案:

答案 0 :(得分:7)

这没有正确的答案。如果查看仅包含在特定分支中的提交,您将获得一个blob列表(基本上是文件版本)。现在,您必须检查这些blob是否是其他分支中任何提交的一部分。完成后,您将获得仅作为分支的一部分的blob列表。

现在你可以总结这些blob的大小来得到结果 - 但这可能是非常错误的。 Git将这些blob相互压缩,因此blob的实际大小取决于repo中的其他blob。你可以删除1000个blob,每个10MB,只释放1kb的磁盘空间。

通常一个大的回购大小是由回购中的单个大文件引起的(如果没有,你可能做错了:)。有关如何查找这些内容的信息,请访问:Find files in git repo over x megabytes, that don't exist in HEAD

答案 1 :(得分:3)

存储库的大部分空间都由包含文件的blob占用。

但是当一个blob由两个分支(或两个具有相同内容的文件)共享时,它不会重复。存储库的大小不能被视为分支大小的总和。没有像分支所占空间这样的概念。

并且有很多压缩能够节省小文件修改的空间。

通常切断分支只会释放一个非常小的,不可预测的空间。

答案 2 :(得分:3)

似乎没有类似的东西已经存在,这里是我为此做的Ruby脚本。

#!/usr/bin/env ruby -w
require 'set'

display_branches = ARGV

packed_blobs = {}

class PackedBlob
    attr_accessor :sha, :type, :size, :packed_size, :offset, :depth, :base_sha, :is_shared, :branch
    def initialize(sha, type, size, packed_size, offset, depth, base_sha)
        @sha = sha
        @type = type
        @size = size
        @packed_size = packed_size
        @offset = offset
        @depth = depth
        @base_sha = base_sha
        @is_shared = false
        @branch = nil
    end
end

class Branch
    attr_accessor :name, :blobs, :non_shared_size, :non_shared_packed_size, :shared_size, :shared_packed_size, :non_shared_dependable_size, :non_shared_dependable_packed_size
    def initialize(name)
        @name = name
        @blobs = Set.new
        @non_shared_size = 0
        @non_shared_packed_size = 0
        @shared_size = 0
        @shared_packed_size = 0
        @non_shared_dependable_size = 0
        @non_shared_dependable_packed_size = 0
    end
end

dependable_blob_shas = Set.new

# Collect every packed blobs information
for pack_idx in Dir[".git/objects/pack/pack-*.idx"]
    IO.popen("git verify-pack -v #{pack_idx}", 'r') do |pack_list|
        pack_list.each_line do |pack_line|
            pack_line.chomp!
            if not pack_line.include? "delta"
                sha, type, size, packed_size, offset, depth, base_sha = pack_line.split(/\s+/, 7)
                size = size.to_i
                packed_size = packed_size.to_i
                packed_blobs[sha] = PackedBlob.new(sha, type, size, packed_size, offset, depth, base_sha)
                dependable_blob_shas.add(base_sha) if base_sha != nil
            else
                break
            end
        end
    end
end

branches = {}

# Now check all blobs for every branches in order to determine whether it's shared between branches or not
IO.popen("git branch --list", 'r') do |branch_list|
    branch_list.each_line do |branch_line|
        # For each branch
        branch_name = branch_line[2..-1].chomp
        branch = Branch.new(branch_name)
        branches[branch_name] = branch
        IO.popen("git rev-list #{branch_name}", 'r') do |rev_list|
            rev_list.each_line do |commit|
                # Look into each commit in order to collect all the blobs used
                for object in `git ls-tree -zrl #{commit}`.split("\0")
                    bits, type, sha, size, path = object.split(/\s+/, 5)
                    if type == 'blob'
                        blob = packed_blobs[sha]
                        branch.blobs.add(blob)
                        if not blob.is_shared
                            if blob.branch != nil and blob.branch != branch
                                # this blob has been used in another branch, let's set it to "shared"
                                blob.is_shared = true
                                blob.branch = nil
                            else
                                blob.branch = branch
                            end
                        end
                    end
                end
            end
        end
    end
end

# Now iterate on each branch to compute the space usage for each
branches.each_value do |branch|
    branch.blobs.each do |blob|
        if blob.is_shared
            branch.shared_size += blob.size
            branch.shared_packed_size += blob.packed_size
        else
            if dependable_blob_shas.include?(blob.sha)
                branch.non_shared_dependable_size += blob.size
                branch.non_shared_dependable_packed_size += blob.packed_size
            else
                branch.non_shared_size += blob.size
                branch.non_shared_packed_size += blob.packed_size
            end
        end
    end
    # Now print it if wanted
    if display_branches.empty? or display_branches.include?(branch.name)
        puts "branch: %s" % branch.name
        puts "\tnon shared:"
        puts "\t\tpacked: %s" % branch.non_shared_packed_size
        puts "\t\tnon packed: %s" % branch.non_shared_size
        puts "\tnon shared but with dependencies on it:"
        puts "\t\tpacked: %s" % branch.non_shared_dependable_packed_size
        puts "\t\tnon packed: %s" % branch.non_shared_dependable_size
        puts "\tshared:"
        puts "\t\tpacked: %s" % branch.shared_packed_size
        puts "\t\tnon packed: %s" % branch.shared_size, ""
    end
end

通过那个,我能够看到在我的2Mo git存储库中,我有一个无用的分支,它带走了1Mo blob,不与任何其他分支共享。

答案 3 :(得分:2)

Git维护一个有向提交的非循环图,(简单来说)每个提交使用磁盘空间。

除非你的所有分支都与第一次提交不同,否则会有各种分支共有的提交,这意味着每个分支“共享”一定数量的磁盘空间。

这使得很难提供“每个分支”的磁盘使用数字,因为它需要通过共享的数量以及与其共享的其他分支进行限定。

答案 4 :(得分:1)

今天早上我遇到了同样的问题,写了一个快速的脚本:

for a in $(git branch -a | grep remotes | awk '{print $1}' | sed 's/remotes\/origin\///'); do echo -n ${a} -\ ; git clean -d -x -f > /dev/null 2>&1 ;git checkout ${a} > /dev/null 2>&1; du -hs -I .git .;done

这将在重置其内容后检出每个远程分支,以确保我们干净地检查它。然后它将显示没有.git目录的大小。

通过这个,我找到了推动一个大文件的分支的人。

请记住在另一个克隆目录中执行此操作,因为它会清除所有未提交的内容

答案 5 :(得分:1)

在 git 2.3.1 中它支持 --disk-usage

# reachable objects
git rev-list --disk-usage --objects --all

https://git-scm.com/docs/git-rev-list#_examples

答案 6 :(得分:-1)

我以残酷的方式做到了。在 GitHub 上选择分支,下载 Zip 并查看它有多大。