# 1 commit 规范
# 1.1 规范
<type>(<scope>): <subject>
<body>
<footer>
2
3
4
5
Header 是必需的, Body 和 Footer 是默认忽略的。
type(必须)
用于说明 commit 的类别。
- feat:一个新功能。
- fix:修复 bug。
- docs:修改文档。
- style:修改格式(不影响代码运行)。
- refactor: 重构。
- test:测试。
- chore:非 src 路径文件和测试文件的修改,如 .gitignore,.editconfig 等。
- revert: 代码回退
type 为 feat 或 fix 则该 commit 肯定出现在 change log 中。
scope:用于说明 commit 影响的范围。
subject 是 commit 的简短描述。建议以动词开头。不加句号。
Body
Body 部分是对本次 commit 的详细描述。
Footer
只用于两种情况:
- 不兼容变动,以 BREAKING CHANGE: 开头,后面是对变动的描述以及变动理由和迁移方法。
- 处理 issue。
处理 issue 格式:
本次提交与某个 issue 有关系:
issue #1,#2,#3
当前提交信息解决了某个 issue:
close #1,#2,#3
Issue
Github 的 issue 功能是一个轻量级的协作系统。
issue 可以有额外的属性:
- labels,标签,表示 issue 的类型,解决的方式。
- Milestone,里程碑。作为 issue 的一个集合,如 demo,release 等。通常用来表示项目的一个阶段。
- Assignee,负责人。这个 issue 由谁负责。
Projects
Github 的项目管理系统,可以创建 kanban、todolist等。
# 1.2 准则
- 除了源码相关的内容,其他 build 产生的东西,均不能进入源码仓库,添加到
.gitingore
忽略掉。 - 撰写规范的提交说明。
- 严格按照流程切换指定分支工作。
# 2 gitlab flow
GitLab 工作流结合了特性驱动开发和特性分支,并且包含了议题追踪。
Git flow 对于大部分使用场景来说太复杂了,github flow 只适用于持续发布的场景。
gitlab flow是 Git flow 与 Github flow 的综合。它吸取了两者的优点,既有适应不同开发环境的弹性,又有单一主分支的简单和便利。
Gitlab flow 的最大原则叫做"上游优先"(upsteam first),即只存在一个主分支master,它是所有其他分支的"上游"。只有上游分支采纳的代码变化,才能应用到其他分支。
# 2.1 持续发布
对于"持续发布"的项目,它建议在master分支以外,再建立不同的环境分支。比如,"开发环境"的分支是master,"预发环境"的分支是pre-production,"生产环境"的分支是production。
开发分支是预发分支的"上游",预发分支又是生产分支的"上游"。代码的变化,必须由"上游"向"下游"发展。比如,生产环境出现了bug,这时就要新建一个功能分支,先把它合并到master,确认没有问题,再cherry-pick到pre-production,这一步也没有问题,才进入production。
# 2.2 版本发布
只有在需要向外界发布软件时才应该使用发布分支。 在这种情况下,每个分支都包含一个次要版本,例如 2.3-stable 或 2.4-stable:
从 main 创建一个 stable 分支作为起点,并且这个分支尽可能的新。 这样,您能减少后续不得不将漏洞修复代码部署到多个分支的情况。声明了一个发布分支后,这个分支只会合并严重的漏洞修复更新。 尽可能先将漏洞修复的更新合并到 main,然后拣选(cherry-pick)到发布分支。
每次您将漏洞修复包含到一个 release 分支,通过设置新的标签的方式提升补丁(patch)版本,在这个工作流里,不推荐使用生产分支。
# 2.3 issue 追踪
任何重大的代码变更需要由一个阐明目的的议题发起。 每个代码变更都有原因,可以帮助团队其他成员了解变更,并且保持特性分支的变更覆盖范围比较小。
当您准备好去编写代码时,从 main 分支为这个议题创建一个分支。这个分支就是接下来做与之相关的变更的地方。
feature 分支命名规范:feature-x
。
完成代码编写后,推送分支到远程,创建一个 PR。
PR 合并策略是非快进合并。 在合并之后,删除对应的特性分支。
# 2.4 rebase 聚合多个提交
PR 之前,尽量将多个提交合并成一个,如果有其他贡献者在同一个分支工作,您应当避免对推送到远程仓库的提交进行 rebase。
使用 rebase -i 选择多个提交聚合成一个。
pick c6ee4d3 add a new file to the repo
pick c3c130b change readme
2
如果在创建特性分支后,您需要采用一些 main 中采纳的新的代码,通常可以通过拣选(cherry-pick)一个提交来解决这个问题。
# 3 实践
# 3.1 创建远程仓库
在 gitee 上创建:git@gitee.com:guokzhao/gitlab-flow.git
。
# 3.2 创建本地库
git init
git branch -M main
git remote add origin git@gitee.com:guokzhao/gitlab-flow.git
git add README.md
git commit -m "docs: 第一次提交"
git push origin main
2
3
4
5
6
# 3.2 创建 issue
创建 issue:打印 hello,world 两次。链接为:I6UNPC
。
# 3.3 创建分支并推送到远程
git checkout -b feature-01
git push origin feature-01
# 3.4 创建文件 main.c
#include <stdio.h>
int main(void)
{
printf("hello,world!\n);
return 0;
}
2
3
4
5
6
7
# 3.5 提交
git add main.c
git commit
2
commit 信息:
feat: 添加 a.c ,打印 hello,world
Issue #I6UNPC
2
3
# 3.6 添加代码再次提交
#include <stdio.h>
int main(void)
{
printf("hello,world!\n);
printf("hello,world!\n);
return 0;
}
2
3
4
5
6
7
8
git add main.c
git commit
2
commit 信息:
feat: 再打印一行 hello,world
close #I6UNPC
2
3
# 3.7 合并 commit 后 push 并 pull request
现在 issue I6UNPC 的任务完成,推送到远程并发起 PR。
git rebase -i HEAD~2
此时交互式合并提交:
pick 703b323 feat: 添加 a.c ,打印 hello,world
s 6246c20 feat: 再打印一行 hello world
# Rebase 09adccb..6246c20 onto 09adccb (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
# commit's log message, unless -C is used, in which case
# keep only this commit's message; -c is same as -C but
# opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# create a merge commit using the original merge commit's
# message (or the oneline, if no original merge commit was
# specified); use -c <commit> to reword the commit message
# u, update-ref <ref> = track a placeholder for the <ref> to be updated
# to this position in the new commits. The <ref> is
# updated at the end of the rebase
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
其中 s 表示合并到前一个提交。
git push origin feature-01
在 github 发起 PR。
# 3.8 审查代码并接受 PR
审核 PR 并测试,然后通过 PR,关闭 issue 和 feature 分支。
# 3.9 本地更新 main 分支并删除 feature 分支
git checkout main
git fetch origin main
git merge origin/main
# 删除本地的远程追踪分支
git branch -D feature-01
git branch -d --remote origin/feature-01
# 或者本地删除远程分支
git push origin -d feature-01
2
3
4
5
6
7
8
# 杂项
本地开发分支拉取远程开发分支用 rebase,开发分支合并主干分支的时候用 rebase,主干分支合并开发分支用 merge --no-ff,开发分支 push 前先同步代码,然后合并多次提交为一个,然后 push。
拉取主线,合并分支:git fetch
get rebase
。
主线合并支线分支:git merge --no-ff
。