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 ImprovementorBreaking 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.zx的变更, 是正式版本的变更, 证明您的API已经稳定了, 不会再有破坏性变更了。 若x发生变更, 须将y和z清零。x.Y.zy的变更, 是新功能发布的变更, 可以包含开发过程中涉及的fix。若y发生变更, 须将z清零。x.y.Zz的变更, 是代表修复的变更, 指修复了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后, 在项目根目录重新执行这篇文章的操作就可以了。

.png)