go mod常用命令 已經 常見問題


最近接觸到go mod,網上查了查資料,這里記錄一下。

 

1 介紹

1.1、go mod是什么

      go mod 是Golang 1.11 版本引入的官方包(package)依賴管理工具,用於解決之前沒有地方記錄依賴包具體版本的問題,方便依賴包的管理。

      之前Golang 主要依靠vendor和GOPATH來管理依賴庫,vendor相對主流,但現在官方更提倡go mod。

1.2、go mod初始化及使用

下載官方包1.11(及其以上版本將會自動支持gomod) 默認GO111MODULE=auto(auto是指如果在gopath下不啟用mod)

Golang 提供一個環境變量 GO111MODULE 來設置是否使用mod,它有3個可選值,分別是off, on, auto(默認值),具體含義如下:

  1. off: GOPATH mode,查找vendor和GOPATH目錄
  2. on:module-aware mode,使用 go module,忽略GOPATH目錄
  3. auto:如果當前目錄不在$GOPATH 並且 當前目錄(或者父目錄)下有go.mod文件,則使用 GO111MODULE, 否則仍舊使用 GOPATH mode。

修改 GO111MODULE 的值的語句是:set GO111MODULE=on 。

在使用模塊的時候, GOPATH 是無意義的,不過它還是會把下載的依賴儲存在 GOPATH/src/mod 中,也會把 go install 的結果放在 GOPATH/bin(如果 GOBIN 不存在的話)

  • go mod download 下載模塊到本地緩存,緩存路徑是 $GOPATH/pkg/mod/cache
  • go mod edit 是提供了命令版編輯 go.mod 的功能,例如 go mod edit -fmt go.mod 會格式化 go.mod
  • go mod graph 把模塊之間的依賴圖顯示出來
  • go mod init 初始化模塊(例如把原本dep管理的依賴關系轉換過來)
  • go mod tidy 增加缺失的包,移除沒用的包
  • go mod vendor 把依賴拷貝到 vendor/ 目錄下
  • go mod verify 確認依賴關系
  • go mod why 解釋為什么需要包和模塊

注意有幾個坑的地方:

  • go mod 命令在 $GOPATH 里默認是執行不了的,因為 GO111MODULE 的默認值是 auto。默認在$GOPATH 里是不會執行, 如果一定要強制執行,就設置環境變量為 on

  • go mod init 在沒有接module名字的時候是執行不了的,會報錯 go: cannot determine module path for source directory。可以這樣執行:

    $ go mod init github.com/jiajunhuang/hello
    

    否則就要在 main.go 里加上導入聲明,例如:

    $ cat main.go
    package main
    
    func main() {
        println("Hello world")
    }
    $ go mod init
    go: cannot determine module path for source directory /Users/jiajun/hello (outside GOPATH, no import comments)
    $ vim go.mod
    $ cat go.mod
    module github.com/jiajunhuang/hello
    $ go mod init
    go mod init: go.mod already exists
    $ rm go.mod
    $ vim main.go
    $ cat main.go
    package main // import "github.com/jiajunhuang/hello"
    
    func main() {
        println("Hello world")
    }
    $ go mod init
    go: creating new go.mod: module github.com/jiajunhuang/hello
    $ ls
    go.mod  main.go
    $ cat go.mod
    module github.com/jiajunhuang/hello
    

    當然,如果在已有代碼的倉庫里執行是不存在這個問題的。

 

2 命令

2.1 指定module的根目錄並生成go.mod文件

go mod init example.com/hello

2.2 下載並添加依賴到go.mod文件中

go build, go test

2.3 查看module下的所有依賴

go list -m all

2.4 更新穩定版依賴

go get rsc.io/sampler

2.5 更新為指定版本依賴

  1.  
    go list -m -versions rsc.io/sampler
  2.  
     
  3.  
    rsc.io/sampler v1 .0.0 v1.2.0 v1.2.1 v1.3.0 v1.3.1 v1.99.99
  4.  
     
  5.  
    go get rsc.io/sampler@v1.3.1

2.6 清理無用的依賴

go mod tidy

2.7 將依賴復制到項目路徑的vendor文件夾中

go mod vendor

2.8 忽略cache里的包,只使用vendor目錄里的依賴進行編譯

