如何在GitHub Action中检查文件与上一提交的差异?
问题
我有一个存储时间戳的文件,本地执行以下命令就能检查该文件与上一提交的差异并解析输出,就算工作区有未提交的新时间戳也能正常使用:
git diff --word-diff=porcelain HEAD~1 -- dev/tests/artifact_build_timestamp.info > /tmp/timestamp-diff.txt || exit 2;
但在GitHub Action中使用actions/checkout@v3(已设置fetch-depth: 0)检出代码时,处于分离头指针模式,无法用HEAD~1对比。我试了下面的脚本,但不确定能不能覆盖所有运行场景,想知道有没有更优的实现方式:
if [[ ! -z "$CI" ]]; then BRANCH_NAME=${GITHUB_HEAD_REF} git pull origin ${BRANCH_NAME} || exit 1; git diff --word-diff=porcelain origin/${BRANCH_NAME}~1 origin/${BRANCH_NAME} -- dev/tests/artifact_build_timestamp.info > /tmp/timestamp-diff.txt || exit 2; fi
解决方案与优化建议
现有脚本的局限
- 场景适配不足:
GITHUB_HEAD_REF仅在PR触发的Action中有值,直接推送分支触发时该变量为空,会导致脚本执行失败。 - 多余操作有风险:已经设置
fetch-depth: 0拉取了完整仓库历史,无需再执行git pull,反而可能因工作区未提交的时间戳文件引发冲突。 - 基准可靠性差:PR场景下用
origin/${BRANCH_NAME}作为对比基准并不准确,应该以PR的目标分支与当前分支的差异为准。
更优的通用实现
通过GitHub内置环境变量动态适配PR、直接推送等不同场景,无需依赖分支名称:
# 区分PR与直接推送场景,确定对比基准 if [[ -n "$GITHUB_BASE_REF" ]]; then # PR场景:拉取目标分支最新状态,对比目标分支与当前PR分支 git fetch origin ${GITHUB_BASE_REF}:refs/remotes/origin/${GITHUB_BASE_REF} DIFF_BASE="origin/${GITHUB_BASE_REF}" DIFF_HEAD="HEAD" else # 直接推送场景:对比当前提交的父提交与当前提交 DIFF_BASE="HEAD~1" DIFF_HEAD="HEAD" fi # 执行diff命令,兼容工作区未提交变更 git diff --word-diff=porcelain ${DIFF_BASE} ${DIFF_HEAD} -- dev/tests/artifact_build_timestamp.info > /tmp/timestamp-diff.txt || exit 2
关键优化点
- 环境变量适配:用
GITHUB_BASE_REF判断PR场景,自动切换对比逻辑,覆盖所有触发方式。 - 避免冗余操作:仅在PR场景按需拉取目标分支,无需全局拉取,减少冲突风险。
- 兼容分离头指针:直接用提交引用或远程分支做对比,不依赖本地分支的HEAD状态。
- 保留本地行为一致性:
git diff对比提交与HEAD时,自动包含工作区未提交变更,和本地执行逻辑一致。
极端场景补充处理
如果遇到初始提交(无HEAD~1)的情况,可以添加判断避免报错:
# 检查对比基准是否存在 if git rev-parse --verify ${DIFF_BASE} >/dev/null 2>&1; then git diff --word-diff=porcelain ${DIFF_BASE} ${DIFF_HEAD} -- dev/tests/artifact_build_timestamp.info > /tmp/timestamp-diff.txt || exit 2 else # 初始提交时,直接输出当前文件内容作为diff(可按需调整逻辑) git show ${DIFF_HEAD}:dev/tests/artifact_build_timestamp.info > /tmp/timestamp-diff.txt || exit 2 fi
内容的提问来源于stack exchange,提问作者Bertuz
相关产品推荐
相关产品推荐

