1. 前言
随着前端项目数量、前端开发人员、前端业务的日渐增多,则非常有必要整理一份简单的 git 规范,来进行项目开发的规范化约束。本文包括开发常用 git 指令、git 分支管理规范、git 提交规范等。
2. git 常用指令
2.1. 查看最新的远程分支
代码语言:javascript复制# 查看远程分支
git branch -r
# 查看本地和远程所有分支
git branch -a
2.2. 更新远程服务器分支列表
代码语言:javascript复制# 假如别人删除了一些远程分支,我本地git branch -r/a 的时候,会看到删除之前的所有分支
git remote update origin --prune
2.3. 删除本地分支和远程分支
代码语言:javascript复制# 删除远程分支:在本地任意非要删除的分支上执行
git push origin --delete 分支名
# 删除本地分支
git branch -D 分支名
2.4. 修改commit内容
代码语言:javascript复制# 如果commit注释写错了,只是想改一下注释,在刚提交之后 执行以下命令
git commit --amend
2.5. 文件恢复
代码语言:javascript复制# 1. 已提交:仅恢复已经提交的部分文件
# -- 后面为想要查看单个文件修改历史的文件路径
git log -- src/a.js
## 查出对应修改历史的 hash,并复制
# 恢复某个文件,后面跟文件路径
git checkout 刚才复制的hash src/a.js
# 2. 提交之前:恢复本地所有修改
git checkout .
# 3. 提交之前:回复本地某个文件的修改 或 取消指定文件删除
git checkout filename
# 4. 恢复到上一个版本,则可以解决整个文件夹删除的修改
git reset --hard HEAD^
# 5. 取消本地增加的文件 (慎用!)
git clean -df
2.6. 代码回退
代码语言:javascript复制# git reset 不会生成新的提交
git reset --hard HEAD^ # 回退到上个版本
git reset --hard commit_id # 退到/进到 指定commit_id
# 区别
git reset --soft commit_id # 回到到某个版本,所有后面的修改都在本地暂存区(stage)
git reset --mixed commit_id # 回到到某个版本,所有后面的修改都在本地工作区,未提交到暂存区
git reset --hard commit_id # 回到到某个版本,所有后面的修改都会丢失
# git revert 会生成新的提交
git revert 某次提交的commit_id # 会仅把该提交的文件恢复,并生成一条新的提交记录
2.7. 强制推送到远程
代码语言:javascript复制# 需要在版本仓库开启允许强制推送的权限,且推送后不要再次拉取
git push --force
2.8. 代码暂存
主要用于当在一个分支的开发工作未完成,却又要切换到另外一个分支进行开发的时候,除了commit原分支的代码改动的方法外,提供暂存代码的方式
代码语言:javascript复制git stash
git stash pop
2.9. 提交记录查看
git log
如果不带任何参数,它会列出所有历史记录,最近的排在最上方,显示提交对象的哈希值,作者、提交日期、和提交说明
如果记录过多,则按Page Up、Page Down、↓、↑来控制显示
按q退出历史记录列表
代码语言:javascript复制git log [<options>] [<since>..<until>] [[--] <path>...]
git shortlog
返回每个贡献者的commit次数以及每次commit的commit message
代码语言:javascript复制git shortlog
git shortlog -s # 返回每个作者的贡献次数
git shortlog -sn # 返回每个作者的贡献次数按从多到少排序
git shortlog -sne # 返回每个作者的贡献次数带邮箱按从多到少排序
git shortlog -sn --merges // 添加一个--no-merges标志,以显示合并提交的次数
git shortlog -sn --no-merges // 添加一个--no-merges标志,以忽略合并提交的次数
# 其可以添加参数:
# s:省略每次 commit 的注释,仅仅返回一个简单的统计。
# n:按照 commit 数量从多到少的顺利对用户进行排序。
# 加上这两个参数之后就可以看到每个用户中的提交次数以及排名情况:
# 更详细的参数说明:
-c, --committer group by committer rather than author
按提交人而非作者分组
-n, --numbered sort output according to the number of commits per author
根据每个作者的提交次数对输出进行排序
-s, --summary suppress commit descriptions, only provides commit count
抑制提交描述,仅提供提交计数(精简打印数据)
-e, --email show the email address of each author
显示每个作者的电子邮件地址
git reflog
git reflog 可以查看所有分支的所有操作记录(包括(包括commit和reset的操作),包括已经被删除的commit记录,git log则不能察看已经删除了的commit记录
git reflog 的应用场景:
git reset --hard HEAD~1则 删除了最新一条记录,如果发现删除错误了,需要恢复,这个时候就要使用 git reflog
代码语言:javascript复制git reflog
# 查看当前分支是基于哪个分支checkout的
# show是缺省值,下面命令等同于git reflog 分支名
git reflog show <childBranch>
# 查看 merge 和 checkout 记录
git reflog show --date=local | grep <branchname>
2.10. 合并
merge
将当前分支合并到指定分支。
通过 merge 合并分支会新增一个 merge commit,然后将两个分支的历史联系起来
其实是一种非破坏性的操作,对现有分支不会以任何方式被更改,但是会导致历史记录相对复杂
代码语言:javascript复制git merge
git merge --squash branchname // 可以帮我们将开发分支上的所有内容合并成一次提交到主分支
rebase
rebase 将当前分支移植到指定分支或指定 commit 之上,和 merging 不同,rebasing 清除了历史,因为它完全是从一个分支转移到了另一个分支。在这个过程中,多余的记录被移除了。
rebase 会将整个分支移动到另一个分支上,有效地整合了所有分支上的提交
主要的好处是历史记录更加清晰,是在原有提交的基础上将差异内容反映进去,消除了 git merge所需的不必要的合并提交
代码语言:javascript复制git rebase
git rebase -i <commit> # 移植到指定 commit 上
git rebase --continue # 用于解决冲突之后,继续执行rebase
cherry-pick
在多分支开发的时候会有需要把一个分支的部分commit应用到其他的分支上,然而git merge会把一个分支的commits 都应用到当前分支,这时候我们可以使用 git cherry-pick ,它的作用是选择已存在的 commit 应用到当前分支上,并产生新的 commit SHA-1 校验和。
代码语言:javascript复制git cherry-pick
如果想应用连续的多个commits还可以使用 commit1到 commit1,如果需要包含可以执行 如果只想把某一个分支最后一个commit应用到当前分支,可以直接使用branch-name分支最后一个commit应用到当前分支。
2.11. 查错
代码语言:javascript复制# git bisect 用来查找哪一次代码提交引入了错误,它的原理很简单,就是将代码提交的历史,按照两分法不断缩小定位。所谓"两分法",就是将代码历史一分为二,确定问题出在前半部分,还是后半部分,不断执行这个过程,直到范围缩小到某一次代码提交。
git bisect start [终点] [起点]
# 执行上面的命令以后,代码库就会切换到这段范围正当中的那一次提交
2.12. 比较
代码语言:javascript复制git diff branch1 branch2 --stat
2.13. tag
代码语言:javascript复制# 打 tag 示例
git tag -a v1.1.1 -m msg
git push origin v1.1.1
其余还有常用的 git add、git pull、git push、git config 等就不再赘述啦。
3. git 分支管理
- master:主分支,永远是可用的、稳定的、可直接发布的版本,不能直接在该分支上开发
- develop:开发主分支,代码永远是最新,所有新功能以这个分支来创建自己的开发分支,该分支只做只合并操作,不能直接在该分支上开发,非必须,看项目需要
- feature/xxx:功能开发分支,在主分支上创建分支,以自己开发功能模块命名,功能测试正常后合并到主分支)
- release:预发布分支,在合并好 feature分支的 develop分支上创建,主要是用来提测的分支,修改好 bug 并确定稳定之后合并到develop和master分支,然后发布master分支,适用于多人开发同时提测
- hotfix/xxx:紧急bug修改分支,在对应版本的 release 分支上创建,流程跟 release分支 相似,修复完成后合并 release 分支,根据情况判断需不需要再合并到 develop 和 master 分支(根据项目需要,可以直接合并到 master)
4. git 提交规范
规范
这里使用 Conventional Commits,它的 message 格式如下:
代码语言:javascript复制<type>(<scope>): <subject>
// 空一行
<body>
// 空一行
<footer>
分别对应 Commit message 的三个部分:Header,Body 和 Footer。
- Header
Header 部分只有一行,包括三个字段:type(必需)、scope(可选)和subject(必需)。
type: 用于说明 commit 的类型。一般有以下几种:
代码语言:javascript复制feat: 新增feature
fix: 修复bug
docs: 仅仅修改了文档,如readme.md
style: 仅仅是对格式进行修改,如逗号、缩进、空格等。不改变代码逻辑。
refactor: 代码重构,没有新增功能或修复bug
perf: 优化相关,如提升性能、用户体验等。
test: 测试用例,包括单元测试、集成测试。
chore: 改变构建流程、或者增加依赖库、工具等。
revert: 版本回滚
scope: 用于说明 commit 影响的范围,比如: views, component, utils, test…
subject: commit 目的的简短描述
- body
对本次 commit 修改内容的具体描述, 可以分为多行。如下:
代码语言:javascript复制# body: 72-character wrapped. This should answer:
# * Why was this change necessary?
# * How does it address the problem?
# * Are there any side effects?
# initial commit
- Footer
一些备注, 通常是 BREAKING CHANGE(当前代码与上一个版本不兼容) 或修复的 bug(关闭 Issue) 的链接。
commit校验
项目需要先加入 commitlint-config-cz 等校验插件,需按照上述格式填写 commit 信息,或使用格式化工具选择填入,在代码校验完成后,使用 npx git-cz 或 npm run commit 命令,根据提示选择本次修改类型,填入修改内容即可。
5. 注意事项
- 一个分支尽量开发一个功能模块,不要多个功能模块在一个分支上开发;
- 严禁所有人员在 master 分支和 develop 分支修改提交代码,master 和 develop(develop 非必须,看项目需要)分支只允许合并;
- 开发过程中,如果组员 A 开发的功能依赖组员 B 正在开发的功能,可以待组员 B 开发好相关功能之后,组员 A 直接pull组员 B 的分支下来开发,不需要先将组员 B 的分支 merge 到主分支;
- feature 分支在申请合并之前,先 pull 主分支,看一下有没有冲突,如果有就先解决冲突后再申请合并;
- master 分支上线后打上 tag,并说明此次详细更改信息,修改时间等;
本文是我日常工作中常用 git 命令、git 分支使用规范的简单总结,如有描述不正确的地方,还望大家多多指正,很多命令、概念没有展开描述,大家可以自行学习。