1
1
# Git 工作流程
2
2
3
- 基于一个流行的 [ 项目开发指南] ( https://github.com/elsewhencode/project-guidelines ) ,本文描述了一个建议的 github 工作流程。和上述指南最大的不同是我们采用 master 分支作为主开发分支。另外创建专门的上线发布 release 分支。这样的好处是 master 在 github 是缺省的分支 ,变基,PR 和合并都比较自然。而且上线发布分支只有少数人关注,对开发人员越隐蔽越好。
3
+ 基于一个流行的 [ 项目开发指南] ( https://github.com/elsewhencode/project-guidelines ) ,本文描述了一个建议的 github 工作流程。和上述指南最大的不同是我们采用 develop 分支作为主开发分支。另外创建专门的上线发布 master 分支。这样的好处是 develop 是 ` master ` 的下游分支 ,变基,PR 和合并都比较自然。而且上线发布分支只有少数人关注,对开发人员越隐蔽越好。
4
4
5
- 具体项目可以定制工作流程。项目初期可以采用简化的工作流。比如,一个项目在初期只有一、二个人的时候,所有操作都在 master 分支 -- 但是上线前必须有 release 分支。
5
+ 具体项目可以定制工作流程。项目初期可以采用简化的工作流。比如,一个项目在初期只有一、二个人的时候,所有操作都在 develop 分支 -- 但是上线前必须有 master 分支。
6
6
7
7
分支类型:
8
8
9
- - release 分支:该分支在第一次上线之后,永远保持可随时上线状态,不允许直接在这个上面进行更改或者提交代码,只能从其他分支 merge。通过权限设置保持 ` release ` 分支中的代码稳定性。
10
- - master 分支:master 分支主要用于新版本的开发,代码第一次上线时,从 master 创建出 release 分支用于上线发布。所有后期版本开发都在 master 分支上进行。版本开发完毕之后,上线前,将 master 的修改合并到 release ,并做上线测试
11
- - 功能分支:每个版本的开发,会有很多独立功能,每个独立功能的开发,从 master 创建一个功能分支,并在功能分支上进行功能的开发,最后变基合并到 master 。
12
- - hotfix 分支:这种类型的分支是针对线上 bug 的紧急 fix,直接从 release 创建分支。修复,测试完毕之后,合并到 release 上线。然后相应应该也并入 master 分支。
9
+ - master 分支:该分支在第一次上线之后,永远保持可随时上线状态,不允许直接在这个上面进行更改或者提交代码,只能从其他分支 merge。通过权限设置保持 ` master ` 分支中的代码稳定性。
10
+ - develop 分支:develop 分支主要用于新版本的开发,代码第一次上线时,从 develop 创建出 master 分支用于上线发布。所有后期版本开发都在 develop 分支上进行。版本开发完毕之后,上线前,将 develop 的修改合并到 master ,并做上线测试
11
+ - 功能分支:每个版本的开发,会有很多独立功能,每个独立功能的开发,从 develop 创建一个功能分支,并在功能分支上进行功能的开发,最后变基合并到 develop 。
12
+ - hotfix 分支:这种类型的分支是针对线上 bug 的紧急 fix,直接从 master 创建分支。修复,测试完毕之后,合并到 master 上线。然后相应应该也并入 develop 分支。
13
13
14
14
一些原则:
15
15
19
19
20
20
这里有七条基本规则需要牢记和遵守:
21
21
22
- - 规则一:保护您的 ` master ` ,尤其是 ` release ` 分支改动需要特别授权。
22
+ - 规则一:保护您的 ` develop ` ,尤其是 ` master ` 分支改动需要特别授权。
23
23
24
24
为什么
25
25
29
29
30
30
为什么
31
31
32
- > 因为这样,所有的工作都是在专用的分支而不是在主分支上隔离完成的。它允许您提交多个合并请求 ` pull request ` (PR)而不会导致混乱。您可以持续迭代提交,而不会使得那些很可能还不稳定而且还未完成的代码污染 master 分支。
32
+ > 因为这样,所有的工作都是在专用的分支而不是在主分支上隔离完成的。它允许您提交多个合并请求 ` pull request ` (PR)而不会导致混乱。您可以持续迭代提交,而不会使得那些很可能还不稳定而且还未完成的代码污染 develop 分支。
33
33
34
- - 规则三:请使用合并请求(Pull Request)将功能分支合并到 ` master ` 。不允许直接合并。
34
+ - 规则三:请使用合并请求(Pull Request)将功能分支合并到 ` develop ` 。不允许直接合并。
35
35
36
36
为什么
37
37
43
43
44
44
> 因为您即将将代码提交到这个稳定的分支。而如果您的功能分支测试未通过,那您的目标分支的构建有很大的概率也会失败。此外,确保在进行合并请求之前应用代码规则检查。因为它有助于我们代码的可读性,并减少格式化的代码与实际业务代码更改混合在一起导致的混乱问题。
45
45
46
- - 规则五:在发起合并请求 PR 前,请更新您本地的` master ` 分支并且完成交互式变基操作(interactive rebase)。发起 PR 之前解决完潜在的冲突
46
+ - 规则五:在发起合并请求 PR 前,请更新您本地的` develop ` 分支并且完成交互式变基操作(interactive rebase)。发起 PR 之前解决完潜在的冲突
47
47
48
48
为什么
49
49
50
- > rebase 操作会将功能分支合并到被请求合并的 master 分支,并将您本地进行的提交应用于所有历史提交的最顶端,而不会去创建额外的合并提交(假设没有冲突的话),从而可以保持一个漂亮而干净的历史提交记录。 [ 合并(merge)和变基(rebase)的比较] ( https://www.atlassian.com/git/tutorials/merging-vs-rebasing )
50
+ > rebase 操作会将功能分支合并到被请求合并的 develop 分支,并将您本地进行的提交应用于所有历史提交的最顶端,而不会去创建额外的合并提交(假设没有冲突的话),从而可以保持一个漂亮而干净的历史提交记录。 [ 合并(merge)和变基(rebase)的比较] ( https://www.atlassian.com/git/tutorials/merging-vs-rebasing )
51
51
52
52
- 规则六:请确保在 PR 合并分支后删除本地和远程功能分支。
53
53
54
54
为什么
55
55
56
- > 如果不删除需求分支,大量僵尸分支的存在会导致分支列表的混乱。而且该操作还能确保有且仅有一次合并到` master ` 。只有当这个功能还在开发中时对应的功能分支才存在。
56
+ > 如果不删除需求分支,大量僵尸分支的存在会导致分支列表的混乱。而且该操作还能确保有且仅有一次合并到` develop ` 。只有当这个功能还在开发中时对应的功能分支才存在。
57
57
58
58
- 规则七:给出清晰的提交信息(commit message)。具体要求参见后门的建议。
59
59
65
65
66
66
基于以上原因, 我们将 [ 功能分支工作流] ( https://www.atlassian.com/git/tutorials/comparing-workflows#feature-branch-workflow ) , [ 交互式变基的使用方法] ( https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing ) 结合一些 [ Gitflow] ( https://www.atlassian.com/git/tutorials/comparing-workflows#gitflow-workflow ) 中的基础功能一起使用。 主要步骤如下:
67
67
68
- ### 2.1 项目初始建立` master ` 和 ` release ` 二个分支
68
+ ### 2.1 项目初始建立` develop ` 和 ` master ` 二个分支
69
69
70
- - 针对一个新项目, 在 github 上创建项目的 repo,同时用 github 界面创建 ` release ` 发行分支仅用于新版本发布上线。 ` clone ` 到本地后,只基于 ` master ` 分支做开发:
70
+ - 针对一个新项目, 在 github 上创建项目的 repo,同时用 github 界面创建 ` master ` 发行分支仅用于新版本发布上线。 ` clone ` 到本地后,只基于 ` develop ` 分支做开发:
71
71
72
72
``` sh
73
73
git clone < 项目地址> # clone the remote repository
74
74
```
75
75
76
76
### 2.2 创建功能分支做具体开发
77
77
78
- - 第一步:检出(Checkout)一个新的功能或故障修复(feature/bug-fix)分支或用 github 界面基于` master ` 创建功能分支。下面是命令行创建功能分支并同步到服务器。随时用 ` git branch -a ` 检查当前分支状态。
78
+ - 第一步:检出(Checkout)一个新的功能或故障修复(feature/bug-fix)分支或用 github 界面基于` develop ` 创建功能分支。下面是命令行创建功能分支并同步到服务器。随时用 ` git branch -a ` 检查当前分支状态。
79
79
80
80
``` sh
81
81
git checkout -b my-feature # create a new branch my-feature from the current branch
@@ -95,31 +95,31 @@ git push # push to remote frequently to bakcup changes
95
95
96
96
> ` git commit -a ` 会独立启动一个编辑器用来编辑您的说明信息,这样的好处是可以专注于写这些注释说明。请参考下面关于说明信息的要求。经常同步到远程库做备份。通常在 IDE 里执行上面三个操作也可以,注意当前分支为功能分支就好。
97
97
98
- ### 2.3 合并功能分支到 ` master ` 分支
98
+ ### 2.3 合并功能分支到 ` develop ` 分支
99
99
100
- 当功能开发完成时,要将所做工作变基并入 ` master ` 分支。
100
+ 当功能开发完成时,要将所做工作变基并入 ` develop ` 分支。
101
101
102
- - 第一步:在准备提交合并前, 先将需要 ` master ` 分支更新到最新。下面的步骤建议手工运行。
102
+ - 第一步:在准备提交合并前, 先将需要 ` develop ` 分支更新到最新。下面的步骤建议手工运行。
103
103
104
104
``` sh
105
- git checkout master
105
+ git checkout develop
106
106
git pull
107
107
```
108
108
109
109
为什么
110
110
111
- > 更新 ` master ` 代码版本有助于发现可能的冲突。当您进行(稍后)变基操作的时候,保持更新会给您一个在您的机器上解决冲突的机会。这比(不同步更新就进行下一步的变基操作并且)发起一个与远程仓库冲突的合并请求要好。
111
+ > 更新 ` develop ` 代码版本有助于发现可能的冲突。当您进行(稍后)变基操作的时候,保持更新会给您一个在您的机器上解决冲突的机会。这比(不同步更新就进行下一步的变基操作并且)发起一个与远程仓库冲突的合并请求要好。
112
112
113
- - 第二步:切换至功能分支,把功能分支变基到` master ` 分支,建议采用` rebase -i --autosquash ` 的交互方式
113
+ - 第二步:切换至功能分支,把功能分支变基到` develop ` 分支,建议采用` rebase -i --autosquash ` 的交互方式
114
114
115
115
``` sh
116
116
git checkout my-feature
117
- git rebase -i --autosquash master
117
+ git rebase -i --autosquash develop
118
118
```
119
119
120
120
为什么
121
121
122
- > 您可以使用 ` --autosquash ` 将所有提交压缩到单个提交。没有人会愿意(看到) ` master ` 分支中的单个功能开发就占据如此多的提交历史。 [ 更多请阅读...] ( https://robots.thoughtbot.com/autosquashing-git-commits )
122
+ > 您可以使用 ` --autosquash ` 将所有提交压缩到单个提交。没有人会愿意(看到) ` develop ` 分支中的单个功能开发就占据如此多的提交历史。 [ 更多请阅读...] ( https://robots.thoughtbot.com/autosquashing-git-commits )
123
123
124
124
- 第三步(可能需要):这一步在没有代码冲突可以跳过。如果您有代码合并冲突, 就需要[ 解决它们] ( https://help.github.com/articles/resolving-a-merge-conflict-using-the-command-line/ ) 。
125
125
@@ -138,7 +138,7 @@ git push -f
138
138
139
139
> 当您进行 rebase 操作时,您会改变功能分支的提交历史。下一步的合并请求(PR)是基于远程库进行的。这一步把本地的变基操作及修改同步到远程库。由于变基会导致 Git 拒绝正常的 ` git push ` 。能使用 ` -f ` 或 ` --force ` 或当多人在同一分支合作时用 ` --force-with-lease ` 参数了。[ 更多请阅读...] ( https://developer.atlassian.com/blog/2015/04/force-with-lease/ )
140
140
141
- - 第五步:提交一个合并请求(Pull Request)。Pull Request 会被负责代码审查的同事接受,合并和关闭 。合并请求完成同时需要删除远程的功能分支。这些操作都利用 github 的用户界面进行。如果代码需要进一步的修改完善,请回到第一步。
141
+ - 第五步:提交一个合并请求(Pull Request)。Pull Request 会被负责代码审查的同事和测试人员接受,组内人员负责审查代码质量,测试人员验证功能的正确性。两名人员接受之后才能合并和关闭 。合并请求完成同时需要删除远程的功能分支。这些操作都利用 github 的用户界面进行。如果代码需要进一步的修改完善,请回到第一步。
142
142
143
143
为什么
144
144
@@ -147,22 +147,63 @@ git push -f
147
147
- 第六步:合并完成后,记得删除您的本地分支。
148
148
149
149
``` sh
150
- git checkout master
150
+ git checkout develop
151
151
git branch -d < 分支>
152
152
```
153
153
154
154
(使用以下代码)删除所有已经不在远程仓库维护的分支。
155
155
156
156
``` sh
157
- git checkout master
157
+ git checkout develop
158
158
git fetch -p
159
159
git branch -D featureBranch
160
160
```
161
161
162
- ### 2.4 版本发布到` release ` 分支
162
+ ### 2.4 版本发布到` master ` 分支
163
163
164
164
由程序员、运维人员和项目经理共同决定发布的时机。具体流程另外描述。
165
165
166
+ 发版的人先从github发起一个从 ` develop ` 到 ` master ` 分支的 ` PR ` ,并且把这个 ` PR ` 发给产品和项目经理review,产品主要负责审查发版的内容是否符合预期,如果符合预期通知发版的人发demo环境进行验证,验证通过之后,产品再接受这个 ` PR ` 。如果遇到develop分支有些feature并不想都发版,那可以基于develop分支checkout一个` prerelease ` 分支,在这个 ` prerelease ` 分支上面去掉那些不需要发版的commit,再提一个从prerelease分支到master分支的PR
167
+
168
+ ``` sh
169
+ git checkout -b prerelease develop
170
+ git checkout master
171
+ git pull
172
+ git checkout prerelease
173
+ git rebase -i master
174
+
175
+ # 手动删掉不准备发版的commit
176
+ git rebase --continue
177
+
178
+ # 在github提一个从prerelease到master的PR
179
+ ```
180
+
181
+ 为什么
182
+
183
+ > 有可能几个feature是同时进行也都合并进了develop分支,但是产品可能暂时只想发其中某一些feature,这时候我们需要单独把这些feature拎出来合并进master,所以需要一个中间分支prerelease分支
184
+
185
+ ### 2.5 hotfix
186
+
187
+ hotfix 通常是指线上环境出现的需要紧急修复的bug,通常先从` master ` 分支切一个` hotfix ` 分支出来,测试验证通过再合并进去,然后确保这个修复已经同步到` develop ` 分支
188
+
189
+ ``` sh
190
+ git checkout master
191
+ git pull
192
+ git checkout -b hotfix-train-ticket
193
+
194
+ # github提PR到master分支,合并之后继续一下的步骤
195
+ git checkout develop
196
+ git pull
197
+ git checkout -b fix-train-ticket
198
+ git cherry-pick ${commitID} # commitID为hotfix分支对应的commitid
199
+
200
+ # github提PR到develop分支,请关联issueID(如果有的话)和之前到master分支的PR ID
201
+ ```
202
+
203
+ 为什么
204
+
205
+ > 所有的热修复都需要立即上线去解决用户的困扰的,所以需要马上合并到master,而develop很可能有新的feature暂时不能发版,所以需要通过cherry-pick把这些修复单独同步到develop,防止下次发版的时候把master上面的修复覆盖掉。
206
+
166
207
## 3 如何写好 Commit Message
167
208
168
209
坚持遵循关于提交的标准指南,会让在与他人合作使用 Git 时更容易。这里有一些经验法则 ([ 来源] ( https://chris.beams.io/posts/git-commit/#seven-rules ) ):
@@ -188,3 +229,16 @@ git branch -D featureBranch
188
229
> 与其在写下的信息中描述提交者做了什么,不如将这些描述信息作为在这些提交被应用于该仓库后将要完成的操作的一个说明。[ 更多请阅读...] ( https://news.ycombinator.com/item?id=2079612 )
189
230
190
231
- 使用主体部分去解释 ** 是什么** 和 ** 为什么** 而不是 ** 怎么做** 。
232
+
233
+
234
+ ## 4 总结Git工作流如下
235
+
236
+ 1 . feature分支往develop合并采用squash策略,需要测试人员验证通过approve
237
+ 2 . 发版的时候develop分支往master分支合并,采用merge策略
238
+ 1 . 开发人员从develop分支(或者prerelease分支)提PR到master
239
+ 2 . 产品审核PR信息,确认发版内容
240
+ 3 . 确认通过之后通知开发人员发demo环境
241
+ 4 . demo验证通过,产品接受PR
242
+ 5 . 开发merge这个PR,删除prerelease分支(如果有)
243
+ 3 . 发版操作由每个仓库的owner来负责,需要更新代码中的version和打tag
244
+ 4 . hotfix需要基于master分支切出来,合并进去之后通知发版的人,并且同时基于最新的develop切一个修复分支出来,cherry-pick刚刚那个修复的commit,再合并回develop,分支的合并过程同上
0 commit comments