Git-系列
Git 熟知熟用
Git 规范与实践

commit message 规范

格式统一、清晰的 commit message 有助于更好的管理提交历史,方便查找、回滚。
Angular 的规范最为常用:Angular Team Commit SpecificationConventional Commits

格式
1
2
3
4
5
<type>[scope]: <subject>

[body]

[footer(s)]

在 VSCode 中,使用 git-commit-plugin 插件以快速生成 Angular 规范的 commit message。

参考:
Commit message 和 Change log 编写指南-阮一峰

type

type 用于说明 commit 的类别:

  1. init 初始化
  2. feat 新功能(feature)
  3. fix 修补 bug
  4. docs 仅修改了文档(documentation)
  5. style 修改格式
  6. refactor 重构,没有加新功能或修复 bug
  7. perf 性能优化
  8. test 修改测试相关代码
  9. build 修改项目构建系统,如修改依赖库、外部接口或者升级 Node 版本等
  10. ci 修改项目持续集成流程,如修改 Travis 配置文件等
  11. chore 对非业务性代码进行修改,如修改构建流程或者工具配置等
  12. revert 回滚版本

除了上述常见的 type,还可以根据项目的实际情况自定义 type,与其它开发者约定好即可。

scope

scope 用于说明 commit 影响的范围,提供上下文信息,是一个名词,可选提供。

应该根据具体项目而定,可以是某个模块、功能或其他任何限定的范围。

subject

subject 是 commit 目的的简短描述,不超过 50 个字符。

  1. 以动词开头,使用第一人称描述。
  2. 第一个字母小写。
  3. 结尾不加句号。

Body 是对本次 commit 的详细描述,包括具体的变化、原因等。

Footer 是补充信息:

  1. 关联 issue,如 Closes #123,表示本次 commit 针对该 issue。
  2. 不兼容变动,以 BREAKING CHANGE: 开头,接着是对变动的描述、理由和迁移方法。

工作流程

工作流 workflow,是指团队成员如何协作完成项目的一系列规范和流程。
在 Git 上即是如何设计分支、提交代码、避免冲突等,使项目像水流一样顺畅、有序地进行开发和维护。

常见工作流:

  1. GitFlow - Vincent Driessen 提出的一种工作流程,主要分为 feature、develop、release、hotfix、master 五种分支。其中 master 分支用于发布,develop 分支为主开发分支。
  2. GitHubFlow - Github 官方推荐的工作流程,主要分支只有 master,开发在新建分支上进行,开发完成后提交 PR 到 master 分支。当然也可以多增加一个 dev 作为主开发分支。
  3. GitLabFlow - GitLab 官方推荐的工作流程。上游优先,形成类似树形的结构,向上:从下游逐层合并到上游直到主分支,向下:只有上游分支采纳的代码变化,才能应用到其他下游分支。

三者均为功能驱动式开发(FDD)
先有需求再有功能分支或者补丁分支等,完成开发后,该分支就合并到主分支,然后被删除。

对比:

  1. GitFlow 过于复杂,分支多,适合版本发布项目,实际开发较难遵守。
  2. GitHubFlow 是 GitFlow 的简化版,简单易懂,适合持续发布项目,目前最为常用,适合中小项目。
  3. GitLabFlow 吸取了两者的优点,既有适应不同开发环境的弹性,又有单一主分支的简单和便利,适用于每次合并功能分支后不需马上部署至生产环境的大型项目。

一个 git 学习网站:learnGitBranching

参考:
四种常见的Git工作流
Git 工作流程-阮一峰
Git工作流面面观——Gitflow工作流
DevOps Guidebook-工作流
Git之GitFlow工作流 | Gitflow Workflow(万字整理,已是最详)

GitHubFlow

1、fork 项目仓库:
在 github 上 fork 项目仓库到自己的仓库。

2、clone 项目到本地:
clone 自己的仓库到本地。

1
git clone git@github.com:qcqx/git-test.git

3、添加上游远端仓库:
在 github 上可以看见本仓库是 fork 来的,但本地 git 并不知道,需要手动添加上游仓库,通常命名为 upstream

1
git remote add upstream git@github.com:qxchuckle/git-test.git

4、同步上游主开发分支:
开发过程中,上游仓库可能有新的提交,需要同步到本地。

通常 dev 分支为主开发分支,当然也有直接拿 main 分支开发的,看具体项目而定。

1
git pull upstream dev:dev

5、从主开发分支新建分支,用于开发新功能:
功能开发分支的命名:

  1. feat/feat- 开头,/ 开头是为了在使用某些 git 工具时,能显示出树形目录结构,方便查看。
  2. 后面跟上功能名,多个单词用 - 连接,如 feat/login
  3. 如果是为了解决某个 issue,可以在后面加上 issue 号,如 feat/iss-123
1
2
git switch dev
git checkout -b feat/new1

6、在新分支上开发:
写代码,提交 commit。

开发过程中可以定期同步下 dev 分支,以免最后合并时冲突太多。

定期同步 dev 分支
1
2
3
4
5
6
7
8
git fetch upstream dev
# 若 fetch 后有新提交,继续同步
# 使用 merge,同步上游 dev 分支
git switch dev
git merge upstream/dev
# 使用 rebase 同步功能开发分支和dev,有冲突则解决。
git switch feat/new1
git rebase upstream/dev # 通常会触发 Fast-forwarded

当然上面的操作可以简化,本地可以不存在一个 dev 分支,直接 rebase 到 upstream/dev。

7、开发完成,合并代码到主开发分支:
使用 merge 还是 rebase 合并,看具体项目规定了。

1
2
3
4
5
6
7
git switch dev
git merge feat/new1
# 或
git switch feat/new1
git rebase dev
git switch dev
git merge feat/new1 # 这是为了触发 Fast-forwarded,移动 dev 分支的 HEAD 到当前提交

8、同步最新上游 dev 分支:
在提交 PR 之前,再次同步上游 dev 分支,以免提交 PR 时有冲突。

1
2
3
4
git fetch upstream dev
# 若 fetch 后有新提交,继续同步
git switch dev
git merge upstream/dev # 有冲突则解决

9、推送代码到自己的仓库:

1
git push origin dev

10、提交 PR(Pull Request):
在 github 上提交 PR,通知上游仓库合并代码。

若需要压缩合并 commit,可以使用 rebase -i 合并 commit,或管理者用 squash merge 合并。

到这里功能开发就完成了,后面是项目管理者的工作了。若 PR 被打回,则修改后重新提交 PR。

11、管理者 code review:
管理者在项目仓库中进行 code review。

1
2
3
4
# 从 dev 分支上新建一个分支用于 code review
git checkout -b qcqx-dev dev
# 拉取 PR 分支到当前 qcqx-feature 分支
git pull https://github.com/qcqx/git-test.git dev

12、合并 PR:
在测试没问题、解决冲突后,管理者将 PR 合并到主开发分支并推送。

1
2
3
git switch dev
git merge --no-ff qcqx-dev
git push

现在 GitHubFlow 流程就结束了。可以选择删除 feat/new1 开发分支。

上面的步骤中,可以发现下游的 dev 分支不是必要的,只是起到一个中转作用,开发者可以直接将 feat 分支和 upstream/dev 进行同步。提 PR 时将 feat 分支合并到上游 dev 分支。这就看具体项目的规定了。

当然实际开发流程可能会有所不同,这里只是一个基本流程。

常见场景

记录一些常见场景下的 git 实践。

提交一个空文件夹

在文件夹中添加一个 .gitkeep 文件,然后提交。

查看某个文件历史

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 列出文件的所有提交记录
> git log --oneline <file>
# 查看文件的详细提交记录,包括 diff
> git log -p <file>
# 查看某个 commit 的详细信息,包括 diff
> git show c178bf49
# 显示某个文件的每个版本提交信息:提交日期,提交人员,版本号,提交信息,没有 diff
> git whatchanged <file>
# 显示文件的每一行最后修改的 commit 信息
> git blame <file>
13d78acb (qxchuckle 2024-05-12 16:46:29 +0800 1) console.log("1")
8fa8fd54 (qxchuckle 2024-05-12 16:47:41 +0800 2) console.log("2")
3ce8e33e (qxchuckle 2024-05-12 16:48:47 +0800 3) console.log("3")
5aa6a818 (qxchuckle 2024-05-12 16:31:50 +0800 4) console.log("4")

自定义 git 命令

git config --global alias.<alias-name> <command> 可以自定义 git 命令别名,方便使用。

1
2
3
4
5
6
git config --global alias.st status
git config --global alias.br branch
git config --global alias.co checkout
git config --global alias.ci commit
#使用
git st # git status

设置大小写敏感

在 Windows 下,git 默认大小写不敏感,即文件名大小写不同,git 仍然认为是同一个文件。

1
2
git config --get core.ignorecase # 查看git 的设置,默认为 true
git config core.ignorecase false # 设置大小写敏感

忽略文件的权限变化

文件权限的变化不再视为修改。

1
git config core.fileMode false