You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Git命令行获取指定提交新增Blob哈希及分支首次出现Blob?

解答你的Git Blob哈希获取问题

一、先明确git diff-tree的输出含义

你观察的没错!git diff-tree输出的每一行里,第3个哈希是旧版本的Blob对象,第4个是新版本的Blob对象。比如你示例里的:100644 100644 03f15b5... 6e0ed0b... M file1.ts,就是说file1.ts在这次提交中从旧Blob 03f15b5... 更新到了新Blob 6e0ed0b...。

补充个小细节:如果是新增文件,旧Blob会是全0的哈希(0000000000000000000000000000000000000000);如果是删除文件,新Blob会是全0哈希。

二、获取单个提交对应的Blob哈希列表

如果你只需要拿到某个提交中所有存在的Blob对象(不管是新增还是修改后的),可以用git ls-tree命令,加上递归参数就能遍历所有文件:

git ls-tree -r --name-only --object-only <commit-hash>

参数说明:

  • -r:递归处理子目录,不会漏掉文件夹里的文件
  • --name-only:只输出Blob哈希(默认会带文件名,加这个就只保留哈希)
  • --object-only:确保只输出Blob对象,排除目录对应的tree对象

如果只想拿到该提交相对于父提交新增/更新的Blob(也就是这次提交引入的新Blob),可以用git diff-tree过滤出有效新Blob:

git diff-tree --no-commit-id -r <commit-hash> | awk '$4 != "0000000000000000000000000000000000000000" {print $4}'

这里-r是递归展开目录,不然像some_folder这种tree对象不会拆成里面的Blob;awk用来排除删除操作的全0哈希。

三、实现你的最终需求:收集分支上首次出现的Blob哈希

你的需求是按提交顺序遍历分支,收集首次出现的Blob哈希,输出B:<hash>格式。这里给你两种可行方案:

方案1:先输出所有Blob再去重(你可接受的简易方案)

直接把所有提交的Blob按顺序输出,再用awk自动去重,只保留首次出现的内容:

git rev-list --reverse <branch> | while read commit; do
    git ls-tree -r --object-only "$commit" | sed "s/^/B:/"
done | awk '!seen[$0]++'

步骤拆解:

  1. git rev-list --reverse <branch>按时间从早到晚输出分支的所有提交
  2. 遍历每个提交,用git ls-tree输出所有Blob哈希,并用sed加上B:前缀
  3. awk '!seen[$0]++'会记住已经输出过的行,只保留第一次出现的内容,自动完成去重

方案2:更高效的增量追踪方式

如果分支历史很长,方案1会重复处理大量已出现的Blob,效率偏低。可以优化成每次只对比当前提交和父提交,提取父提交里没有的新增Blob:

# 处理分支的第一个提交(无父提交,所有Blob都是首次出现)
first_commit=$(git rev-list --reverse <branch> | head -n1)
git ls-tree -r --object-only "$first_commit" | sed "s/^/B:/"

# 处理后续提交,对比父提交提取新增Blob
git rev-list --reverse <branch> | tail -n +2 | while read commit; do
    parent_commit=$(git rev-parse "$commit^")
    # 找出当前提交独有的Blob(父提交没有的)
    comm -23 <(git ls-tree -r --object-only "$commit" | sort) <(git ls-tree -r --object-only "$parent_commit" | sort) | sed "s/^/B:/"
done

步骤拆解:

  1. 先处理分支的第一个提交,它的所有Blob都是首次出现
  2. 对后续每个提交,用comm -23对比它和父提交的Blob列表,筛选出当前提交独有的Blob(也就是新增的)
  3. 同样加上B:前缀输出,全程只处理新增内容,效率更高

额外小调整(如果需要关联提交哈希)

看你示例里有C:<hash>的格式,如果你需要记录每个Blob首次出现的提交哈希,可以修改脚本如下:

declare -A seen  # 用哈希表记录Blob是否已出现
git rev-list --reverse <branch> | while read commit; do
    git ls-tree -r --object-only "$commit" | while read blob; do
        if [ -z "${seen[$blob]}" ]; then
            echo "C:$commit"
            echo "B:$blob"
            seen[$blob]=$commit
        fi
    done
done

这样会同时输出Blob首次出现的提交哈希和Blob哈希,按需选用即可。

内容的提问来源于stack exchange,提问作者Daniel K.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:24:37