git的flow搭建
前言
使用git时, 一般都会有自己或团队的一套工作流, 这里介绍下自己工作流的搭建。
这篇文章只是整个开发工作流的一个边角 —— 是与git相关的flow。
1、提交信息的规范
我采用的是约定式提交, 并且配置了插件来协助执行(如commitizen的cz-cli、 husky 、 commitlint、 standard-version)
Conventional Commits(约定式提交)脱胎于Angular提交信息准则AngularJS Git Commit Message Conventions, 约定式提交提供了更加通用、简洁和灵活的提交规范
“Angular提交信息规范”和”Conventional提交规范”都是用于规范Git提交信息的规则,它们的目标是使提交历史更清晰,更易于阅读和理解。
Angular提交信息规范:这是Angular团队提出的一种提交信息规范。它定义了一组提交类型(如feat、fix等),并规定了提交信息的格式,包括标题(Header)、正文(Body)和脚注(Footer)。
Conventional提交规范:这是一种更通用的提交信息规范。它不仅包含了Angular提交信息规范中的内容,还定义了更多的提交类型,并提供了一种标记破坏性变更的方法。
总的来说,”Angular提交信息规范”可以看作是”Conventional提交规范”的一个子集或者说是一种特定实现。它们都旨在通过规范化的提交信息,提高代码质量和协作效率。
因此, 我们制定自己的约定式提交规范时, 可以将Angular提交信息规范作为参考。
2、开发日志书写规范及版本维护更新规范
约定式提交有一个好处就是, 可以依次约定为基础, 从而借助工具来自动帮助我们生成changelog
- 这里有一篇关于如何维护更新开发日志的文章, 可以参考下https://keepachangelog.com/zh-CN/1.0.0/
- 当然, 如果使用了约定式提交, 我们可以基于提交范式, 轻易的写出一个满足维护需求、基于提交历史的自动生成changelog的插件(所生成的changelog绝不再是git日志的堆砌物),而这样的插件已经有了, 我们会在搭建流程章节介绍个人的选择。
另外, 项目版本维护与更新, 在有了能够满足阅读需求的changelog做基础后, 也变得轻松了不少。
当然, 我们还可以借助些业内总结过好用的版本的语义化规范(前端的一个规范, 但适用范围不仅限于前端, 供大家参考), 来规范版本的生成和设置。
- 这是描述语义版本控制规范的网站https://semver.org/
- 这是该网站的代码仓库https://github.com/semver/semver.org
- 当然, 学以致用, 按照约定式提交迭代的项目, 可以很好的兼容这些规范, 本人也是比较建议大家按照规范来开发迭代并发布的。相关的插件, 会在搭建流程章节介绍个人的选择。
3、总结
标准且符合规范的提交是工作流中不可或缺的一部分, 他的好处如下:
- 更加结构化的提交历史
- 保证每次信息都有确切的含义
- 方便直接生成changelog
- 方便信息搜索和过滤
搭建流程
1、配置校验规范
以下配置保证commit时会触发检验规则, 过滤掉不规范的提交
不论使用那种方式( 使用正常commit 或 后文会提到的格式工具如cz )的提交都需要符合 约定式提交规范 才能顺利通过(也就是利用git的钩子可以通过husky来简化git钩子的使用加上脚本的正则 commitlint就是用来做这个的 来检验下文本):
commitlint
可以是一个commit的校验工具, 通常和husky一起使用,校验用户提交的commit符不符合规范(按官网的入门提示按装使用其默认规则即可, 配置过程包含husky
的安装 , 一切安装文档即可)husky
不过多介绍, 与commitlint结合使用的方法也在 commitlint的官方文档有体现
参考命令(按顺序依次执行即可) (已弃用, 请参考此链接配置)
1
npm install --save-dev @commitlint/config-conventional @commitlint/cli
1
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
####################### 弃用 开始 #############################
1
npm install husky --save-dev
1
npx husky install
1
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit ${1}'
####################### 弃用 结束 #############################
tips: 复制粘贴的过程中, 要注意命令末端可能会多余的出现
~
, 出现的话一定要删除这个字符后再执行命令新的husky钩子配合commitlint的安装+配置过程(主要是v9做了调整)
1
2
3
4
5
6
7npm install --save-dev husky
npx husky init # 需要注意的是, 这一步会引入test用的脚本, 路径在.husky/pre-commit, 我们需要在配置完毕后删除它(即这个文件pre-commit), 不如会影响钩子的整体执行
npm pkg set scripts.commitlint="commitlint --edit"
echo "npm run commitlint \${1}" > .husky/commit-msg
以上命令是全部按照默认的配置, 如需进一步定制, 可参考此插件的项目文档https://github.com/conventional-changelog/commitlint
此时我们检验下, 刚才对
钩子
和校验插件
的配置与安装是否生效。参考命令
1
2
3# 按照不符合格式的log提交, 是无法成功的
git commit -m "update"
git commit -m "aaa(123): aaa"为保险起见, 用符合规范的提交进一步检验
1
2# 只有按照约定时提交的正确格式, 才能够通过校验, 完成提交
git commit -m "fix(123): aaa"
2、配置提交时的效率工具
以下配置是为了更高效的编写符合规范的提交log, 以避免因提交格式问题造成的提交失败。
- 我们可以借助插件来辅助commit时log的书写。 这里我使用的是cz-cli
cz-cli
是一个可以帮助我们避免错误提交的cli工具, 协助我们轻松写出符合规范的提交。参考命令
首先, 全局安装安装 Commitizen CLI 工具:
1
npm install commitizen -g
然后, 配置适配器, 这里我们使用”使用 cz-conventional-changelog 适配器”
1
commitizen init cz-conventional-changelog --save-dev --save-exact
验证安装
参考命令
1
git cz
安装成功的标准: 执行
git cz
命令后, 不再跳入vim编辑器打开的log模板, 而是进入cz工具的快速格式化界面即代表安装成功。(注意, 新开一个终端来验证即可, 无需重启终端–只要用的不是当前配置适配器时用的终端就行)
3、changelog的自动生成
以下配置是为了更高效的编写符合规范的changelog日志, 以避免浪费过多的时间在这上面。
- 我们可以借助插件来辅助changelog的书写, 准确的说是直接生成。 这里我使用的是conventional-changelog-cli
conventional-changelog-cli
是一个用于生成changelog的cli工具, 帮助我们生成符合规范的开发日志。安装流程
参考命令
我们直接全局安装这个工具即可
1
npm install -g conventional-changelog-cli
验证安装
参考命令
首先, 我们进入一个遵循约定式提交规范的项目中
1
cd my-project
然后使用以下命令来生成一个changelog.md文件, 若成功生成且内容符合预期, 则安装无误。
1
conventional-changelog -p angular -i CHANGELOG.md -s
- 参数 -p 指定提交信息的规范,有以下选择:angular, atom, codemirror, ember, eslint, express, jquery, jscs or jshint
- 参数 -i 指定读取CHANGELOG内容的文件
- 参数 -s 表示将新生成的CHANGELOG输出到 -i 指定的文件中
使用说明
前文”验证安装”小节中使用的命令, 不会覆盖任何以前的变更日志(推荐使用这种方式, 也是我最常用的方式)。上面的内容根据最后一个
semver 标记
( 符合语义化版本控制说明
的tag
), 提交生成了一个更改日志,该日志与约定式提交规范的Feature
,Fix
,Performance Improvement
orBreaking Changes
模式匹配。参考命令
我们也可通过 -r 参数, 来进行覆盖式的生成。(参数-r默认为1, 设置为0使用将重新生成所有版本的变更信息)
1
conventional-changelog -p angular -i CHANGELOG.md -s -r 0
借助于git的强大, 即使覆盖式生成, 也可以快速还原自定义的部分。
此外, 根据上述介绍, 不难发现, “CHANGELOG” 与我们的 版本管理(或者说打tag)——推荐使用
语义化版本控制说明
的规范, 有着千丝万缕的联系。因此, 我们在使用时, 还有以下几点需要注意:
- 每次需要打tag标签时, 记得先进行
conventional-changelog
, 这么做的原因是因为 “CHANGELOG” 需要包含在新版本所在的提交中。 下面附上官方给的工作流程:Make changes (做出改变)
Commit those changes (提交这些更改)
Make sure Travis turns green (确保测试通过)
- 如果你配置的有你所使用的测试框架的远程ci配置的话,就推送到仓库让其自动触发自动测试–直到通过。
- 若没有的话, 就在本地手动执行你的测试脚本–直到通过。
总之, 不论哪种, 都需要保证测试通过。 因为我们’必须要保证’我们打tag的版本, ‘必须、一定’是可用的。)
Bump version in package.json (在 package.json 对版本信息做相应的变更, 一般与我们本次要打的tag的版本信息保持一致)
conventional-changelog (生成变更日志)
Commit package.json and CHANGELOG.md files (提交 package.json 和 CHANGELOG.md 文件)
- 因此, 上述操作是为了确保打标签时的程序版本一定是可以正常使用的, 以及确保我们的Tag版本变更这个commit中, 只有这两种文件的新增(即CHANGELOG.md 和 package.json)–因为对于大型项目来说package.json文件是可能有多个的。
Tag (标签–这个时候我们就可以打上标签了, 一般与 package.json中的标签版本保持一致)
Push (推–推送到远端存储)
对第一次接触的小伙伴们, 这里做一些发散解释:
“Make sure Travis turns green” 是指确保你的代码通过了 Travis CI 的构建和测试。Travis CI 是一个持续集成服务,用于构建和测试在 GitHub 上托管的项目。当你提交或推送更改时,Travis CI 会自动运行你的测试。
“绿色”在这里表示所有的测试都已通过。在 Travis CI 的构建状态报告中,如果所有测试都通过,那么状态会显示为绿色。如果有任何测试失败,状态会显示为红色。
因此,”确保 Travis 变绿”就是确保你的所有测试都通过,以便你的代码可以被合并或部署。如果你看到 Travis 的状态是红色,那么你需要检查测试结果,找出并修复导致测试失败的问题。
题外话
既然提到了
semver 标记
/semver tag
, 我在这里说些简单的用法(具体的规范可以在本文开头找到链接), 以方便大家理解下一小节的插件应用。X.y.z
x的变更, 是正式版本的变更, 证明您的API已经稳定了, 不会再有破坏性变更了。 若x发生变更, 须将y和z清零。x.Y.z
y的变更, 是新功能发布的变更, 可以包含开发过程中涉及的fix。若y发生变更, 须将z清零。x.y.Z
z的变更, 是代表修复的变更, 指修复了bug。 比如有什么紧急的bug需要处理, 可在处理后发布修复版本; 再比如, 你想把某一天或几天专门用于处理一批用户反馈的bug, 等处理工作完毕后, 可以专门发布一个修复版本。
4、版本的自动管理
此部分未了解过, 暂且跳过
因为个人的项目很小, 涉及到的混编也不多, 写代码也写的不快更新是很慢的
最主要的还是我的提交信息做不到太严格的边界分明, 而且我也不想完全按照语义化的在几乎每次提交后都打上tag。
因此目前的我手动打tag配合changelog工具的完全够用
自动管理tag, 推荐此项目https://github.com/semantic-release/semantic-release
等我变厉害了, 就更新此部分内容。
?、分支流搭建
分支流
搭建不会引入任何项目文件系统的变更, 仅在git中做操作。因此, 您可以在 1、2、3、4 完成前后执行此操作。
- 从github上创建新的远端存储库, 加或不加初始的
README.md
文件都无所谓。 (这里以加了为例, 在 1、2、3、4 步骤操作之前搭建分支流
) - clone仓库, 如果是私有仓库, 请在clone操作前准备好相关token .
- cd 项目名, 进入项目。 此时我们处于初始的
main
分支, 对应的远端分支为默认的origin/main
(origin为默认的远端仓库名, 可根据您自己的需求更改, 我在这里不对其做处理)。这里的
main
分支, 就作为我们面向github发布的主分支, 也就是发布分支, 在其之上, 保证强制单一分支特性。 - 接下来, 我们通过分支创建命令, 分别创建
dev
分支和srackhall
分支。这里的
dev
分支, 就作为我们面向实际开发的主分支, 也就是开发主分支
在其之上进行非快进式合并, 尽量在开发主分支
内保留全部历史, 以使得我们的项目仓库不完全依赖与github平台, 更方便后期遭遇特殊情况时的迁移, 或是一开始就打算多平台托管。这里的
srackhall
是以开发者命名的, 相对于具体开发者的开发分支。 所有开发者, 都需要维护自己的分支, 从而通过 pr 的方式, 向dev
和main
主分支内合入提交。当然, 我会在规则中, 强制这一做法, 所有人必须通过 pr 来向 两个 主分支 合入代码。
- 通过
git push dev
命令, 将dev
分支推送到远端仓库。此时若是通过
git remote show origin
查看, 会发现dev
分支仅绑定了远端仓库(origin)的,git push
操作。因此, 此时若执行
git pull
是无法拉取到远端仓库的origin/dev
分支的。 不过不用过分担心, 因为执行后, git也是会基于此现象给你相关提示的。 - 通过
git branch --set-upstream-to=origin/dev dev
命令, 绑定本地dev
分支至远程origin/dev
分支的git pull
命令。如果你的开发分支名称不是
dev
, 那么请按照此命令格式自行填写git branch --set-upstream-to=origin/<branch> <branch>
- 最后, 我们再次执行
git remote show origin
, 以及git pull
, 就可以得到以下正确完整的分支流验证了。
如何使用搭建后的分支流
此小节略过,下图中方式错误, 并没有参考意义, 请直接参考总结中的内容使用。
如下图, 这是我这几天新开的个人项目第一次进行pr后的结果(分别向main和dev执行pr), 同时维持了main分支的单一策略, 以及dev分支的完整历史策略。

