Git脚本删除分支.env文件后切换分支无法检测到其他分支.env问题
问题
我写了一段Bash脚本,用来移除项目所有分支里的.env文件。执行脚本时,第一个分支能找到并删除.env文件,但切换到其他确实存在.env文件的分支后,脚本却检测不到这些文件。附上脚本代码:
#!/bin/bash function remove_env() { if [[ -z $1 ]];then echo "Require at least one argument, check help" exit 1 fi if [[ $1 == "-h" ]];then echo "./env-remover.sh \"<path to the env file>\" -f (optional force everything)" exit 1 fi filepath=$1 remote=$(git config --get remote.origin.url) branch=$(git rev-parse --abbrev-ref HEAD) if [[ -z $2 ]];then git filter-repo --path $filepath --invert-paths git remote add origin $remote git push --set-upstream origin $branch --force elif [[ $2 == "-f" ]];then git filter-repo --path $filepath --invert-paths --force git remote add origin $remote git push --set-upstream origin $branch --force else echo "Bad syntax" exit 1 fi } force="" if [ -n $1 ] && [ "$1" == "-f" ]; then force="-f" echo "Force enabled" fi for branch in $(git for-each-ref --format='%(refname:short)'); do true_branch_name=$(echo $branch | sed -e 's/\origin\///g') git checkout -f $true_branch_name > /dev/null env_file=$(find . -type f -name ".env" ! -path "./front-web/*" ! -path "./area_api/node_modules/*" | cut -c 3-) # there is only 1 .env so I don't need to parse multiple responses if [ -z $env_file ]; then echo -e "\e[32mno .env in $true_branch_name\e[0m" else echo -e "\e[31m\e[1m\e[4m.env founded at $env_file in $true_branch_name\e[0m" remove_env $env_file $force fi done
原因分析
- git filter-repo破坏分支引用:
git filter-repo会重写仓库的所有历史提交,包括所有分支的历史记录。你脚本一开始通过git for-each-ref获取的分支列表是重写前的旧引用,第一次执行filter-repo后,仓库分支结构已完全改变,后续循环里checkout的分支是无效的旧引用,自然找不到原本存在的.env文件。 - 错误的分支循环逻辑:
git filter-repo一次执行就会处理所有分支的历史,不需要逐个分支循环处理。重复执行反而会破坏仓库结构,导致后续分支操作异常。 - 冗余的Remote操作:每次执行
filter-repo会自动移除remote,脚本重复执行git remote add origin $remote会导致remote重复添加,且每次只push当前分支,其他分支的修改无法同步到远程。
修复方案
不需要循环切换分支,直接用git filter-repo一次性处理所有分支历史,移除指定路径的.env文件后同步所有分支到远程。修复后的脚本如下:
#!/bin/bash # 处理强制参数 force="" if [[ "$1" == "-f" ]]; then force="--force" echo "Force mode enabled" fi # 保存远程仓库地址 remote=$(git config --get remote.origin.url) if [[ -z $remote ]]; then echo "Error: No remote origin found" exit 1 fi # 定义需要排除的路径(避免误删指定目录下的.env) exclude_paths=( "./front-web/*" "./area_api/node_modules/*" ) # 构建find命令的排除参数 find_args=() for path in "${exclude_paths[@]}"; do find_args+=(! -path "$path") done # 查找所有需要移除的.env文件 env_files=$(find . -type f -name ".env" "${find_args[@]}") if [[ -z $env_files ]]; then echo "No .env files found in the repository" exit 0 fi # 遍历移除每个.env文件的所有历史记录 for env_file in $env_files; do # 去掉路径开头的./,适配filter-repo的路径格式 clean_path=${env_file#./} echo "Removing $clean_path from all branch histories..." git filter-repo --path "$clean_path" --invert-paths $force done # 重新添加远程仓库 git remote add origin "$remote" # 推送所有分支和标签到远程(强制覆盖,因为历史已重写) echo "Pushing all updated branches to remote..." git push origin --all --force git push origin --tags --force echo "All .env files have been removed from all branches"
关键改动说明
- 移除了循环切换分支的逻辑,利用
git filter-repo的特性一次性处理所有分支历史,这是工具的正确用法。 - 批量查找所有需要删除的.env文件,避免遗漏。
- 执行完历史重写后,一次性推送所有分支和标签,确保远程仓库同步所有修改。
- 优化参数处理和错误判断,提升脚本稳定性。
注意:
git filter-repo会彻底重写仓库历史,执行前务必备份仓库,同时通知所有协作成员重新clone仓库(不能用git pull拉取更新)。
内容的提问来源于stack exchange,提问作者Remy
相关产品推荐
相关产品推荐

