GitHub Actions中Linux与Windows运行器git worktree行为差异问题
问题现象
编写GitHub Action工作流时,通过创建git worktree的方式将文件推送到与Action当前运行分支不同的目标分支,执行环境差异导致结果不一致:
- 使用
ubuntu-latest运行器时逻辑运行正常,可正确推送至目标ghpages分支 - 使用
windows-2019运行器时逻辑执行失败,git push未推送到worktree绑定的ghpages分支,反而尝试推送当前受保护的main分支,触发分支保护报错
Ubuntu环境正常运行代码
git worktree add -B ghpages html_build origin/ghpages cp -a docs/. html_build/ cd html_build git add . git commit -m "ghpages" git push
Windows环境异常代码
git worktree add -B ghpages html_build origin/ghpages robocopy .\docs\ .\html_build\ /MIR cd html_build git add . git commit -m "ghpages" git push
Windows环境报错日志
remote: error: GH006: Protected branch update failed for refs/heads/main. remote: error: At least 1 approving review is required by reviewers with write access. To https://github.com/XXX/XX ! [remote rejected] main -> main (protected branch hook declined) error: failed to push some refs to 'https://github.com/XXX/XX'
临时移除main分支保护规则后验证,提交内容确实被错误推送到main分支,而非预期的ghpages分支。
根本原因
不存在git worktree在Linux、Windows运行器上的原生行为差异,问题来自两个Windows环境特有的执行逻辑坑:
- 核心原因是
robocopy /MIR的镜像同步逻辑:该参数会强制目标目录内容和源目录完全一致,所有源目录不存在的文件、文件夹都会被直接删除。执行上述robocopy命令时,源目录docs内没有worktree自动生成的.git引用文件(worktree目录下的.git不是文件夹,是指向主工作区git配置的文本引用文件),同步时这个文件会被直接删除。.git文件丢失后,html_build目录就不再是绑定ghpages分支的独立工作树,git向上递归查找仓库根目录时,会直接命中上层主工作区(也就是Action默认checkout的main分支仓库),后续所有git操作实际都是在main分支上执行的。
而Linux下的cp -a docs/. html_build/只会把docs目录下的内容复制到目标目录,不会删除目标目录已有的文件,自然不会破坏worktree的.git引用,所以逻辑正常。 - 次要原因是PowerShell的目录切换上下文和bash存在差异:如果git操作拆分在不同的run步骤中执行,
cd切换目录后的上下文不会自动继承,git可能仍然读取主工作区的配置,不过该问题在同一段run脚本内执行时影响极小。
解决方案
针对Windows环境调整执行逻辑,避开上述问题即可,两种常用方案任选:
- 方案1(推荐,双保险不会推错分支):给robocopy加排除.git的参数避免破坏worktree结构,同时显式指定推送的目标分支,不依赖git默认的上下文识别,修改后代码如下:
git worktree add -B ghpages html_build origin/ghpages # 加/XD .git参数,排除.git文件,避免被robocopy误删 robocopy .\docs\ .\html_build\ /MIR /XD .git cd html_build git add . git commit -m "ghpages" # 显式指定将当前HEAD推送到远程ghpages分支,完全避免分支识别错误 git push origin HEAD:ghpages
- 方案2:如果希望和Linux环境写法保持一致,可以使用PowerShell原生的目录栈命令强制切换执行上下文,同样需要给robocopy加排除.git参数:
git worktree add -B ghpages html_build origin/ghpages robocopy .\docs\ .\html_build\ /MIR /XD .git Push-Location html_build git add . git commit -m "ghpages" git push Pop-Location
注意:无论用哪种方案,都必须给robocopy加/XD .git参数,这是该场景下90%以上异常的触发原因。
内容的提问来源于stack exchange,提问作者001001
相关产品推荐
相关产品推荐

