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

如何解决Github Actions矩阵中多环境Git推送冲突问题

解决GitHub Actions矩阵作业Git推送冲突问题

问题根源

你的矩阵作业并行执行时,每个作业启动时拉取的是仓库初始状态,修改对应环境文件后直接提交推送。当第一个作业成功更新远程分支后,后续作业的本地分支已落后于远程版本,此时推送就会触发cannot lock ref冲突——远程分支的HEAD已不是作业拉取时的版本。随机sleep仅能降低冲突概率,无法从根本上解决问题。

解决方案

方案1:将矩阵作业改为串行执行

通过GitHub Actions的concurrency配置,强制同工作流内的矩阵任务按顺序执行,彻底避免并行推送冲突。

修改工作流的作业配置,添加concurrency字段:

jobs:
  shutdown-envs:
    runs-on: ubuntu-latest
    concurrency:
      group: ${{ github.workflow }}-${{ github.ref }}
      cancel-in-progress: false
    strategy:
      matrix:
        unprotected_environment: ${{ steps.generate-matrix.outputs.environments }}
    steps:
      # 你的现有步骤...

上述配置会让整个工作流的矩阵任务串行执行,若需按环境分组串行,可在group后追加-${{ matrix.unprotected_environment }}。

方案2:推送前拉取最新代码并合并

在git push前执行拉取操作,确保本地分支同步远程最新状态后再推送。由于每个作业修改的是不同环境的独立目录,合并时不会出现内容冲突。

修改你的git-push步骤脚本:

set -ex -o pipefail
git config --global user.name github-actions-workflows
git config --global user.email devops+github-actions-workflows@company
env_name=${{ matrix.unprotected_environment }}

# 修改对应环境文件
cd ${{ github.workspace }}/${{ env.qa_processing_tg_dir }}/${{ env.qa_envs_region}}/${env_name}
git add ecs-service
git add autoscaling/product
git add ecs-capacity-provider/service
cd ${{ github.workspace }}/${{ env.qa_commercial_tg_dir }}/${{ env.qa_envs_region}}/${env_name}
git add ecs-service
git add ecs-capacity-provider/service

git commit -m "Shutting down for the night environment ${env_name}"

# 推送前拉取最新代码,用rebase保持提交历史整洁
git pull --rebase origin master
# 若rebase失败(理论上不会,因为修改的是独立目录),可改用普通pull
# git pull origin master

git push
export COMMIT_ID=$(git rev-parse HEAD)
echo "::set-output name=commit_id::${COMMIT_ID}"
echo "COMMIT_ID: ${COMMIT_ID}"

方案3:批量修改所有环境,单次提交推送

放弃矩阵并行,一次性收集所有需停机的环境,批量修改文件后单次提交推送,从根源上消除冲突。

示例脚本:

set -ex -o pipefail
git config --global user.name github-actions-workflows
git config --global user.email devops+github-actions-workflows@company

# 假设已通过前置步骤获取需停机的环境列表
envs=(${{ steps.generate-matrix.outputs.environments }})

for env_name in "${envs[@]}"; do
  # 修改processing目录下的环境文件
  cd ${{ github.workspace }}/${{ env.qa_processing_tg_dir }}/${{ env.qa_envs_region}}/${env_name}
  git add ecs-service
  git add autoscaling/product
  git add ecs-capacity-provider/service
  # 修改commercial目录下的环境文件
  cd ${{ github.workspace }}/${{ env.qa_commercial_tg_dir }}/${{ env.qa_envs_region}}/${env_name}
  git add ecs-service
  git add ecs-capacity-provider/service
done

# 一次性提交所有变更
git commit -m "Shutting down QA environments for the night: ${envs[*]}"
git push
export COMMIT_ID=$(git rev-parse HEAD)
echo "::set-output name=commit_id::${COMMIT_ID}"

方案选择建议

  • 若需保留并行效率(比如每个环境的Terragrunt执行需单独运行),优先选方案2,既保留并行优势,又能避免冲突。
  • 若环境处理逻辑简单,无需并行,方案3更简洁,提交历史也更清晰。
  • 方案1适合必须串行处理的场景,但会增加整体工作流的执行时间。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 13:45:37