在复杂项目中,特别是多团队的快速迭代中,版本管理与分支管理,总是我们难以回避的问题,这里分享一下我们在团队中使用的规范,以及对应的每一步的步骤。
团队开发中,遵循一个合理、清晰的Git使用流程,是非常重要的。
否则,每个人都提交一堆杂乱无章的commit,项目很快就会变得难以协调和维护。
没有规则的分支管理,同样会使版本变得混乱,系统难以进行持续发布、持续集成。
软件版本号有四部分组成,第一部分为主版本号,第二部分为次版本号,第三部分为修订版本号,第四部分为日期版本号加希腊字母版本号,希腊字母版本号共有五种,分别为base、alpha、beta 、RC 、 release。
如此时版本号为:1.0.0.0321_alpha ,此时为内部测试阶段。
开发人员修复了测试人员提交的bug并经测试人员测试验证关闭bug之后,发布到外网时,此时就进入了软件的下一个阶段,版本号可改为:1.0.0.0321_beta ,如当前日期跟上一个版本号的日期不一样,版本号可改为:1.0.0.0322_beta。
如果修复了一些重大Bug 并按照流程发布到外网时就可发布一个修订版,如1.0.1.0322_beta,日期为发布的当前日期。
如果对软件进行了一些功能上的改进或增强,进行了一些局部变动的时候要修改次版本号,如:1.1.0.0322_beta(上一级有变动时,下级要归零)。
当功能模块有较大变动,增加模块或整体架构发生变化时要修改主版本号,如新增加了退款功能,则版本号要改为:2.0.0.0322_beta 。
在工作中,用一个分支来处理开发、测试、发布、线上hotfix等等流程是难以控制的:项目上线前你只想让其他人提交一个小修改,结果fetch下来的是另一个人为下次上线提交上来的几百个文件修改。
GIT提供了良好的分支管理功能,通过对分支的规划管理,能够有效管理项目,保证软件质量,提高工作效率,有利于CI/CD的推进。
master分支上存放的应该是随时可供在生产环境中部署的代码(Production Ready state)。当开发活动告一段落,产生了一份新的可供部署的代码时,master分支上的代码会被更新。同时,每一次更新,添加对应的版本号标签(TAG)。
dev分支包含开发过程中最新的提交变更。有人会称之为"集成分支"。该分支是自动化每日构建的代码源。
当dev分支上的源码到达一个稳定的状态时,就可以发布版本。所有dev上的变更都会在到达一定阶段时合并进release分支,每次测试环境的发版需要版本更新。
dev分支是保存当前最新开发成果的分支。通常这个分支上的代码也是可进行每日夜间发布的代码(Nightly build)。因此这个分支有时也可以被称作"integration branch"。
当dev分支上的代码已实现了软件需求说明书中所有的功能,通过了所有的测试后,并且代码已经足够稳定时,就可以将所有的开发成果合并进release分支了。
对于release、master分支上的新提交的代码建议都打上一个新的版本号标签(TAG),供后续代码跟踪使用。因此,每次将dev分支上的代码合并回release分支时,我们都可以认为一个新的可供在准生产环境中部署的版本就产生了。当release分支上的代码合并回master分支时,一个新的可供在生产环境中部署的版本就产生了。
通常而言,"仅在发布新的可供部署的代码时才更新master分支上的代码"是推荐所有人都遵守的行为准则。基于此,理论上说,每当有代码提交到master分支时,我们可以使用Git Hook触发软件自动测试以及生产环境代码的自动更新工作。这些自动化操作将有利于减少新代码发布之后的一些事务性工作。
从master分支切出dev分支:git checkout -b(如果不存在 dev 分支,则加-b,已存在则不加) dev
该版本主要特性都实现且无明显bug时切换至release分支:git checkout release
合并dev分支代码至release:git merge –no-ff dev
辅助分支是用于组织解决特定问题的各种软件开发活动的分支。辅助分支主要用于组织软件新功能的并行开发、简化新功能开发代码的跟踪、辅助完成版本发布工作以及对生产代码的缺陷进行紧急修复工作。这些分支与主分支不同,通常只会在有限的时间范围内存在。
“辅助分支”,大体包括如下几类:"管理功能开发"的分支、"帮助构建可发布代码"的分支、"可以便捷的修复发布版本关键BUG"的分支等等。
feature分支(有时也被称作topic分支)是用来为下一发布版本开发新特性。当开始开发一个特性的时候,该feature会成为哪个发布版本的一部分,可能还不知道。feature分支的重点是,只要特性还在开发,该分支就会一直存在,不过它最终会被合并回dev分支(将该特性加入到发布版本中),或者被丢弃(如果试验的结果令人失望)。
feature分支代码可以保存在开发者自己的代码库中而不强制提交到主代码库里,或者某一个小组创建一个临时的用于一个较大功能的开发。
Feature分支每天从dev分支获取最新代码,进行代码合并,避免累积过多更新,导致合并代码时出现太多冲突代码。
Feature分支每天将自测通过没有问题的代码合并后提交至中央仓库,进行每日构建。
release分支用于进行生产部署,此分支为迭代内容在dev实现并已基本稳定,此版本发布为beta版。
release分支为准备新的产品版本发布做支持。它允许你在最后时刻检查所有的细节。此外,它还允许你修复小bug以及准备版本发布的元数据(例如版本号,构建日期等等)。在release分支做这些事情之后,dev分支就会显得比较干净,也方便为下一大版本发布添加新的功能。
从 dev分支合并发布分支的时间通常是dev分支(差不多)能反映新版本所期望状态的时候。也就是说,这是时候将版本发布所计划的特性都已经合并回了dev分支。而未来其它版本发布计划的特性则不应该合并,它们必须等到当前的版本分支创建好之后才能合并。
在release分支更新的时候,对应的版本发布才获得一个版本号。在该时刻之前,dev分支反映的是"下一版本"的相关变更,但不知道这"下一版本"到底会成为0.1还是1.0,直到release分支被创建。版本号是在发布分支创建时,基于项目版本号规则确定的。
更新后打上对应版本号标签(TAG)。
hotfix分支和release分支十分类似,它的目的也是发布一个新的产品版本,尽管是不在计划中的版本发布。当产品版本发现未预期的问题的时候,就需要理解着手处理, 这个时候就要用到hotfix分支。当产品版本的重大bug需要立即解决的时候,我们从对应版本的标签创建出一个hotfix分支。
使用hotfix分支的主要作用是(dev分支上的)团队成员可以继续工作,而另外的人可以在hotfix分支上进行快速的产品bug修复。
与hotfix类似,用于修复release分支的bug。
在了解如何review之前先明确几个观点:
同大多数 VCS 一样,Git 也可以对某一时间点上的版本打上标签。人们在发布某个软件版本(比如 v1.0 等等)的时候,经常这么做。本节我们一起来学习如何列出所有可用的标签,如何新建标签,以及各种不同类型标签之间的差别。
列出现有标签的命令非常简单,直接运行 git tag 即可:
$ git tag
v0.1
v1.3
显示的标签按字母顺序排列,所以标签的先后并不表示重要程度的轻重。
我们可以用特定的搜索模式列出符合条件的标签。在 Git 自身项目仓库中,有着超过 240 个标签,如果你只对 1.4.2 系列的版本感兴趣,可以运行下面的命令:
$ git tag -l 'v1.4.2.*'
v1.4.2.1
v1.4.2.2
v1.4.2.3
v1.4.2.4
Git 使用的标签有两种类型:轻量级的(lightweight)和含附注的(annotated)。轻量级标签就像是个不会变化的分支,实际上它就是个指向特定提交对象的引用。而含附注标签,实际上是存储在仓库中的一个独立对象,它有自身的校验和信息,包含着标签的名字,电子邮件地址和日期,以及标签说明,标签本身也允许使用 GNU Privacy Guard (GPG) 来签署或验证。
一般我们都建议使用含附注型的标签,以便保留相关信息;当然,如果只是临时性加注标签,或者不需要旁注额外信息,用轻量级标签也没问题。
创建一个含附注类型的标签非常简单,用 -a (译注:取 annotated 的首字母)指定标签名字即可:
$ git tag -a v1.4 -m 'my version 1.4'
$ git tag
v0.1
v1.3
v1.4
而 -m 选项则指定了对应的标签说明,Git 会将此说明一同保存在标签对象中。如果没有给出该选项,Git 会启动文本编辑软件供你输入标签说明。
可以使用 git show 命令查看相应标签的版本信息,并连同显示打标签时的提交对象。
$ git show v1.4
tag v1.4
Tagger: Scott Chacon <[email protected]>
Date: Mon Feb 9 14:45:11 2009 -0800
my version 1.4
commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: Scott Chacon <[email protected]>
Date: Sun Feb 8 19:02:46 2009 -0800
Merge branch 'experiment'
我们可以看到在提交对象信息上面,列出了此标签的提交者和提交时间,以及相应的标签说明。
如果你有自己的私钥,还可以用 GPG 来签署标签,只需要把之前的 -a 改为 -s (译注: 取 signed 的首字母)即可:
$ git tag -s v1.5 -m 'my signed 1.5 tag'
You need a passphrase to unlock the secret key for
user: "zero "
1024-bit DSA key, ID F721C45A, created 2021-01-09
现在再运行 git show 会看到对应的 GPG 签名也附在其内:
$ git show v1.5
tag v1.5
Tagger: zero <[email protected]>
Date: Mon Feb 9 15:22:20 2021 -0800
my signed 1.5 tag
----BEGIN PGP SIGNATURE----
Version: GnuPG v1.4.8 (Darwin)
iEYEABECAAYFAkmQurIACgkQON3DxfchxFr5cACeIMN+ZxLKggJQf0QYiQBwgySN
Ki0An2JeAVUCAiJ7Ox6ZEtK+NvZAj82/
=WryJ
----END PGP SIGNATURE----
commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: zero <[email protected]>
Date: Sun Feb 8 19:02:46 2021 -0800
Merge branch 'experiment'
轻量级标签实际上就是一个保存着对应提交对象的校验和信息的文件。要创建这样的标签,一个 -a,-s或 -m 选项都不用,直接给出标签名字即可:
$ git tag v1.4-lw
$ git tag
v0.1
v1.3
v1.4
v1.4-lw
v1.5
现在运行 git show 查看此标签信息,就只有相应的提交对象摘要:
$ git show v1.4-lw
commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: zero <[email protected]>
Date: Sun Feb 8 19:02:46 2020 -0800
Merge branch 'experiment'
后期加注标签
你甚至可以在后期对早先的某次提交加注标签。比如在下面展示的提交历史中:
$ git log --pretty=oneline
15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment'
a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support
0d52aaab4479697da7686c15f77a3d64d9165190 one more thing
6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment'
0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function
4682c3261057305bdd616e23b64b0857d832627b added a todo file
166ae0c4d3f420721acbb115cc33848dfcc2121a started write support
9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile
964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo
8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme
我们忘了在提交 “updated rakefile” 后为此项目打上版本号 v1.2,没关系,现在也能做。只要在打标签的时候跟上对应提交对象的校验和(或前几位字符)即可:
$ git tag -a v1.2 9fceb02
可以看到我们已经补上了标签:
$ git tag
v0.1
v1.2
v1.3
v1.4
v1.4-lw
v1.5
$ git show v1.2
tag v1.2
Tagger: zero <[email protected]>
Date: Mon Feb 9 15:32:16 2021 -0800
version 1.2
commit 9fceb02d0ae598e95dc970b74767f19372d61af8
Author: zero <[email protected]>
Date: Sun Apr 27 20:43:35 2021 -0700
updated rakefile
…
默认情况下,git push 并不会把标签传送到远端服务器上,只有通过显式命令才能分享标签到远端仓库。其命令格式如同推送分支,运行 git push origin [tagname] 即可:
$ git push origin v1.5
[new tag] v1.5 -> v1.5
如果要一次推送所有本地新增的标签上去,可以使用 --tags 选项:
$ git push origin --tags
[new tag] v0.1 -> v0.1
[new tag] v1.2 -> v1.2
[new tag] v1.4 -> v1.4
[new tag] v1.4-lw -> v1.4-lw
[new tag] v1.5 -> v1.5
现在,其他人克隆共享仓库或拉取数据同步后,也会看到这些标签。
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
Exclude maven wrapper
!/.mvn/wrapper/maven-wrapper.jar
*.class
.svn
_svn
BlueJ files
*.ctxt
Mobile Tools for Java (J2ME)
.mtj.tmp/
Package Files #
*.jar
*.war
*.ear
STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/
/.mvn/
/mvnw
/mvnw.cmd
Windows:
Thumbs.db
ehthumbs.db
Desktop.ini
有些时候,你想添加一个文件到Git,但发现添加不了,原因是这个文件被.gitignore忽略了:
$ git add App.class
The following paths are ignored by one of your .gitignore files:
App.class
Use -f if you really want to add them.
如果你确实想添加该文件,可以用-f强制添加到Git:
$ git add -f App.class
或者你发现,可能是.gitignore写得有问题,需要找出来到底哪个规则写错了,可以用git check-ignore命令检查:
$ git check-ignore -v App.class
.gitignore:3:*.class App.class
Git会告诉我们,.gitignore的第3行规则忽略了该文件,于是我们就可以知道应该修订哪个规则。
• 忽略某些文件时,需要编写.gitignore;
•.gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理!