Stack是否仅构建时运行hpack?切Git分支时.cabal为何被自动修改
成因说明
Stack 没有常驻后台的守护进程监听文件变更来重生成 .cabal,你遇到的瞬时修改问题,触发源基本都来自 shell 环境的自动执行逻辑:
- 只要执行任意需要读取项目配置的 Stack 子命令(不止
build,包括查询 GHC 版本、读取路径、补全信息加载这类非构建操作),Stack 默认都会先校验package.yaml和现有.cabal文件的一致性,判定不匹配就会自动调用 hpack 重写.cabal。仅在构建前重生成的逻辑确实能满足构建需求,但 Stack 目前没有做这个场景的区分,所有读配置的命令都会触发 hpack 检查。 - 你观察到的时间差完全匹配 shell 提示符插件的执行时机:执行完
git restore *.cabal命令返回交互 shell 时,侧边栏显示 GHC 版本的插件会自动调用 Stack 命令读取当前项目环境,这个过程触发了.cabal重写,等你再执行git switch时,文件已经产生未提交变更,自然会报错。把两个命令用&&合并成同一条执行时,中间不会回到 shell 交互态,没有触发插件执行的窗口,所以可以正常切换。 - 不同分支下生成的
.cabal中Paths_Package内容存在差异是正常现象:hpack 生成该段内容时会读取当前本地环境状态、包版本配置,哪怕两个分支的package.yaml完全一致,切换分支过程中的文件临时状态、本地 Stack 环境参数变化,都可能导致生成内容出现 diff。 stack --bash-completion-script本身不会触发重写,但 Zsh 补全逻辑如果在预加载项目补全信息时调用了其他需要读配置的 Stack 子命令,同样会触发.cabal重写。
可参考的解决方法
- 最优方案:不要将自动生成的
.cabal文件纳入 Git 版本管理,在.gitignore中添加*.cabal规则,所有协作者统一通过package.yaml管理配置,从根源上避免自动生成文件带来的冲突。如果项目需要兼容不使用 hpack 的场景、必须提交.cabal文件,可以参考下面的方案。 - 临时规避:执行 Git 分支切换等操作时,添加环境变量禁用 Stack 的自动 hpack 逻辑,例如使用
STACK_AUTO_HPACK=false git switch <目标分支名>,需要构建时再手动执行stack build触发一次.cabal生成即可。 - 调整 shell 配置:修改终端侧边栏显示 GHC 版本的插件逻辑,调用 Stack 命令时统一加上
--no-hpack参数,避免非构建场景下触发文件改写。 - 配置 Git 钩子:在仓库的
post-checkout钩子中添加git restore *.cabal逻辑,分支切换完成后自动复位.cabal文件状态,省去手动操作的步骤。
内容的提问来源于stack exchange,提问作者zaabson
相关产品推荐
相关产品推荐

