# 1 commit 规范

# 1.1 规范

<type>(<scope>): <subject>

<body>

<footer>
1
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 准则

  1. 除了源码相关的内容,其他 build 产生的东西,均不能进入源码仓库,添加到 .gitingore 忽略掉。
  2. 撰写规范的提交说明。
  3. 严格按照流程切换指定分支工作。

# 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
1
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
1
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;
}
1
2
3
4
5
6
7

# 3.5 提交

git add main.c
git commit
1
2

commit 信息:

feat: 添加 a.c ,打印 hello,world

Issue #I6UNPC
1
2
3

# 3.6 添加代码再次提交

#include <stdio.h>

int main(void)
{
    printf("hello,world!\n);
    printf("hello,world!\n);
    return 0;
}
1
2
3
4
5
6
7
8
git add main.c
git commit
1
2

commit 信息:

feat: 再打印一行 hello,world

close #I6UNPC
1
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.
#

1
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
1
2
3
4
5
6
7
8

# 杂项

本地开发分支拉取远程开发分支用 rebase,开发分支合并主干分支的时候用 rebase,主干分支合并开发分支用 merge --no-ff,开发分支 push 前先同步代码,然后合并多次提交为一个,然后 push。

拉取主线,合并分支:git fetch get rebase

主线合并支线分支:git merge --no-ff

最后更新: 2023/11/7 08:36:05