改代码后air不重启,根本原因是默认只监听当前目录的.go文件且不递归进入internal/、pkg/等目录,需确认在go.mod所在根目录运行并正确配置include_ext和exclude_dir。

改代码后没反应,八成是 air 没监控到你改的文件,而不是工具坏了。
为什么改了 main.go 或 handler/user.go,air 却不重启?
根本原因不是“没生效”,而是 air 默认只监听当前目录(即运行 air 命令时所在的路径)下的 .go 文件,且不递归进入符号链接、vendor/、.git/ 或隐藏目录 —— 如果你的代码在 internal/、pkg/ 或子模块里,又没显式配置监听范围,它就真的“看不见”。
- 确认你在项目根目录(
go.mod所在路径)执行air,不是在cmd/myapp/里 -
air.toml中的root字段别写死绝对路径(比如/home/user/project),换成.或留空 - 如果用模板或配置驱动逻辑(如
.yaml、.tmpl),默认不监听,必须手动加进include_ext:include_ext = ["go", "yaml", "tmpl"] - 检查
exclude_dir是否误删了你放业务代码的目录,比如写了exclude_dir = ["internal"]却忘了注释掉
build.cmd 和 bin 不一致导致 “exec: file does not exist”
这个错误不是编译失败,而是 air 找不到它该启动的二进制文件。常见于构建命令输出路径和实际运行路径对不上。
-
build.cmd必须是能直接执行的完整命令,例如go build -o ./tmp/main .;不能写go run main.go,否则air无法接管进程生命周期 -
bin的值必须和build.cmd中-o后面的路径完全一致,包括斜杠方向(Windows 下建议统一用/或./开头) - 如果项目有多个
main包(如cmd/api和cmd/admin),build.cmd要明确指定入口:go build -o ./tmp/api ./cmd/api
Windows 下频繁保存报 fork/exec 或“拒绝访问”
这不是 Go 编译问题,是 Windows 文件锁机制导致旧进程还没释放 .exe 句柄,新构建就试图覆盖它。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
- 别用
go build -o main.exe .直接覆盖同名文件;改成带唯一后缀的路径,例如go build -o ./tmp/main_$(Get-Date -UFormat %s).exe .(PowerShell) - 更稳妥的做法是启用
build.delay,设为500以上毫秒,给旧进程退出留出缓冲时间 - 某些杀毒软件会拦截
air启动的子进程,临时禁用实时防护可快速验证是否为此原因
热更新 ≠ 热加载,HTTP Server 重启时连接会断开
air 做的是进程级重启:旧进程 kill,新进程 start。它不会保留 TCP 连接、内存状态或 goroutine 上下文 —— 这一点常被误认为“不热”。
- 如果你依赖长连接(如 WebSocket、gRPC 流)、未持久化的缓存或正在处理中的异步任务,重启必然中断
- 想真正实现“不中断更新”,得自己实现 graceful shutdown + 零停机部署(比如用
http.Server.Shutdown()配合信号监听),air不负责这部分 - 开发阶段够用,但别把它当生产热更新方案;上线仍应走静态编译 + 容器滚动更新
最容易被忽略的点:很多人花时间调颜色、日志格式,却漏掉 include_ext 和 exclude_dir 的实际匹配逻辑 —— 它们才是决定“改哪行代码会触发重启”的开关。

