go build -mod=vendor

2.9 校驗依賴並查看是否有修改

go mod verify

 

3 問題

3.1 go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'

go mod init

go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'

開啟go module:

  1. set GO111MODULE=on //windows

  2. export GO111MODULE=on //linux

3.2 $GOPATH/go.mod exists but should not

GO 1.11或之后模塊遇到這個問題:

$GOPATH/go.mod exists but should not 

    開啟模塊支持后(set GO111MODULE=on),並不能與$GOPATH共存,所以把$GOPATH從env中移出即可(unset GOPATH),可運行“unset GOPATH && make”。

 

4 例子

4.1 例子1

go mod初始化:在$GOPATH外建一個文件夾,把個人代碼放進去,我的測試代碼路徑:https://github.com/kevinhao8/go-mod-example。

首先main入口代碼所在文件夾創建mod

創建語句  go mod init [module name]

比如我的測試代碼 redisTest.go,創建語句就是  go mod init redisTest,成功創建時返回  go: creating new go.mod: module redisTest

此時文件夾下出現 go.mod文件,打開發現只有2行如下,並沒有記錄依賴庫。

module redisTest

go 1.12

此時需要輸入go test語句,根據需要的依賴自動生成require,也就是依賴包,此時go.mod多了如下內容(紅字是我寫的注釋,文件里面沒有)

require (
      github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect(有indirect注釋的代表間接依賴,沒有的代表直接依賴)
      github.com/gin-gonic/gin v1.3.0  
      github.com/golang/protobuf v1.3.1 // indirect
      github.com/mattn/go-isatty v0.0.7 // indirect
      github.com/ugorji/go/codec v0.0.0-20190316192920-e2bddce071ad // indirect(這里是版本號+時間戳+hash)
      gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
      gopkg.in/yaml.v2 v2.2.2 // indirect
)

此時會有如下失敗提示,此處為我踩得第一個坑!!!花了挺長時間才解決

build redisTest: cannot load dbredis: cannot find module providing package dbredis

dbredis是我寫的私有包,代碼是沒有問題的,為什么找不到呢?從網上查了一圈,發現私有包如果不想發布到網上,需要手動添加require ,然后replace 進行替換,將私有包指向本地module所在的絕對或相對路徑。一般用相對路徑更通用。

此時手動將go.mod改為如下,紅字為新加

require (
      dbredis v0.0.0
      github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect
      github.com/gin-gonic/gin v1.3.0
      github.com/golang/protobuf v1.3.1 // indirect
      github.com/mattn/go-isatty v0.0.7 // indirect
      github.com/ugorji/go/codec v0.0.0-20190316192920-e2bddce071ad // indirect
      gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
      gopkg.in/yaml.v2 v2.2.2 // indirect
)

replace dbredis v0.0.0 => ./dbredis

再度運行go test  命令,發現仍有失敗提示如下,找不到dbredis文件夾下的go.mod文件。

go: parsing dbredis\go.mod: open E:\code\go-mod-example\dbredis\go.mod: The system cannot find the file specified.
go: error loading module requirements

從網上查資料發現,這種情況下需要給私有包也生成mod,這樣整個工程的依賴才能完整。故運行如下命令:

cd dbredis

go mod init dbredis(此處我寫的mod名跟package名一致,不知道不一致行不行)

go test

三條命令依次運行通過,dbredis文件夾下的go.mod文件如下:

module dbredis

go 1.12

require github.com/go-redis/redis v6.15.2+incompatible

此時再運行如下命令:

cd ..(回到上層文件夾)

go test

運行通過,不再有報錯。運行命令 go build redisTest.go 也能夠正常生成redisTest.exe

至此通過mod來管理依賴包基本實現,我們的程序能基本脫離$GOPATH編譯。
 

5 go mod 和 dep 比較

  • go mod 支持代理,以后就可以使用私有鏡像源了~,具體請搜索 GOPROXY
  • go mod 速度比 dep 快很多
  • go.mod 中列出了所有的依賴,這一點其實我不是很喜歡,因為當項目一大,歷史一久,只要升級其中一個依賴,很可能整個依賴 就掛了。我還是比較喜歡只要列出頂級依賴,由程序處理子依賴的情況。