但从第二次开始, 由于main分支与dev分支不再使用同一版本号, 因此需要引入图中所示的本地rebase操作, 之后在进行分别提交, 分别基于srackhall分支向main分支合并, 以及基于srackhall_dev分支向dev分支合并。 (其中在srackhall分支进行开发, 再通过(删除并重新创建或向上快进式合并)rebase_srackhall_dev分支后, 对srackhall_dev分支进行rebase操作, 然后对srackhall_dev进行本地的快进式合并, push到远端, 然后执行pr至dev分支)
总结
如何从srackhall, 并入main与dev (本小节已作废)
请前往下个小节阅读最新同名内容
我们需始终在 main 分支上 引出 srackhall 分支
我们在 srackhall 分支上 srackhall所在位置, 创建一个 srackhall_dev分支(用于做为srackhall分支的副本使用)
推送 srackhall 分支 到 origin/srackhall 分支
下面顺序写反了, 应该先处理
此prorigin/srackhall -> origin/main
, 然后再处理origin/srackhall -> origin/dev
, 仅标记了整体反转, 中间的逻辑反转自行带入处理。
// 2…{
提交
origin/srackhall -> origin/dev
这个pr, 并在dev中处理此pr, 根据pr中的批量commit情况, 在 ‘快进式提交’或’非快进式提交’ 二选一 来合入 dev主 分支(在合入之前,出现任何情况, srackhall_dev都是唯一的退路)。(可选) 通过 git pull origin dev , 来在本地检查刚才的 pr 更新的dev。
这里不拉, 最后也是要拉的, 因为我们还需要从dev检出新的 srackhall, 来用于以后的开发。
如果这里拉取, 需要注意 pull 前先 ‘检出/切换’ 至 dev 分支。
- 因为pull自带merge操作, 如果在其它分支的话, 是会引起 ‘dev分支的最新拉取结果’ 与 ‘当前所在分支’ 合并的。
- 如果快进式还好, 可以通过
git branch -f <branch-name> <commit-hash>
退回之前。注意, 此命令不要在被操作的分支上进行操作, 需先检出至任意其它分支后, 再操作。否则, 你可能会遇到这个错误
fatal: cannot force update the branch 'srackhall' checked out at 'D:/safe/Habit-tracking'
- 否则, 若不通分叉, 则极大概率会引起冲突(也不一定,99.99%吧哈哈), 虽然也问题不大, 都是可退回的, 就是操作会更麻烦些。
- 如果快进式还好, 可以通过
因此为了避免不必要的时间浪费, 我们最好是 pull 哪个分支, 就先提前 检出此分支, 并基于此分支操作。 或者使用
git fetch
, 仅拉取数据, 稍后在本地手动处理合并。- 因为pull自带merge操作, 如果在其它分支的话, 是会引起 ‘dev分支的最新拉取结果’ 与 ‘当前所在分支’ 合并的。
删除远端的 origin/srackhall 分支(若dev分支的合并是 第一次选择 非快进式合并 不用删也行, 否则必须删除, 为了使流程不出错, 故 统一选择删除)
- 删除本地分支, 使用 `` 命令即可
- 远程分支, 在远程直接进行删除即可, 或者 `` 命令删除。
- 远程分支残留, 使用 `` 命令进行删除。
如果在处理完pr并成功合并至dev分支后, 本地 srackhall 分支和 srackhall_dev分支 出现不一致, 则删除这个srackhall_dev分支。
这个 不一致 问题, 通常是在他人来处理pr时, 可能需要按照要求 在本地美化历史 并强制推送, 以达到他想要的历史信息, 之后才会继续处理。(这样一来, 由于历史的变更问题, 原本的srackhall_dev就会过时, 因此需要删除。 自己处理自己的, 一般不会有此情况。)
(如果上一步删除了srackhall_dev的话, 否则跳过此条内容)再次创建srackhall_dev (基于 srackhall分支重新创建srackhall_dev分支)。 (即确保其与最新的srackhall为准)
// }…2
// 1…{
pull main 分支(也可以所有, 但主要是 main 分支, 因为我们一会要在本地对main分支执行rebase, 因此要尽可能保证main分支是最新的, 避免pr失效还得再走一遍强制pull流程, 并将srackhall_dev作为副本启用–即 删除srackhall分支, 并在srackhall_dev分支处重新创建srackhall分支, 然后重新执行后面的rebase操作)
有很多小伙伴分不清 rebase和merge, 我简单解释下吧:
git merge
:当你在一个分支(比如 main)上执行git merge dev
时,Git 会将 dev 分支的更改合并到 main 分支。这个操作会影响 main 分支,但不会改变 dev 分支。(即只会影响当前所在分支, 在哪个分支上做操作, 就哪个分支受影响)git rebase
:当你在一个分支(比如 dev)上执行git rebase main
时,Git 会尝试将 dev 分支上的更改应用到 main 分支的最新提交上。这个操作只会影响 dev 分支,不会改变 main 分支。(即只会影响当前所在分支, 在哪个分支上做操作, 就哪个分支受影响)git merge
:当你在一个分支(比如 dev)上执行git merge main
时,Git 会将 main 分支的更改合并到 dev 分支。这个操作会影响 dev 分支,但不会改变 main 分支。(即只会影响当前所在分支, 在哪个分支上做操作, 就哪个分支受影响) 只不过最终此分支还在原处(基于原本父commit), 冲突在最新commit中(而rebase的分支,其父commit变成了基于main的最新commit, 冲突则散在了在相应的每个变基位置做了处理)。
当两者都需要处理冲突的情况下
- 针对最终的dev、main两个分支 的整体提交数量来说:
- merge 会 比 rebase 在 整体提交数量上多出1个全新的提交(即多的这个提交就是main分支往我这dev合入时的冲突处理提交 – 所有冲突都在这一个提交中做了处理)。
- 而rebase执行后, 两分支的整体节点数(或commit数)是不会变的, 冲突被rebase到了每个相应具体的历史commit中, 因此这些commit从内容到时间线以及uuid, 都是会发生变化的(虽然其中某个commit的内容, 可能在rebase的过程中无需变更, 但其父commit变了,因此时间线和uuid一定要变)。
- 仅针对 dev 这个分支的提交总数来说:
- rebase的执行结果 大于等于 merge的执行结果。
- 因为无论如何, merge 在需要处理冲突的情况下, 都是只会产生
1
个新节点的。 - 而rebase在需要处理冲突的情况下, main分支终点到分叉点,至少也是有一个提交的, 而这些提交便是 我们基于终点的变基 后新增的提交。 即中间新增的节点数一定是
大于等于 1
的。
- 因为无论如何, merge 在需要处理冲突的情况下, 都是只会产生
- rebase的执行结果 大于等于 merge的执行结果。
- 针对最终的dev分支 的历史完整性 来说, dev分支的提交历史发生了变更, 其中涉及到 处理冲突时的变更, 合入到了dev从分叉点到终点间的
每个
提交中(rebase到哪个提交, 比较哪个提交, 产生冲突就当场处理)。 即原有的从分叉点都最终 dev 分支commit被遗弃, 不只是内容, 连uuid和时间等信息都是新的。 而merge不会影响到历史完整性, 因为所有的冲突都由一个全新的提交来承载了。
在本地将 srackhall 分支 rebase 到 main分支上
push srackhall 分支到 origin/srackhall 分支
提交
origin/srackhall -> origin/main
这个pr (注意此处的origin/srackhall,是必须按照前面几步在本地通过rebase后的, 这样可以在本地先检查一遍, 而不是吧结果留到pr中去)。此时再前往main分支处理此相同的pr, 由于已在dev分支处理过了, 因此
注意 main 分支需始终保持单一策略, 千万不能使用’非快进式合并’的方式进行合并(这个在github规则中强制设置禁止即可, 直接失能相关选项)
- 若是dev处理时选用了 ‘快进式提交’, 则 main 这里的pr处理 也保持一致地使用 ‘快进式提交’, 对于github来说, 就是使用rebase and merge这个选项, 因为在确认其是快进式的情况下, 它们都一致。
- 若是dev处理时选用了 ‘非快进式提交’, 则 main 这里的pr 就需要使用 ‘合并提交’ 即squ…将提交合并成一个 来处理了。 (这里可能在非第一次后, 执行重复操作。 因此优化流程, 可以先对main分支进行pr, 然后再处理dev分支的pr)
// }…1
- 最后需要, 删除 origin/srackhall、 删除 srackhall、 删除 srackhall-dev
- 执行pull, 拉取 origin/main 分支到本地 main(也可以带dev分支一起拉取, 不过我们这里主要使用main), 并基于 最新的 main分支, 创建 srackhall分支, 以继续开发。(即保证始终以main分支引出 srackhall 独立开发分支)
对于 tag 和 CHANGELOG 的在我们此工作流上的操作流程
- 确保以上’从srackhall, 并入main与dev’的pr流程测试通过。
- 在srackhall分支, 使用``命令, 更改 package.json中的版本信息。
- 在srackhall分支, 使用
conventional-changelog -p angular -i CHANGELOG.md -s
命令, 以追加的方式, 生成最新的CHANGELOG.md文件。 - 在srackhall分支, 进行本地commit。(此commit中仅有 CHANGELOG.md 和 package.json 两种文件–package.json可能有多个)。
- 在刚刚的commit上, 打上与package.json中相同版本号的tag。(最后在远端打也行, 主要是确保并入main与dev的过程不出错)(远端打的话,对比日志信息即可, 即打完main上的以后, 找到dev上相应的位置, 打上相同的tag就行了)
注意,tag是对uuid唯一的, 我所说的相同的tag, 需要的是在其相应位置, 创建一个与主分支tag号码相同而前缀不同的tag。 即 v1.1.5 和 dev1.1.5 (dev1.1.5这个tag用在dev分支)
- 通过上面的 ‘如何从srackhall, 并入main与dev’ 的方法, 将其合入’origin/dev’和’origin/main’(注意tag可能会因rebase而脱离, 要在pr处理时注意一点)。
注意,tag是对uuid唯一的, 我所说的相同的tag, 需要的是在其相应位置, 创建一个与主分支tag号码相同而前缀不同的tag。 即 v1.1.5 和 dev1.1.5 (dev1.1.5这个tag用在dev分支)
此时, 我们即保证了完整的历史记录(通过dev分支), 又保证了主分支的唯一性。
- main分支仅在github上使用, 可以针对main分支来部署ci
- 如果github不像封锁俄罗斯那样封锁中国开发者的话, 即使是单一规则的main分支, 也是在pr中保留有完整的历史记录的。
对于 Gitee 等其它存储此项目的平台或自建服务器中, 即使仅克隆 dev 分支, 也可以通过dev分支还原出完整的main分支来。
- 带main分支一起clone也没关系, 不过采用还原的方式的好处是, 可以将单一main的pr信息一起还原(不过还是需要抓取每个pr中的文本内容才行)。但是issue可能就无法完美还原了, 可以需要自行写迁移脚本来处理。
如何从srackhall, 并入main与dev
我们需始终在 main 分支上 引出 srackhall 分支
1、对于main分支, 优先处理
- 我们在 srackhall 分支上 srackhall所在位置, 创建一个 srackhall_copy分支(用于做为srackhall分支的副本使用)
- git checkout main
- git pull origin main
- git checkout srackhall
- (看情况使用)git rebase main
如果main分支在第2步有新节点, 则执行此步骤, 否则无需执行
执行此步骤时, 请细心处理冲突 - git push srackhall , 获得 origin/srackhall
- 创建并提交pr: origin/main <- origin/srackhall
- 处理pr, 处理过程略…
- 最终将处理好的pr, 使用 squ…. 或 rebase and merge 将其合入主分支
- 删除origin/srackhall, 并回到本地, 在本地也将其缓存删除
对与远程以删除的陈旧缓存, 我们可以对具体仓库名称使用此命令
git remote prune [仓库名称]
如
git remote prune origin
执行后, 即可自动基于origin远程仓库来清除本地陈旧的远程分支缓存。 - git checkout main
- git pull origin main , 并检查最终成果
如果你忘记检出到main分支, 影响了其它分支处理merge的话
- 若为快进式, 可直接通过此命令
git branch -f <branch-name> <commit-hash>
将相应分支指针移动回原有位置。 - 若为非快进式, 则全选当前分支, 并在之后使用相同的方法将相应分支指针移动回原有位置。
- 若为快进式, 可直接通过此命令
- 删除原 srackhall, 并在当前最新的main分支指针处, 新建srackhall
非必要, 如果远端处理pr选择了 rebase and merge 的话, 就无需这一步了
- 删除命令为
git branch -D [分支名称]
(-D大写意为强制删除, 小写则为非强制, 一般我直接用大D)
- 删除命令为
- git checkout srackhall , 继续开发
如果你使用了dev分支, 则先处理dev分支的pr(参考 2 ), 再继续开发
如果你使用了stash + srackhall-note的组合, 则先处理srackhall-note(参考 3 ), 再继续开发。
2、若使用了dev分支, 则继续处理dev分支
(后续对dev分支的操作, 看个人需求, 我本人已弃用dev, 触发github禁用中国用户, 否则以上操作完全够用)(如果您不喜欢dev这个名字, master这个名字也很合适这个分支的作用)
- 检查此时的srackhall分支, 是否与srackhall_copy分支发生不一致。 并建立 srackhall_dev 分支。
若发生, 则删除原本的srackhall_copy, 并在最新的srackhall分支指针处重新创建一个srackhall_copy
- git checkout dev
- git pull origin dev
这里的dev分支, 一般情况下与main分支一致, 目前就我一个人用, 不可能出现不一致情况, 人多就不一定了, 不过此分支只允许我一人操作就好了, 保证不会有其它人对此分支做操作。
不过就算到时候找了其他可操作此分支的人, 应该也可以(推测)直接在远程写脚本来执行处理, 毕竟pr已经处理过冲突了, 即使直接在远端rebase也问题不大 - git checkout srackhall-dev
- (必须使用)git rebase dev
由于已在main的过程中处理过冲突, 这里一般可以直接迁移分支名指针。(除非,在此期间有其它用户操作dev分支向起合入了其它commit)
- git push srackhall_dev , 获得 origin/srackhall-dev
- 创建并提交pr: origin/dev <- origin/srackhall-dev
- 处理pr, 处理过程略…
此处在origin/main的pr过程中其实已处理过了, 因此无需处理。
- 最终将处理好的pr, 使用 非快进式合并 或 rebase and merge 将其合入dev分支
这里根据origin/main的处理对照处理即可, 若前面选择用了 squ.. 则此处就选 非快进式, 否则就与前面一致地使用 rebase and merge
- 删除origin/srackhall-dev, 并回到本地, 在本地也将其缓存删除
- git checkout dev
- git pull origin dev , 并检查最终成果
- 删除原 srackhall-dev,
并在当前最新的main分支指针处, 新建srackhall-dev必要, 因为我们不需要此分支
- git checkout srackhall , 继续开发
3、处理srackhall-note分支(如果你使用了)
note分支, 仅推荐纯个人项目使用(或前期仅有一个人时的项目使用--特别是初始的设计和架构阶段<此阶段往往会产生大量无效注释>), 若你有开源意愿, 或者后期可能以团队模式开发, 则不推荐使用, 因为参与进此项目的其它用户, 会使得此分支增加极为巨大的重复工作量
note分支可以将前期设计阶段的大量思考想法类注释–即对开发和代码阅读无意义的注释, 给拦截在主分支、dev分支以及 srackhall分支外。 等测试版本发布时, 对于项目的整体介绍和未来规划, 是可以参考最初的note分支的。
- 若你前期使用了, 后期想要弃用, 对于注释,最好取其精华的适当逐步地添加入主线。 然后逐步抛弃note分支。
- 若你仅在设计阶段当作初始文档使用, 当进入正常开发后(即注释稳定后), 记得逐步抛弃note分支。
若你可以确认,
分支中没有除你自己的提交以外的提交
。(如果项目只有自己在做开发, 则这个是必然的, 无需往后看了)此时无需处理srackhall-note分支, 继续使用当前srackhall-note做开发, 并继续和srackhall分支共用stash即可。
若
main分支中有他人的commit混入
(项目做起来后, 概率极大), 那么有以下多种方案, 可供选择:- 第一种:
- git checkout srackhall-note
- git [merge/rebase] main (这个工作量有点大了其实) (冲突数量极大, 因此不建议)
- 此时, 我们的执行结果(即代码内容), 就与 srackhall保持一致了。
- 继续在srackhall-note进行开发, 并通过stash向 srackhall 分支输送无注释版本。
- 第二种:
- 在最开始打算处理main分支pr之前, 多建立一个note-computer分支。 并在 pull main之后 , checkout note-computer分支, 对 main分支执行 merge 操作。
得到一个除我之外, 其他人对main分支的commit做的更改的合集。
- 在最后, 我们手动查看合集中的内容, 并手动的添加到 srackhall-note 分支中(复制粘贴大法), 然后手动提交一次, 将更改合集合入我们的 srackhall-note分支。
- 此时, 我们的执行结果(即代码内容), 就与 srackhall保持一致了。
- 继续在srackhall-note进行开发, 并通过stash向 srackhall 分支输送无注释版本。
- 在最开始打算处理main分支pr之前, 多建立一个note-computer分支。 并在 pull main之后 , checkout note-computer分支, 对 main分支执行 merge 操作。
- 第三种:
- 结合第二种和第一种。
- 先通过第二种得知冲突具体位置。
- 然后在通过第一种中的 merge 来直接获取全部冲突, 然后无视掉具体冲突以外的(即接受为 srackhall-note, 若涉及大量文件,则不推荐此处理法), 然后着重处理具体冲突所在冲突文件(最终将其合并到位)。
- 第四种:
- 放弃原有srackhall-note
- 在srackhall分支指针出, 开启新的srackhall-note-1分支, 并依次往上累加。 并始终以最大值为准。
- 第一种:
.gitigonore
如果您不想让这些配置影响到您的仓库, 那么请在项目搭建之初, 就通过.gitignore
文件来忽略它们(Srackhall也推荐大家这么做)。
放心, 这不会对您的项目产生任何影响, 您只需要在clone后, 在项目根目录重新执行这篇文章的操作就可以了。