Go1.25 新特性:Go modules 終于要支持 Git 子目錄,太感人了!!!
大家好,我是煎魚。
在過去 Go 最早是使用 GOPATH 的模塊依賴管理方式,源于 Go 的大單體倉庫的模式。隨后 @rsc 推行了 Go modules(也就是現(xiàn)在的 go.mod)的模塊依賴管理方式。
但 Go modules 本身也依然有不少的問題點,其中一個是類似 GitLab subgroups 的兼容適配問題。
與我們今天分享的問題點也比較相近。
業(yè)務背景
原提案作者 @Anmol Sethi 有一個開源項目 nhooyr/websocket[1]
圖片
該項目的倉庫根目錄塞滿了 Go 文件,造成頁面混亂、不容易閱讀。(作者自述)
于是作者想要將模塊源碼遷移到倉庫下的子模塊,這樣可以實現(xiàn)根目錄就干凈了,文檔和配置文件也不會和源碼混在一起,更利于維護與閱讀。
但是很無奈的是,Go 并不支持模塊在倉庫子目錄中的情況,導致如果嘗試:
go get github.com/nhooyr/websocket/mod@latest或在 go.mod 中這樣引用:
require github.com/nhooyr/websocket/mod v0.1.0就會失敗,因為 go module 無法識別子模塊的場景。這是該作者遇到的真實案例。
不支持的原因
在 Go 的模塊代理機制中,cmd/go 會根據(jù)代碼里對應的 go-import meta 標簽來定位模塊的位置。
例如下面這個最常見的 group/project 例子,我們模仿 go get 命令直接拉取:
curl -X GET "https://gitlab.xxx.com/libraries/example?go-get=1"
<html><head><meta name="go-import" cnotallow="gitlab.xxx.com/libraries/example git https://gitlab.xxx.com/libraries/example.git" /></head></html>現(xiàn)有的 cmd/go 機制只會把倉庫根目錄當作模塊根。
如果在 Git 倉庫中,實際把 go 模塊源碼放在子目錄(例如:github.com/eddycjy/repo/subdir),則 cmd/go 無法正確處理。
Go1.25 新特性:Go 模塊將支持 Git 子目錄
@Anmol Sethi 發(fā)起了新提案《cmd/go: allow serving module under the subdirectory of git repository[2]》:
圖片
期望去推動并解決這個問題。
最終定論是,允許在 go-import meta 標簽中明確支持指定子目錄,例如:
<meta name="go-import" cnotallow="example.com/repo git https://.../repo sub/dir">這樣 Go 命令就可以把模塊定位在包含源碼的子目錄中,而不是整個倉庫根目錄。
核心變更上主要是對 cmd/go 的解析邏輯進行了擴展,支持新 meta 標簽格式 root-path vcs repo-url subdir 的解析:
圖片
以此達到了 go-import 元標記中指定子目錄的功能。
對 Go 官方這部分具體代碼感興趣的同學,可以查看以下 CL《cmd/go: add subdirectory support to go-import meta tag[3]》:
圖片
總結
這個提案目前已經通過并且合并,預計將會在 Go1.25 中開始正式應用。也是廣大 Go 開發(fā)者的好消息了。

而且普遍從 issues 來看,大家都認為這將是一個比較實用的改進,特別適合 monorepo 維護與多語言項目結構。
參考資料
[1] nhooyr/websocket: https://github.com/coder/websocket
[2] cmd/go: allow serving module under the subdirectory of git repository: https://github.com/golang/go/issues/34055
[3] cmd/go: add subdirectory support to go-import meta tag: https://github.com/benjivesterby/go/commit/835e36fc7f631f74233edfd4ab43b6b56833db86
































