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

如何高效检查Git工作树、暂存区、本地与远程仓库状态一致?

多设备Git仓库一致性检查脚本优化

我常在多台电脑上操作同一批Git仓库,工作前后会运行脚本检查仓库是否存在未暂存(unstaged)、未提交(uncommitted)、未推送(unpushed)或未拉取(unpulled)的内容,用标准Git术语来说,就是要确保本地的工作树(work tree)= 暂存区(staging area)= 本地仓库(local repo)= 远程仓库(remote repo)。

原脚本及问题

原脚本通过环境变量GITS_DB指向记录所有Git仓库目录的文本文件,可实现上述检查功能,但运行速度偏慢,即使网络状态良好也是如此。原脚本代码如下:

#!/bin/bash

RED='\033[0;31m'
NC='\033[0m' # no color

for g in $(< ${GITS_DB})
do
    (
        cd ${g}
        git fetch --all &> /dev/null|| \
            echo "warning: unable to fetch ${g}, getting local status"
        if [ $(git status --porcelain | wc -l) != "0" \
            -o $(git rev-list HEAD@{upstream}..HEAD | wc -l) != "0" \
            -o $(git rev-list HEAD..HEAD@{upstream} | wc -l) != "0" ];  then
            echo -e "${RED}${g} is not clean${NC}"
        fi
    )
done

优化思路与最终方案

我尝试将脚本中两个rev-list命令替换为直接对比HEAD与HEAD@{upstream}的SHA-1值,简化远程与本地仓库的一致性判断:

$(git rev-parse --verify HEAD) != $(git rev-parse --verify HEAD@{upstream})

之后结合建议优化出两个脚本,将运行时间从约2分钟缩短至5-7秒:

脚本1:生成标记仓库类型的文件

该脚本会遍历系统中的Git仓库,标记每个仓库是顶级仓库还是子模块,并将结果写入GITS_DB指定的文件:

#!/bin/bash

# 检查环境变量GITS_DB是否存在
if [[ -z "$GITS_DB" ]];
then
    echo "Environment variable GITS_DB has no value, exiting..."
    exit 1
fi

# 创建GITS_DB所在目录(如果不存在)
GITS_DIR=`dirname $GITS_DB`
mkdir -p ${GITS_DIR}

# 删除旧的仓库列表文件
if [ -e ${GITS_DB} ];
then
    rm ${GITS_DB}
fi

# 创建空的仓库列表文件
touch ${GITS_DB}

# 按路径长度倒序遍历所有.git目录,避免重复处理子模块
for REPO_DOT_GIT in `find $HOME -name '.git' -printf "%d %p\n" | sort -nr | awk '{ print $2 }'`
do
    REPO_DIR=`dirname ${REPO_DOT_GIT}`
    (
        cd ${REPO_DIR}
        # 判断是否为子模块
        if [[ $(git rev-parse --show-superproject-working-tree) ]];
        then
            REPO_TYPE=s # s代表子模块
        else
            REPO_TYPE=t # t代表顶级仓库
        fi
        printf "%c %s\n" "${REPO_TYPE}" "${REPO_DIR}" >> ${GITS_DB}
    )
done

脚本2:并行拉取+一致性检查

该脚本会并行拉取所有顶级仓库及其子模块,然后逐一检查每个仓库的清洁度:

#!/bin/bash

RED='\033[0;31m'
NC='\033[0m' # 重置颜色

# 并行拉取所有顶级仓库及子模块
while read TYPE DIR;
do
    if [[ "${TYPE}" == "t" ]];
    then
        (
            cd ${DIR}
            # 递归拉取子模块时启用并行(20个任务)
            git -c submodule.fetchJobs=20 fetch -q --all --recurse-submodules=yes ||
                {
                    echo -e "${RED}无法拉取${DIR}或其子模块,退出${NC}";
                    exit 1
                }
        ) &
    fi
done < ${GITS_DB}
wait # 等待所有并行拉取任务完成

# 逐一检查每个仓库的清洁度
while read TYPE DIR;
do
    (
        cd ${DIR}
        # 检查工作区/暂存区是否有变更,或本地与远程提交是否不一致
        if [[ $(git status --porcelain) ||
             $(git rev-parse --verify HEAD) != $(git rev-parse --verify HEAD@{upstream}) ]];
        then
            echo -e "${RED}${DIR}状态不一致${NC}"
        fi
    )
done < ${GITS_DB}

内容的提问来源于stack exchange,提问作者jhu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 00:57:47