Git Diff结果缓存及多参数查询高效实现方案咨询
提升Git Diff重复调用速度的方案
针对你的问题,我分两部分来具体解答:
一、通过缓存提升重复调用速度
Git本身并没有内置专门针对不同git diff参数的缓存机制——不过因为Git的对象数据库是本地存储且基于哈希校验的,如果你重复执行完全相同的git diff命令(相同commit对、相同参数),Git会直接复用已计算的对象对比结果,速度本来就很快。但如果是不同参数的重复调用(比如你需要的两种--shortstat变体),Git还是会重新扫描差异并过滤结果,这时候我们可以自己实现简单的缓存逻辑。
你可以写一个简单的shell脚本,把不同参数的diff结果缓存到本地文件,用commit哈希和命令参数的组合作为缓存键。举个例子:
#!/bin/bash # 定义缓存目录,可自行修改 CACHE_DIR="$HOME/.git-diff-cache" COMMIT1="$1" COMMIT2="$2" # 创建缓存目录(如果不存在) mkdir -p "$CACHE_DIR" # 生成缓存键:基于commit对和参数的哈希值 generate_key() { echo "$COMMIT1 $COMMIT2 $1" | sha256sum | awk '{print $1}' } # 获取并缓存总统计结果 get_full_stat() { KEY=$(generate_key "full") CACHE_FILE="$CACHE_DIR/$KEY" if [ -f "$CACHE_FILE" ] && [ "$(find "$CACHE_FILE" -mmin -60)" ]; then # 缓存未过期(这里设为60分钟,可调整) cat "$CACHE_FILE" else git diff --shortstat "$COMMIT1" "$COMMIT2" > "$CACHE_FILE" cat "$CACHE_FILE" fi } # 获取并缓存仅AD的统计结果 get_ad_stat() { KEY=$(generate_key "ad") CACHE_FILE="$CACHE_DIR/$KEY" if [ -f "$CACHE_FILE" ] && [ "$(find "$CACHE_FILE" -mmin -60)" ]; then cat "$CACHE_FILE" else git diff --diff-filter=ad --shortstat "$COMMIT1" "$COMMIT2" > "$CACHE_FILE" cat "$CACHE_FILE" fi } # 输出结果 echo "总统计结果:" get_full_stat echo -e "\n仅添加/删除的统计结果:" get_ad_stat
这个脚本会自动缓存两种命令的结果,且设置了60分钟的过期时间(避免仓库更新后缓存失效),重复调用时直接读取缓存文件,速度会快很多。
二、用单次Git调用推导两种结果
如果你不想维护缓存,还有更高效的方式:用git diff --numstat一次获取所有文件的差异细节,然后通过脚本统计得到你需要的两种--shortstat结果。这样只需要执行一次Git命令,就能推导两个结果,成本更低。
git diff --numstat的输出格式为(每行对应一个文件的差异):
添加行数 删除行数 文件名
对于新增文件,删除行数为-;对于删除文件,添加行数为-;重命名的文件会显示为旧文件名 -> 新文件名。
我们可以用awk脚本处理这个输出,同时计算总统计和AD过滤后的统计:
#!/bin/bash COMMIT1="$1" COMMIT2="$2" # 执行一次git diff获取所有差异数据,然后用awk统计 git diff --numstat "$COMMIT1" "$COMMIT2" | awk ' BEGIN { total_files = 0; total_ins = 0; total_del = 0; ad_files = 0; ad_ins = 0; ad_del = 0; } { # 处理重命名行(包含"->"),算一个文件变化 if ($0 ~ /->/) { total_files +=1; # 重命名状态为R,不在AD过滤范围内,所以AD统计不计数 } else { total_files +=1; ins = ($1 == "-") ? 0 : $1; del = ($2 == "-") ? 0 : $2; total_ins += ins; total_del += del; # 判断是否是添加(A)或删除(D)的文件 if ($1 != "-" && $2 == "-") { # 新增文件 ad_files +=1; ad_ins += ins; } else if ($1 == "-" && $2 != "-") { # 删除文件 ad_files +=1; ad_del += del; } } } END { # 输出总统计(模拟--shortstat格式) printf "总统计:%d file%s changed, %d insertion%s(+), %d deletion%s(-)\n", total_files, (total_files !=1 ? "s" : ""), total_ins, (total_ins !=1 ? "s" : ""), total_del, (total_del !=1 ? "s" : ""); # 输出AD过滤后的统计 printf "仅添加/删除:%d file%s changed, %d insertion%s(+), %d deletion%s(-)\n", ad_files, (ad_files !=1 ? "s" : ""), ad_ins, (ad_ins !=1 ? "s" : ""), ad_del, (ad_del !=1 ? "s" : ""); } '
这个脚本只需要执行一次git diff --numstat,就能同时得到你需要的两种统计结果,避免了两次Git调用的开销,对于大仓库来说效率提升很明显。
内容的提问来源于stack exchange,提问作者ARF