一個生成的 go.mod 的示例

module github.com/my/module/v3  // 這是你的包的聲明

// require 里是依賴。需要帶上路徑和版本。
require (
    github.com/some/dependency v1.2.3
    github.com/another/dependency v0.1.0
    github.com/additional/dependency/v4 v4.0.0
)

 

其他

windows下的嘗試:

gomod初嘗試
下載官方包1.11(及其以上版本將會自動支持gomod) 默認GO111MODULE=auto(auto是指如果在gopath下不啟用mod)
go mod help查看幫助
go mod init<項目模塊名稱>初始化模塊,會在項目根目錄下生成 go.mod文件。

go mod tidy根據go.mod文件來處理依賴關系。

go mod vendor將依賴包復制到項目下的 vendor目錄。建議一些使用了被牆包的話可以這么處理,方便用戶快速使用命令go build -mod=vendor編譯

go list -m all顯示依賴關系。go list -m -json all顯示詳細依賴關系。

go mod download <path@version>下載依賴。參數<path@version>是非必寫的,path是包的路徑,version是包的版本。

在gopath外新建一個項目,單獨開一個cmd設置set GO111MODULE=on(習慣性的和git初始化一樣)go mod init然后報錯了。 正解如下:go mod init xxx(module名稱可與文件名不同)

在項目目錄下執行go mod tidy下載完成后項目路徑下會生成go.mod和go.sum

go.mod文件必須要提交到git倉庫,但go.sum文件可以不用提交到git倉庫(git忽略文件.gitignore中設置一下)。

go模塊版本控制的下載文件及信息會存儲到GOPATH的pkg/mod文件夾里。

 

--------------------分割線---------------------------------------------------------

gopath 與go mod的區別

  1.  
    環境變量GOPATH不再用於解析 imports包路徑,即原有的GOPATH/src/下的包,通過import是找不到了。
  2.  
    Go Module功能開啟后,下載的包將存放與$GOPATH/pkg/mod路徑
  3.  
    $GOPATH/bin路徑的功能依舊保持


go get 流程的變化

  1.  
    老的go get取包過程類似:git clone + go install , 開啟Go Module功能后go get就只有 git clone 或者 download過程了。
  2.  
    新老實現還有一個不同是,兩者存包的位置不同。前者,存放在$GOPATH/src目錄下;后者,存放在$GOPATH/pkg/ mod目錄下。
  3.  
    老的 go get取完主包后,會對其repo下的submodule進行循環拉取。新的go get不再支持submodule子模塊拉取。



依賴包的變化

  1.  
    三方遠程包:
  2.  
    檢查遠程倉庫最新的tag版本,有就取得該版本
  3.  
    遠程倉庫沒有tag版本時,直接獲取master分支的HEAD版本
  4.  
    如果在 go.mod文件中指定了具體版本,go get直接獲取該指定版本
  5.  
    go.mod中除了可以指定具體版本號以外,還支持分支名
  6.  
     
  7.  
    本地包:
  8.  
    通過replace()進行替換


私有倉庫權限和私有vcs非標准路徑取包問題

  1.  
    權限問題
  2.  
    windows10下:
  3.  
        控制面板>用戶賬戶>憑據管理手動添加普通憑據即可
  4.  
    linux下:
  5.  
    增加 $HOME/.gitconfig 配置:
  6.  
    [url "ssh://git@github.com/MYORGANIZATION/"]
  7.  
    insteadOf = https://github.com/MYORGANIZA...
  8.  
     
  9.  
    增加 $HOME/.netrc:
  10.  
    machine github.com login YOU password APIKEY
  11.  
    將其中的 APIKEY 換成自己的登錄KEY。
  12.  
     
  13.  
    非標准路徑問題(https: //private.vcs.com:20000)
  14.  
    搭建一個中間服務:https: //private.vcs.com 能夠通過go get的包路徑匹配查詢正確的倉庫地址。


 

參考:

https://blog.csdn.net/Lazybones_3/article/details/89355133

https://blog.csdn.net/kevinh531/article/details/88691870

https://jiajunhuang.com/articles/2018_09_03-go_module.md.html

https://blog.csdn.net/qq_33296108/article/details/88184060 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM