英文:
Structuring Go subpackages for teams
问题
我们目前正在将一些代码库迁移到Go语言,并且在为团队中的多个开发人员设计一个灵活的目录结构方面遇到了一些困难。如果这是一个初学者问题,我很抱歉,我已经在其他地方搜索过了,但没有找到答案。
假设我有一个具有以下结构的包:
package main
import "username/myproject/subpackage"
func main() {
}
还有一个子包:
package subpackage
func main() {
}
这样做是可以的,从GitHub上阅读其他人的代码来看,似乎这是定义子包的一种常用方式。
以CoreOS源代码为例:https://github.com/coreos/etcd/blob/master/main.go
我的问题是,由于Go的目录结构,这些包存储在特定的git仓库中,如果团队中的其他人检出此代码进行工作,由于分叉,他们的目录结构将不同。路径中的用户名和导入语句将发生变化。我们经常相互拉取和推送代码,而不是使用集中式仓库,这也没有帮助。
package main
import "otherusername/myproject/subpackage"(这一行需要更改)
func main() {
}
我读到的关于Go的所有内容都指向它在团队环境中的可用性,所以我想知道我是否正确理解了包系统。
理想情况下,我们希望能够使用相对路径调用子包。我们习惯于使用命名空间,我知道Go没有命名空间。例如:
package main
import "myproject/subpackage"
func main() {
}
但是Go找不到文件,我确定这不是正确的做法,因为在线上没有使用相对路径的示例。
所以有几个问题:
1)包是否应该有一个明确定义的所有者,并始终将该用户名作为导入路径的一部分?
2)这个“所有者”仓库是否应该是一个集中式仓库(比如公司或组织),所有的代码都被推送到/拉取自该仓库?
3)在创建者的文件夹/命名空间中使用代码的其他团队成员是否应该使用它,而不是使用自己的文件夹/命名空间?
4)是否有一种方法可以在导入语句中定义相对路径?如果有,为什么没有人这样做?这被认为是不好的做法吗?
5)Go子包如何处理仓库分叉?
谢谢。
英文:
We are currently moving some of our codebase to Go and are struggling a bit with a flexible directory structure for multiple devs within a team. Apologies if this is a noob question but I've searched everywhere else and not come up with an answer.
Say I have a package with the following structure:
package main
import "username/myproject/subpackage"
func main() {
}
and a subpackage:
package subpackage
func main() {
}
This works fine and from reading other peoples code on Github, it seems like this is the accepted way to define subpackages.
See the CoreOS source as an example: https://github.com/coreos/etcd/blob/master/main.go
My problem is that due to the directory structure of Go, these packages are stored within a specific git repo and if someone else in the team checks out this code to work on, their directory structure will be different due to forking. The username in the paths and the import statements will change. This isn't helped by the fact we pull and push a lot to each other rather than using a centralised repo.
package main
import "otherusername/myproject/subpackage" (This line will have to be changed)
func main() {
}
Everything I have read about Go points to its usability in team environments so I'm wondering if I'm understanding the package system properly.
Ideally we would like to be able to call subpackages with relative paths. We are used to working with namespaces and I know Go doesn't have them. ie:
package main
import "myproject/subpackage"
func main() {
}
But Go can't find the file and I'm sure it's not the right way of doing it as no examples online use relative paths.
So a couple of questions:
-
Should packages have a defined owner and always keep that username as part of the import paths?
-
Should this "owner" repo be a centalised repository (say a company or organisation) that all code is pushed to / pulled from?
-
Should other team members working on a piece of code use it within the creators folder/namespace rather than their own?
-
Is there a way to define relative paths in import statements, and if so, why does no-one do it? Is it considered bad practice?
-
How is repo forking handled with Go subpackages?
Thanks.
答案1
得分: 15
简短版本:
-
包应该始终可以通过
go get package
进行获取(使用go get package
工作),所以99%的情况下,你的包应该是github.com/user/reponame
,并且在整个项目中都保持这个包。 -
是的,这应该是中央仓库,贡献者(内部员工或社区成员)应该向该仓库创建拉取请求,而不是直接在其上工作。
-
是的,他们应该在原始文件夹中使用它,并使用他们的git远程分支(见下文)。
-
不是和是的。你可以为非go-gettable包定义相对导入。例如,当你不在你的gopath中时,你可以使用
import "./subpackage"
。然而,如果你进入你的GOPATH,Go会抱怨你混合了本地和远程导入。一般情况下,不要使用相对导入。 -
分叉子包是通过分叉主包来处理的。
长版本:
我将以一个具有多个团队成员的Github仓库为例。
中央仓库将是http://github.com/central/repo
该仓库有子仓库,如github.com/central/repo/pkg,github.com/central/repo/whatever。
最简单且我认为最好的方法是使用git远程。
假设我想为一个子仓库(或其他任何内容)做贡献,这个过程很简单:就像在任何其他语言中一样,分叉该仓库。
现在,正如你提到的,你有一个带有导入的仓库副本,该导入指向中央仓库。实际上,这种方式并不实用。
这就是为什么(除了简单的小项目),我从不go get
我的分叉,而是go get
中央仓库,然后进入$GOPATH/src/github.com/central/repo
,并使用git remote add creack https://github.com/creack/repo
添加我的远程分支。
现在我可以在项目上工作,使用它就像它是中央仓库一样,一旦完成,我将我的分支推送到我的分叉上,然后创建一个拉取请求。
在这种情况下,分叉只是github上源代码的一个占位符,并且不会被使用。
英文:
Short version:
-
Package should always be go gettable (work with
go get package
), so 99% of the time, your package will begithub.com/user/reponame
and you always keep that across your project. -
Yes, this should be the central repo and contributor (internal employee or community) should create pull request to that repo, never actually work on it.
-
Yes, they should use it within the original folder with their git remote forked (see bellow)
-
No and Yes. You can define relative import for non go-gettable package. I.e. when your are not in your gopath, you can
import "./subpackage"
. However, if you go to your GOPATH, Go will complain that you mix local and remote imports. In the general case, don't use relative import. -
Forking of subpackage is handled by forking the main package.
Long version:
I'll take as example a Github repo with multiple team members.
Central repo would be http://github.com/central/repo
This repo has sub repos like github.com/central/repo/pkg, github.com/central/repo/whatever.
The easiest way and IMHO the best way is to use git remote.
Let's say I want to contribute to a subrepo (or anything for that matter), the process is simple: just like in any other language, fork the repo.
Now, as you mentioned, you have a copy of the repository with import which targets the central one. Not very practical to work with indeed.
This is why (expect for simple small projects), I never go get
my fork, I go get
the central repository, go to $GOPATH/src/github.com/central/repo
and add my remote with git remote add creack https://github.com/creack/repo
Now I can work on the project, use it as if it were the central one and once I am done, I push my branch to my fork, then create a pull request.
In this case, the fork is only a placeholder for the sources on github and is not used.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论