Git 教程
前言
工作区(Working Directory)
暂存区(Stage)
版本库(Repository)
远程仓库(Remote)
1. Git 分支规范
1.1 分支类型
分支类型基于Git Flow规范,并做了简化。
功能分支(feature)
紫色
发布分支(release)
黑色和红色
修复分支(hotfix)
灰色
主分支(master)
绿色
1.2 分支命名
类型 | 规则 | 备注 |
---|---|---|
功能分支 | feature-* | 以功能或上线日期为准 |
发布分支 | develop | dev环境发布分支 |
发布分支 | test/sit | 测试环境发布分支 |
发布分支 | release* | 预发布和生产发布分支, 默认release,多版本并行可release1, release2 |
修复分支 | hotfix-* | 已修复问题命名 |
主分支 | master | 保护分支,一般发布完生产需要合并到master |
1.3 分支合并
该图的原型为git flow, 原作者为Vincent Driessen
- 公共发版分支,是供给多版本有交叉提测时段时,针对某一环境发版专用的环境发版分支。
- 公共发版分支,必须是单向合并,严禁反向污染。 (gitlab线上合并,有冲突时禁用)
- release生产/预发布发版分支 ,由业务线组长或该版本负责人,统一集中合并。
- 公共发版分支维护统筹,由各业务线组长负责;
- 跨业务线开发,需要发布环境时,需主动联系该业务线负责人,说明版本计划、时间、公共包版本等,沟通清楚无异议后方可使用
- 严控版本Tag ,每次发版后,需业务新建tag入口组长或功能主开发进行操作,格式如下: 生产版本: Tag-YYYYMMDD版 (日期为发版日期) 修复版本: Fix-YYYYMMDD版 (日期为修复日期)
2. Git 提交规范
本节由alan提供。
commit message format(信息域) commit message 一般分为三个部分 Header,Body 和 Footer
<type>(<scope>): <subject>
// 空一行
<body>
// 空一行
<footer>
2.1 HEAD
type
用于说明commit
的类型,允许以下标识:
类型 | 描述 |
---|---|
feat | 新增功能 |
fix | 修复 bug |
docs | 文档变更 |
style | 不影响代码运行的变动如:样式调整 |
refactor | 重构(既不是新增加的 feature,也不是修复 bug) |
pref | 性能优化 |
test | 增加测试如:测试代码 |
chore | 构建过程或者辅助功能的变动 |
revert | 版本回退 |
build | 打包 |
2.2 BODY
本次
commit
的内容描述
2.3 FOOTER
本次
commit
存在不兼容变动或者关闭的 issue
2.4 注意事项
1:每个提交都必须使用类型字段前缀,它由一个名词构成,诸如 feat
或 fix
, 其后接可选的范围字段,可选的 !,以及必要的冒号(英文半角)和空格。
2:当一个提交为应用或类库实现了新功能时,必须使用 feat
类型。
3:当一个提交为应用修复了 bug
时,必须使用 fix
类型。
4:范围字段可以跟随在类型字段后面。范围必须是一个描述某部分代码的名词,并用圆括号包围, 例如: fix(parser): 描述字段必须直接跟在 <类型>(范围) 前缀的冒号和空格之后。 描述指的是对代码变更的简短总结,例如: fix(doc): update ref doc
。
5:在简短描述之后,可以编写较长的提交正文,为代码变更提供额外的上下文信息。正文必须起始于描述字段结束的一个空行后。
6:提交的正文内容自由编写,并可以使用空行分隔不同段落。
7:在正文结束的一个空行之后,可以编写一行或多行脚注。每行脚注都必须包含 一个令牌(token),后面紧跟 : 或 # 作为分隔符。
8:脚注的令牌必须使用 - 作为连字符,比如 Acked-by (这样有助于 区分脚注和多行正文)。有一种例外情况就是 BREAKING CHANGE,它可以被认为是一个令牌。
9:脚注的值可以包含空格和换行,值的解析过程必须直到下一个脚注的令牌/分隔符出现为止。
10:破坏性变更必须在提交信息中标记出来,要么在 <类型>(范围) 前缀中标记,要么作为脚注的一项。
11:包含在脚注中时,破坏性变更必须包含大写的文本 BREAKING CHANGE,后面紧跟着冒号、空格,然后是描述,例如: BREAKING CHANGE: environment variables now take precedence over > config files
。
12:包含在 <类型>(范围) 前缀时,破坏性变更必须通过把 ! 直接放在 : 前面标记出来。 如果使用了 !,那么脚注中可以不写 BREAKING CHANGE:
, 同时提交信息的描述中应该用来描述破坏性变更。
13:在提交说明中,可以使用 feat
和 fix
之外的类型,比如:docs: updated ref docs
。
14:工具的实现必须不区分大小写地解析构成约定式提交的信息单元,只有 BREAKING CHANGE
必须是大写的。 BREAKING-CHANGE
作为脚注的令牌时必须是 BREAKING CHANGE
的同义词。 :::
2.5 具体使用
站点已集成
commitizen
遵循谷歌conventionalcommits
约定式提交规范,进行了汉化方便辨识同时集成了commitlint
和lintstaged
规则格式校验; 提交类型以及内容体参照 👆 具体操作:fileChange
后执行命令git add .
(全量存入暂存区或者单文件存入)再执行 script 命令:
npm run commit
例:
PS F:\qzd-patents-pc\qzd-patents-pc> npm run commit
> wz-website@1.0.0 commit
> git cz
cz-cli@4.2.4, cz-customizable@6.3.0
All lines except first will be wrapped after 100 characters.
? 请选择提交的类型; (Use arrow keys)
> feat: 新功能
fix: 修复
docs: 文档变更
style: 代码格式(不影响代码运行的变动)
refactor: 重构(既不是增加feature),也不是修复bug
pref: 性能优化
test: 增加测试
(Move up and down to reveal more choices)
通过方向键选择提交类型,再进行本次提交的内容描述:
例:
All lines except first will be wrapped after 100 characters.
? 请选择提交的类型; fix: 修复
? 请输入修改的范围(可选) commitlint.md
? 请简要描述提交(必填) content change
? 请输入详细描述(可选) commitlint.md content edit
? 请选择要关闭的issue(可选)
###--------------------------------------------------------###
fix(commitlint.md): content change
commitlint.md content edit
###--------------------------------------------------------###
? 确认要使用以上信息提交?(y/n) (Yneh) y
编辑完内容后确认提交本次commit
确认提交后会进行prettier
、eslint
格式校验,校验通过继续向下执行。
pre-commit 已集成规则校验,务必按照此规范commit
3. Git 常见问题
3.1 git merge 或 git pull时出现冲突要怎么解决。
首先我们简述一下git merge 的机制 Tree-Way Merge(三向合并)
, A(当前分支),B(待合并分支), C(两者共同历史),
- 首先用A,B 和 C对比,发现第30行,如果只有一个分支A对比C有变更,那就采用A分支自动merge。
- 如果只有B对比C有变更,那么采用B分支自动合并,
- 如果两个分支都有变更,此时三个分支都不一致,那么就需要手动合并。
1,2 两种场景属于自动merge 我们一般是不需要处理的。
第三种就是我们日常遇到的冲突场景,也是比较容易丢失代码的场景。
以vscode为例
首先遇到冲突第一件事情是看跟谁冲突了,然后联系对方确定以谁的为准,
严禁直接采用自己的代码放弃别人的代码
, 经过对方确认后,再决定使用那一方的代码。
第二步是解决冲突。
左键点击文件可以很清晰的看到Tree-Way Merge(三向合并)的三个文件,我用字母做了标识,可以参考关于三向合并的说明(Visual Studio Code 1.69, 设置中搜索 git.mergeEditor
控制使用新界面还是老界面)。
右键点击文件弹出菜单,根据你跟对方协商的结果,决定采用谁的代码,Accpet All Current
是指全部以当前分支(A)的代码为准,Accpet All Incomming
是指全部以被合并分支(B) 为准。⚠️这个操作合并的是整个文件而不是单行冲突。单行合并请勾选对应的行数进行操作。
新版界面
老版界面
有些函数比较复杂,同一个作用域内出现了多个冲突, 解决冲突后,可能存在括号丢失之类的,要查看是否有语法错误。
如果是文件行数较多的文件,请务必保证解决了所有的冲突而不是所有的冲突,可以通过git hooks或者自己全局来搜索<<< 来确认。
提交代码
git add filename
git commit -m "fix: fix conflict for filename"
git push
至此,一个冲突解决完成。
3.2 如何进行代码回滚?
代码回滚一定要慎重!如果修改到的文件比较少,我们可以不通过命令回滚的方式,手动删除之前的修改,再进行提交。
- 获取到想要回滚到commit Id
git log
- 回滚到指定提交
# 适用场景: 如果想恢复到之前某个提交的版本,且那个版本之后提交的版本我们都不要了,就可以用这种方法。
$ git reset --hard < commit ID >
$ git push -f
# 适用场景:如果我们想撤销之前的某一版本,但是又想保留该目标版本后面的版本,记录下这整个版本变动流程,就可以用这种方法。
$ git revert -n < commit ID >
$ git commit -m "fix: revert some commit"
$ git push
两种方法对比在于要不要撤回某个commit 之后的所有提交。 git reset 会放弃所有,并且如果之前提交已经同步到了remote, 那么需要使用git push -f 进行强制提交,因为本地分支对于远程分支落后了n个版本。
git revert 只会放弃某次commit的代码,并且是生成一次新的commit, 需要再commit一次。 所以比远程多了一次提交,所以不需要强制提交。
3.3 不小心把代码push到远程仓库后怎么撤销?
参考上一个问题代码回滚
3.4 错误的merge要怎么撤销?
尚未merge成功的状态下,想要撤回合并请使用
$git merge --abort
如果已经merge 成功了,想要撤销合并
找到merge 之前的commit id,参考3.2问题代码回滚
3.5 windows系统文件名大小写不敏感问题?
# 此操作设置git大小写敏感
git config --global core.ignorecase false
# 此操作设置window10 以上系统大小写敏感
fsutil file setCaseSensitiveInfo <dir path> enable
3.6 已经提交过的文件怎么忽略?
1.从本地Git缓存中删除文件
# 忽略文件
$ git rm --cached <filename>
# 忽略文件夹
$ git rm -r --cached <Dirname>
2.提交到仓库里面
$ git commit -m "chore: remove somefile version tacking changes"
$ git push
3.将文件path添加到.gitignore 文件
3.7 换行符不统一导致eslint校验不通过的问题?
git 配置
# 提交时转换为 LF,检出时不转换
$ git config --global core.autocrlf input
# 不允许有混用换行符提交
$ git config --global core.safecrlf true
在编辑器插件设置中设置 end_of_line
值为 lf
尚未安装插件的话建议设置编辑器配置files.eol
值为 '\n'
4. 附录 Git 常用命令
git 命令分为重要
, 常用
, 不推荐
, 熟悉
四种。
重要
一般为前置全局配置的命令,一定在初始化之项目之前配置。
常用
一般的开发中使用频率较高的命令
不推荐
是指常用,但是不推荐使用的命令
熟悉
是指可能会用到的命令
还有一些较冷门的命令将不会在以下说明中列出。
4.1 创建版本库
# 初始化git仓库
git init
# 在目录内新建一个仓库
git init <dirname>
# 克隆一个git仓库, 此处的url一般推荐ssh,不推荐https(常用)
git clone <url>
4.2 配置
# 设置提交代码时候的用户信息(重要)
$ git config <--global> user.name "<name>"
$ git config <--global> user.email "<email address>"
# 提交时转换为LF,检出时不转换, 解决win mac 系统换行符问题,
# 一般规范内使用LF换行,不同的换行符会被识别为代码变更。(重要)
$ git config --global core.autocrlf input
# 拒绝提交包含混合换行符的文件(重要)
$ git config --global core.safecrlf true
# 查看config配置
$ git config --list
# 编辑Git配置文件
$ git config -e <--global>
4.3 修改和提交
# 将某个文件添加到暂存区(常用)
git add <filename1> <filename2> ...
# 将某个目录添加到暂存区(常用)
git add <dirname>
# 将所有变更文件添加到暂存区(不推荐)
git add .
# 提交(常用)
$ git commit -m "<message>"
# add 和 commit 合为一步(常用)
$ git commit -am "<message>"
# 删除工作区文件,并将这次删除放入暂存区
git rm <filename>
4.4 更新和发布
# 获取远程分支,并更新到本地分支(常用)
$ git pull <remote> <branch>
# 推送本地更新到远程分支(常用)
$ git push <remote> <branch>
# 获取远程分支,但是不更细本地分支(常用)
$ git fetch <remote>
# 获取远程分支详细信息
$ git remote -v
# 添加一个新的远程仓库
$ git remote add <shortname> <url>
# 删除远程仓库
$ git remote rm <name>
4.5 合并和变基
# 合并分支到当前分支, 存在两条记录
$ git merge <branch>
# 合并分支到当前分支, 存在一条记录
$ git rebase <branch>
# 取消当前的rebase, 用于rebase冲突后放弃rebase
$ git rebase --abort
# 继续rebase, 用于解决冲突后继续执行rebase
$ git rebase --continue
4.6 分支和标签
# 显示本地分支, -a 显示全部,包含remote(常用)
$ git branch <-a>
# 切换分支(常用)
$ git checkout <branch>
# 丢弃工作区修改, . 丢弃所有
$ git checkout -- <filename>
# 从当前分支新建一个本地分支并切换(常用)
$ git checkout -b <branchname>
# 删除本地分支(常用)
$ git branch -d <branch>
# 给当前分支打标签
$ git tag <tagname>
4.7 撤销和回滚
将当前版本重置至HEAD, 用于merge失败
$ git reset --hard HEAD
# 将当前版本重置至某一个提交状态(不推荐)
$ git reset --hard <commit>
# 将当前版本重置至某一个提交状态,代码不变
$ git reset <commit>
# 重置至某一状态,保留版本库中的不同文件
$ git reset --merge <commit>
# 重置至某一状态,重置变化的文件,代码改变
$ git rest --keep <commit>
# 丢弃本地更改信息并将其存入指定文件
$ git checkout HEAD <file>
# 撤销提交
$ git revert <commit>
4.8 其他
# 查看当前版本状态(常用)
$ git status
# 查看日志,可选用查看几条(常用)
$ git log -<number>
# 显示某个提交的详细内容
$ git show <commit>
# 显示文件每一行的cimmit号,提交者,最早提交日期
$ git blame <file>