Git的使用
Git的工作方式
分为集中式工作流、功能分支工作流、Gitflow工作流和Forking,其中集中式工作流和功能分支工作流是已经使用过的,Gitflow和Forking两种工作流暂时没有使用过。
集中式工作流:一个远程仓库,一个主分支master,团队每个成员都有一个本地仓库,在本地仓库中进行代码的编辑、暂存和提交工作:
git add <some file> 或 git add .> //`some file`代表要暂存的文件,`.`代表工作目录下的所有文件 gie commit -m "一些描述" //提交文,描述指的是本次提交修改了什么功能或者修改了什么bug,方便以后的查看 git push origin master //发布本地仓库到远程的中央仓库中,origin是远程仓库名,master是参数告诉Git的分支,master代表主分支,当然分支可以不是主分支
注意:在一种情况下push命令会出错,即如果小明第一次发布代码到远程仓库,此时小红在本地开发自己的功能,那么在小红push自己的本地库到远程的时候会报错,原因是小红的本地库和远程库有分歧,需要先pull远程库到本地,与本地库合并之后再push到远程库。
功能分支工作流:在集中式工作流的基础上,为各个新功能分配一个专门的分支来开发,即在master主分支外在创建一个分支,程序员开发的新功能全部push到此分支上,等到功能成熟的时候再把此分支合并到主分支master上
git checkout -b newbranch master //checkout代表创建切换带新分支newbranch //-b代表如果新分支不存在则会创建一个新分支 //最后的master代表新分支是基于主分支创建的
新分支创建之后,对其的编辑、暂存和提交工作与之前一样,对其push的命令变为
git push origin newbranch
,等到新功能完善之后,通过以下命令:git checkout master git pull git pull origin newbranch git push
首先
git checkout master
切换到主分支,然后执行git pull
把本地仓库的主分支上传到远程库,再执行git pull origin newbranch
保证合并newbranch
分支和已经和远程一致的本地master分支,你可以使用简单git merge marys-feature
命令,但前面的命令可以保证总是最新的新功能分支。 最后把更新的master分支重新push到远程库。Gitflow工作流:除了有master主分支(用于存储正式发布的历史)外,还有一个作为功能集成分支的develop分支。
- 当初始化完成后,某个程序员想要开发一个性能,并不是直接从master分支上拉出新分支,而是使用develop分支作为父分支,当新功能完成后,再合并会父分支,新功能的提交并不与master分支直接交互。
Forking工作流:是分布式工作流,充分利用了Git在分支和克隆上的优势,既可以管理大团队的开发者(developer)和接受不信任贡献者(contributor)的提交。这种工作流使得每个开发者都有一个服务端仓库(此仓库只有自己可以push,但是所有人都可以pull修改),每个程序员都push代码到自己的服务端仓库,但不能push到正式仓库,只有项目维护者才能push到正式仓库,这样项目维护者可以接受任何开发者的提交,但无需给他正式代码库的写权限。
- 这种工作流适合网上开源社区的开源项目,大家统一对项目做贡献,但是有一个人或一个团队作为开发者来管理项目,所有的贡献者的代码由开发者审核,其功能完善之后再由开发者push到正式仓库中。
Pull Request
- Pull Request是一个为讨论提交功能的专门论坛,是一个友好的web界面(在个人github项目中也有这样一个选项),大家在其中做一些Code Review的工作,把结果反馈到Pull Request中,还可以在其中push新的提交微调功能,等到讨论结束后醒目维护者合并所有的功能到官方仓库中,关闭Pull Request。
- 发起一个Pull Request,就是要请求另一个开发者来pull自己仓库的一个分支到它的仓库中,因此需要提供四个信息:源仓库、源分支、目的仓库、目的分支。
- Pull Request可以用于上述除了集中式工作流的其他三种工作流,因为其要求要么分支不同,要么仓库不同,而集中式工作流只有一个仓库,一个master分支。
重构代码
- 在寒假和第一周的时间里,自己从头开始,使用golang+beego写了一个自己的博客系统,通过重写一遍后台管理系统的过程中,参考别人的成熟并优雅的设计,对自己以前的代码重构有着一些想法。
models文件夹
初始化文件init.go
- 此文件包含了beego的Orm初始化,包括:
//set defalut database
orm.RegisterDataBase("default", _DB_DRIVER, _DB_CONNECT_STR)
// register model
orm.RegisterModel(new(User), new(Article), new(Label))
// create table
orm.RunSyncdb("default", false, true)
其中_DB_DRIVER = "mysql"
,是数据库名字,_DB_CONNECT_STR="root:golang@/myblog?charset=utf8"
,root代表mysql的用户名,golang为其密码,@/
之后的myblog为mysql中此项目的数据库名字,charset=utf8
代表编码方式为utf8。注意:此时如果数据库中有关于时间相关的字段存入时,会发现存入的时间与实际的时间出入8个小时,原因见 Beego的ORM插入Mysql后,时区不一致的解决方案。
由于是初始化文件,因此最好包含初始化部分,为别人的使用留下方便,因为别人第一次使用你的系统的时候,首先他的数据库是空的,即user表中没有数据,其次对你的用户添加模式并不了解。下载的模板就是看了半天才发现其初始化是怎么做的。
如何使其生效?在main.go中写初始化函数,在此函数中调用它。
func init() {
models.Init()
}
其余文件(以user.go
为例)
- 最主要的是增删改查功能(以查找函数为例)
//以前的做法
//通过用户名查找用户
func (this *User) GetByUserName(UserName string) (*User, error) {
user := &User{}
o := orm.NewOrm()
err := o.QueryTable(_USER_TABLE).Filter("UserName", UserName).One(user)
if err != nil {
return nil, err
}
return user, nil
}
//通过用户Id查找用户
func (this *User) UserGetById(Id int64) (*User, error) {
user := new(User)
err := orm.NewOrm().QueryTable(_USER_TABLE).Filter("id", Id).One(user)
if err != nil {
return nil, err
}
return user, nil
}
//现在的做法
func (u *User) Read(fields ...string) error {
if err := orm.NewOrm().Read(u, fields...); err != nil {
return err
}
return nil
}
通过以上的函数可以看出来,以前的做法是先构造一个用户(可能是通过前端的信息获得,也可能是通过Session获得登录用户),再通过其用户名或者用户Id与数据库中的数据比对,再去判断是否有此用户,有则返回此用户,错误为空;否则用户为空,错误非空。
而现在更成熟的做法是:构造一个用户之后,直接调用user.Read()
函数,如果返回为空,证明此用户是合法的,直接对其进行后续的操作就可以了,否则此用户不合法,进行相应处理。
if uesr.Read()==nil{
//用户合法
} else {
//用户不合法,重新登录
}
- mysql的表之间的关联:之前是利用Orm的便利,直接利用
orm:"rel(m2m)"
和orm:"reverse(many)"
来表示关联表,但其实mysql本身的索引index也可以实现相应的功能,但是这样的话中间表需要自己手动建立,这方面的知识留待后续了解使用。
controllers文件夹
- 所有的控制文件都以
*Controller.go
结尾,用以和models中的同名文件冲突,例如BaseController.go
等。 - 写一个
BaseController.go
文件,其中的控制器BaseController
继承beego.Controller
,剩余的所有控制器都继承此控制器,这样做的好处是可以把一些公共的,大家都用得到的函数写到里面,比如说CheckLogin()
函数,即登录验证,这样就不用每个控制函数里面都写一个登录验证函数了。其调用部分写在BaseController.go
文件的Prepare()
里面,这样就不用在每个控制器函数文件中调用了,真正的一劳永逸。
views文件夹
- 根据页面功能的不同,可以将HTML文件放入到不同的文件夹中去,这样寻找起来就非常方便。
- 不必每个HTML文件都完全的有
head
、body
等,这些有多个页面同时共享的部分都可以写到一个页面layout.html
中,然后在相应的控制器函数中多写一句this.Layout="layout.html"
即可,可以使得页面的HTML文件大大简化,也使得其修改变得很方便beego的Layout设计。