For example, we have a repo with structure as below
- cmd
- pkg
- server
- client
- api
- go.mod
- go.sum
If the repo consumers hope to import client and api pkg, they have to import the whole module and indirectly import dependencies of server pkg.
Only three choices for this situation.
New git repo for client and api
New go.mod file and new git tag for client and api, e.g client/v0.1.0
New go.mod file and use replace directive
For choice 1, we have to manage more git repos and submit more PRs for a feature.
For choice 2, we have to tag api and client, then change the go.mod version and tag main module.
For choice 3, replace directive has some problems now.
However, go install is not worked if replace directive exists(See #44840, #40276)
Another problem of replace is if client also imports api and replaces it. consumers have to use replace in go.mod again to ensure api module's version.
require (
github.com/xxx/yyy/api v0.0.1
github.com/xxx/yyy/client v0.0.1
)
# If omit this line, the below error will be thrown
# go: github.com/xxx/yyy/client@v0.0.1 requires
#. github.com/xxx/yyy/api@v0.0.0-00010101000000-000000000000: invalid version: unknown revision 000000000000
replace github.com/xxx/yyy/api => github.com/xxx/yyy/api v0.0.1
Design
Add local directive for all modules which are imported from same git repo.
Use same version as the main module to import local modules.
In main module
module github.com/xxx/yyy
local (
github.com/xxx/yyy/client
github.com/xxx/yyy/api
)
in client module
module github.com/xxx/yyy/client
local (
github.com/xxx/yyy/api
)
Go 1.18 has workspaces. Could they be used in your use case?
go.work seems a local workspace and not be pushed to remote repo in best practice? If I split monorepo to three git repos, go.work can be easily used for me to modify my code.
I would like to add a further issue to consider here.
We have a similar project structure, but we also use vendoring in the root project. Using the example from the description, this means the pkg/client module is copied to vendor (but with full module path of course), and whenever you make a change to pkg/client during development, you have to run go mod vendor.
Why
One go.mod is not reasonable for monorepo
For example, we have a repo with structure as below
If the repo consumers hope to import
client
andapi
pkg, they have to import the whole module and indirectly import dependencies ofserver
pkg.Only three choices for this situation.
client/v0.1.0
replace
directiveFor choice 1, we have to manage more git repos and submit more PRs for a feature.
For choice 2, we have to tag
api
andclient
, then change the go.mod version and tag main module.For choice 3,
replace
directive has some problems now.replace
directive for monorepoThe below lines are used in many go.mod files.
However, go install is not worked if
replace
directive exists(See #44840, #40276)Another problem of
replace
is ifclient
also importsapi
and replaces it. consumers have to usereplace
in go.mod again to ensureapi
module's version.Design
local
directive for all modules which are imported from same git repo.In main module
in client module
in consumer module
go mod graph for consumer
Compatibility
No compatibility problem
Alternatives
require
as the local module. (also good to me)replace
directive.The text was updated successfully, but these errors were encountered: