有没有遇到过这种困扰?本地配置文件里藏着数据库密码、密钥等敏感信息,一不小心就提交到 Git 仓库了,既不安全又容易泄露隐私。
今天就给大家分享 Git 仓库脱敏方法,重点讲在开发过程中最实用的「Git 内置过滤器」方案------不用改代码、不用手动改配置,提交自动脱敏、拉取自动还原,全程无感操作。
一、先搞懂核心需求:本地能用,仓库安全
目标很简单:
- 本地开发时,能用到完整的配置(含敏感信息),不影响正常开发;
- 提交到 Git 仓库时,敏感信息自动变成占位符,不会泄露;
- 最好自动化,不用每次提交前手动改配置,省事。
💡提前划重点:
下面 3 种方法里,优先选「方法 3:Git 内置过滤器」。前两种适合已开发完的项目,过滤器方案适合正在开发的项目,零侵入还省心。
3 种脱敏方法对比
方法 1:创建配置模板文件(简单但繁琐)
比如,有个配置文件叫 settings.yaml,里面有敏感信息。做法很简单:
- 复制一份
settings.yaml,改名叫settings_example.yaml; - 手动把
settings_example.yaml里的敏感信息删掉(比如把密码改成xxxxxx),作为模板给团队参考; - 在
.gitignore里加一行settings.yaml,让 Git 忽略这个真实配置文件,避免提交。
缺点:每次新增配置项,都要手动同步模板文件,团队协作时容易漏更。
方法 2:把敏感信息存到环境变量(脱离项目但需额外配置)
核心思路:把密码、密钥这些敏感信息,存到电脑的「环境变量」里(和项目分开),项目里只留"占位符"。
举个例子, settings.yaml 可以写成这样:
yaml
database:
host: ${DB_HOST} # 占位符:本地环境变量里找 DB_HOST
username: ${DB_USER} # 占位符:本地环境变量里找 DB_USER
password: ${DB_PASSWORD} # 敏感密码:从环境变量读取
secret:
token_key: ${TOKEN_SECRET} # 密钥:从环境变量读取
缺点:每个开发者都要手动在自己电脑上配置环境变量,新成员加入时步骤多,容易配错。
方法 3:Git 内置过滤器(自动化首选)
这是 Git 自带的功能,相当于给配置文件加了"自动开关":
- 提交代码时(git add):触发
clean过滤器,自动把敏感信息换成占位符; - 拉取代码时(git pull):触发
smudge过滤器,自动把占位符换回本地的真实敏感信息。
优点:不用改项目代码、不用装额外工具,开发者完全不用管,提交/拉取全程自动处理,不影响开发效率。
二、自动化配置过滤器脚本(直接用)
手动配置过滤器步骤有点多,我写了个脚本,一键就能搞定所有配置。不想看手动步骤的朋友,直接用这个脚本就行!
当然,若读者对手动配置感兴趣,又或想了解脚本的工作原理,可跳过此部分,往后阅读:。
使用步骤(超简单)
- 打开你的 Git 项目根目录(就是和
.git文件夹同级的目录); - 新建一个文件,命名为
git_desensitize.sh; - 把下面的代码复制粘贴进去;
- 执行命令:
bash git_desensitize.sh,等待脚本执行完成。
后续在其他地方拉取项目,只需把原项目的 .git/config 文件复制过去,删除要复原的「需脱敏文件」(如之前的 settings.yaml),再执行 git checkout-index --all --force 就能恢复本地配置。

bash
#!/bin/bash
# ==============================================================
# Git 配置文件全自动脱敏脚本
# 使用说明:1.修改顶部【配置区】的files和fields
# 2.执行脚本:bash git_desensitize.sh
# 核心特性:一键生成clean/smudge过滤器 + 绑定.gitattributes
# ==============================================================
# ========== 【唯一配置区】 ==========
# 要脱敏的文件列表
files=(
"settings.yaml"
# "src/config/.env"
# "application.yml"
)
# 要脱敏的字段名列表
fields=(
"password"
"secret"
"issuer"
"addr"
"host"
"port"
"ip"
"domain"
"send_email"
"app_key"
"access_key"
"secret_key"
)
# ========== 【常量定义】 ==========
FILTER_NAME="auto_sensitive_filter" # Git过滤器名称
GIT_ATTRIBUTES=".gitattributes" # 绑定文件名称
BASE_PLACEHOLDER="******" # 占位符基础前缀
# ========== 【0.前置一键校验】 ==========
check_env(){
[ ! -d ".git" ] && echo -e "\033[31m请在Git项目根目录执行!\033[0m" && exit 1
[ ! $(command -v git) ] && echo -e "\033[31m未检测到Git环境!\033[0m" && exit 1
[ ! $(command -v sed) ] && echo -e "\033[31m未检测到sed命令!\033[0m" && exit 1
} && check_env
# ========== 【1.扫描提取敏感值+去重+生成映射】 ==========
echo -e "\n\033[36m===== 扫描目标文件,提取敏感值 =====\033[0m"
declare -A FIELD_COUNTER # 字段计数器:记录每个字段有效序号
declare -a VALUE_MAPPING # 核心映射表:存储 原始值|字段名|序号
declare -A DUPLICATE_CHECK_MAP # 去重校验MAP:key=字段名_原始值,实现双重去重
# 初始化字段计数器
for field in "${fields[@]}"; do
FIELD_COUNTER[$field]=0
done
# 遍历所有目标文件
for file in "${files[@]}"; do
if [ ! -f "$file" ]; then
echo -e "\033[33m文件 $file 不存在,跳过\033[0m"
continue
fi
# 遍历所有脱敏字段
for field in "${fields[@]}"; do
all_origin_values=$(sed -n "s/^[[:space:]]*${field}[[:space:]]*[:=][[:space:]]*["']*(.*)["']*[[:space:]]*$/\1/p" "$file")
# 遍历所有提取到的原始值
while IFS= read -r origin_value; do
if [ -z "$origin_value" ]; then
continue
fi
# 去重:字段名+原始值 作为KEY,完全一致则判定为重复
unique_check_key="${field}_${origin_value}"
if [[ -n "${DUPLICATE_CHECK_MAP[$unique_check_key]}" ]]; then
echo -e "\033[33m重复:$file -> $field = $origin_value\033[0m"
continue
fi
# 非重复数据:序号自增 + 标记去重KEY + 存入映射表
((FIELD_COUNTER[$field]++))
seq_num=${FIELD_COUNTER[$field]}
DUPLICATE_CHECK_MAP[$unique_check_key]=1
VALUE_MAPPING+=("$origin_value|$field|$seq_num")
echo -e "\033[32m提取:$file -> $field$seq_num = $origin_value\033[0m"
done <<< "$all_origin_values"
done
done
# 校验是否成功获取到原始值
if [ ${#VALUE_MAPPING[@]} -eq 0 ]; then
echo -e "\033[31m错误:未扫描到任何有效字段值\033[0m"
exit 1
fi
# ========== 【2.生成clean/smudge规则】 ==========
echo -e "\n\033[36m===== 生成clean/smudge规则 =====\033[0m"
CLEAN_RULE=""
SMUDGE_RULE=""
for item in "${VALUE_MAPPING[@]}"; do
# 解析映射项:原始值|字段名|序号
val=$(echo "$item" | cut -d'|' -f1)
field=$(echo "$item" | cut -d'|' -f2)
num=$(echo "$item" | cut -d'|' -f3)
placeholder="${BASE_PLACEHOLDER}_${field}${num}"
# 转义所有特殊字符
val_esc=$(echo "$val" | sed 's/[/*$&|]/\&/g')
ph_esc=$(echo "$placeholder" | sed 's/[/*$&|]/\&/g')
# 生成sed规则:将原始值替换为占位符
CLEAN_RULE+=" -e 's/${val_esc}/${ph_esc}/g'"
SMUDGE_RULE+=" -e 's/${ph_esc}/${val_esc}/g'"
done
echo -e "\033[32m生成${#VALUE_MAPPING[@]}条\033[0m"
# ========== 【3.配置Git全局过滤器】 ==========
echo -e "\n\033[36m===== 配置Git全局过滤器 =====\033[0m"
# 发起配置命令
git config filter.$FILTER_NAME.clean "sed $CLEAN_RULE"
git config filter.$FILTER_NAME.smudge "sed $SMUDGE_RULE"
git config filter.$FILTER_NAME.required true
# 检查配置是否成功
filter_check=$(git config --get filter.$FILTER_NAME.clean)
smudge_check=$(git config --get filter.$FILTER_NAME.smudge)
required_check=$(git config --get filter.$FILTER_NAME.required)
if [ -n "$filter_check" ] && [ -n "$smudge_check" ] && [ "$required_check" = "true" ]; then
echo -e "\033[32m配置成功\033[0m"
else
echo -e "\033[31m过滤器配置失败,请手动执行脚本内命令\033[0m"
exit 1
fi
# ========== 【4.绑定文件到.gitattributes】 ==========
echo -e "\n\033[36m===== 绑定文件过滤规则 =====\033[0m"
for file in "${files[@]}"; do
if ! grep -q "^${file}[[:space:]]*filter=${FILTER_NAME}$" $GIT_ATTRIBUTES 2>/dev/null; then
echo "${file} filter=${FILTER_NAME}" >> $GIT_ATTRIBUTES
echo -e "\033[32m绑定:$file -> $FILTER_NAME\033[0m"
else
echo -e "\033[33m提示:$file 已存在过滤规则\033[0m"
fi
done
git add $GIT_ATTRIBUTES
echo -e "\033[32m修改成功:$GIT_ATTRIBUTES\033[0m"
# ========== 【5.重新追踪应用】 ==========
echo -e "\n\033[36m===== 重新追踪文件 =====\033[0m"
for file in "${files[@]}"; do
if [ -f "$file" ]; then
if git diff --cached --quiet "$file" >/dev/null 2>&1; then
git rm -r --cached "$file"
fi
git add "$file"
fi
done
echo -e "\033[32m完成\033[0m"
exit 0
三、想了解原理?手动配置步骤
如果想搞懂背后的原理,或者需要自定义配置,可以跟着下面的步骤手动操作。
其实核心就 3 步:配置过滤器、绑定文件、验证效果。
第一步:配置过滤器
推荐只让过滤器在当前项目生效(避免影响其他项目),操作很简单:
- 打开项目里的
.git文件夹(这个文件夹是隐藏的,需要显示隐藏文件); - 找到
config文件,用记事本或编辑器打开; - 在文件末尾添加下面的内容:
ini
[filter "sensitive_filter"] # 过滤器名字,自己随便起,后面要用到
clean = sed -e 's/123456/****_pwd1/g' -e 's/666123/****_pwd2/g'
smudge = sed -e 's/****_pwd1/123456/g' -e 's/****_pwd2/666123/g'
required = true
解释下这几行的意思(理解就行):
s/原内容/替换内容/g:sed 的替换语法,s表示文本替换,g表示全局匹配替换(出现多次全都替换);clean = ...:提交时执行的命令,把真实密码(比如123456)换成占位符(比如****_pwd1);smudge = ...:拉取时执行的命令,把占位符(****_pwd1)换回真实值(123456);-e:可以拼接多个替换规则,比如同时替换密码和密钥(支持正则表达式);
💡注意:
.git/config是本地文件,不会提交到远程仓库!团队其他成员需要在自己的本地项目里,也配置这个文件(可以把你的 config 文件发给他们复制)。
👀细心的你有没有发现?这样写配置,如果要脱敏的字段很多,那就要重复写很长的一串规则啊!
还是用我写的自动脚本吧~~!
补充做法
-
想让 git 全局项目都生效,那就要修改 Git 全局配置文件
.gitconfig;一般windows 的 git 全局配置文件位置为C:\Users\你的用户名.gitconfig; -
也可以用命令行进行配置
-
全局配置生效:
python# 配置 clean 过滤器 git config --global filter.sensitive_filter.clean "sed -e 's/123456/****_pwd1/g' -e 's/666123/****_pwd2/g'" # 配置 smudge 过滤器 git config --global filter.sensitive_filter.smudge "sed -e 's/****_pwd1/123456/g' -e 's/****_pwd2/666123/g'" # 强制生效:无过滤规则则拒绝提交/拉取 git config --global filter.sensitive_filter.required truefilter.sensitive_filter.clean:此处第二段的sensitive_filter是自定义过滤器名称。
-
仅当前项目配置生效:去掉参数
--global即可。
-
第二步:创建 .gitattributes 文件(告诉Git哪些文件要过滤)
我们需要创建一个 .gitattributes 文件,告诉 Git"哪些文件需要用上面配置的过滤器"。这个文件要提交到仓库,让团队所有人都能用同样的规则。
- 在项目根目录新建文件,命名为
.gitattributes; - 写入下面的内容(根据你的配置文件调整):
ini
# 格式:【需要过滤的文件】 filter=过滤器名称
# 单文件精准匹配(推荐,精准脱敏)
settings.yaml filter=sensitive_filter
# 通配符匹配(批量脱敏,适合同类型配置文件)
*.yml filter=sensitive_filter
# 排除不需要过滤的文件(可选)
README.md !filter
# 注意:过滤器名称 `sensitive_filter` 必须和步骤 1 中配置的完全一致(大小写敏感)
写完后,执行下面的命令提交这个文件:
sql
git add .gitattributes
git commit -m "添加敏感文件过滤规则"
第三步:验证配置是否成功
查看已配置的过滤规则,执行以下命令查看:
csharp
# 查看全局过滤器配置
git config --global --get-regexp filter
# 查看当前项目过滤器配置
git config --get-regexp filter
# 查看所有 Git 配置(含过滤器)
git config --list
第四步:使用验证
如果你的配置文件之前已经被 Git 追踪过(比如已经提交过),需要先把它从 Git 暂存区移除(不会删除本地文件):
bash
git rm --cached "被脱敏文件的地址"
然后验证脱敏效果:
csharp
# 将文件加入暂存区(触发 clean 脱敏)
git add "被脱敏文件的地址"
# 查看暂存区中文件的脱敏效果
git diff --cached "被脱敏文件的地址"
# 提交到本地仓库
git commit -m "feat: 提交脱敏后的配置文件"
补充:用正则实现"任意敏感值自动脱敏"
如果你的配置文件里敏感值经常变,不想每次都手动加替换规则,可以用正则表达式写 clean 规则,实现"只要是某个字段,就自动替换成占位符"。
比如这样配置过滤器:
ini
[filter "sensitive_filter"]
clean = sed -e 's/(password:\s*).*/\1******/g' -e 's/(secret:\s*).*/\2******/g' -e 's/(token:\s*).*/\1******/g'
smudge = sed -e 's/password: 1******/password: my_db_pass_123/g' -e 's/secret: 2******/secret: my_jwt_7890/g'
required = true
说明:这种方式适合敏感字段固定,但值经常变的场景,不过 smudge 规则还是要手动维护真实值,不如自动化脚本省心。
四、总结一下
如果是正在开发的项目,优先用「Git 内置过滤器」+「自动化脚本」,一键配置,全程自动脱敏/还原,不影响开发;如果是已开发完的项目,用模板文件或环境变量的方式更简单。
核心原则就是:敏感信息只留在本地,仓库里只存脱敏后的内容,既安全又省心!