前言

使用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/
  • 当然, 学以致用, 按照约定式提交迭代的项目, 可以很好的兼容这些规范, 本人也是比较建议大家按照规范来开发迭代并发布的。相关的插件, 会在搭建流程章节介绍个人的选择。

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
      7
      npm 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 or Breaking 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 的方式, 向 devmain 主分支内合入提交。

    当然, 我会在规则中, 强制这一做法, 所有人必须通过 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, 仅拉取数据, 稍后在本地手动处理合并。

  • 删除远端的 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 的。
    • 针对最终的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分支, 优先处理
  1. 我们在 srackhall 分支上 srackhall所在位置, 创建一个 srackhall_copy分支(用于做为srackhall分支的副本使用)
  2. git checkout main
  3. git pull origin main
  4. git checkout srackhall
  5. (看情况使用)git rebase main

    如果main分支在第2步有新节点, 则执行此步骤, 否则无需执行
    执行此步骤时, 请细心处理冲突

  6. git push srackhall , 获得 origin/srackhall
  7. 创建并提交pr: origin/main <- origin/srackhall
  8. 处理pr, 处理过程略…
  9. 最终将处理好的pr, 使用 squ…. 或 rebase and merge 将其合入主分支
  10. 删除origin/srackhall, 并回到本地, 在本地也将其缓存删除

    对与远程以删除的陈旧缓存, 我们可以对具体仓库名称使用此命令git remote prune [仓库名称]

    git remote prune origin 执行后, 即可自动基于origin远程仓库来清除本地陈旧的远程分支缓存。

  11. git checkout main
  12. git pull origin main , 并检查最终成果

    如果你忘记检出到main分支, 影响了其它分支处理merge的话

    • 若为快进式, 可直接通过此命令git branch -f <branch-name> <commit-hash>将相应分支指针移动回原有位置。
    • 若为非快进式, 则全选当前分支, 并在之后使用相同的方法将相应分支指针移动回原有位置。
  13. 删除原 srackhall, 并在当前最新的main分支指针处, 新建srackhall

    非必要, 如果远端处理pr选择了 rebase and merge 的话, 就无需这一步了

    • 删除命令为 git branch -D [分支名称] (-D大写意为强制删除, 小写则为非强制, 一般我直接用大D)
  14. git checkout srackhall , 继续开发

    如果你使用了dev分支, 则先处理dev分支的pr(参考 2 ), 再继续开发
    如果你使用了stash + srackhall-note的组合, 则先处理srackhall-note(参考 3 ), 再继续开发。

2、若使用了dev分支, 则继续处理dev分支

(后续对dev分支的操作, 看个人需求, 我本人已弃用dev, 触发github禁用中国用户, 否则以上操作完全够用)(如果您不喜欢dev这个名字, master这个名字也很合适这个分支的作用)

  1. 检查此时的srackhall分支, 是否与srackhall_copy分支发生不一致。 并建立 srackhall_dev 分支。

    若发生, 则删除原本的srackhall_copy, 并在最新的srackhall分支指针处重新创建一个srackhall_copy

  2. git checkout dev
  3. git pull origin dev

    这里的dev分支, 一般情况下与main分支一致, 目前就我一个人用, 不可能出现不一致情况, 人多就不一定了, 不过此分支只允许我一人操作就好了, 保证不会有其它人对此分支做操作。
    不过就算到时候找了其他可操作此分支的人, 应该也可以(推测)直接在远程写脚本来执行处理, 毕竟pr已经处理过冲突了, 即使直接在远端rebase也问题不大

  4. git checkout srackhall-dev
  5. (必须使用)git rebase dev

    由于已在main的过程中处理过冲突, 这里一般可以直接迁移分支名指针。(除非,在此期间有其它用户操作dev分支向起合入了其它commit)

  6. git push srackhall_dev , 获得 origin/srackhall-dev
  7. 创建并提交pr: origin/dev <- origin/srackhall-dev
  8. 处理pr, 处理过程略…

    此处在origin/main的pr过程中其实已处理过了, 因此无需处理。

  9. 最终将处理好的pr, 使用 非快进式合并 或 rebase and merge 将其合入dev分支

    这里根据origin/main的处理对照处理即可, 若前面选择用了 squ.. 则此处就选 非快进式, 否则就与前面一致地使用 rebase and merge

  10. 删除origin/srackhall-dev, 并回到本地, 在本地也将其缓存删除
  11. git checkout dev
  12. git pull origin dev , 并检查最终成果
  13. 删除原 srackhall-dev, 并在当前最新的main分支指针处, 新建srackhall-dev

    必要, 因为我们不需要此分支

  14. git checkout srackhall , 继续开发
3、处理srackhall-note分支(如果你使用了)

note分支, 仅推荐纯个人项目使用(或前期仅有一个人时的项目使用--特别是初始的设计和架构阶段<此阶段往往会产生大量无效注释>), 若你有开源意愿, 或者后期可能以团队模式开发, 则不推荐使用, 因为参与进此项目的其它用户, 会使得此分支增加极为巨大的重复工作量

note分支可以将前期设计阶段的大量思考想法类注释–即对开发和代码阅读无意义的注释, 给拦截在主分支、dev分支以及 srackhall分支外。 等测试版本发布时, 对于项目的整体介绍和未来规划, 是可以参考最初的note分支的。

  • 若你前期使用了, 后期想要弃用, 对于注释,最好取其精华的适当逐步地添加入主线。 然后逐步抛弃note分支。
  • 若你仅在设计阶段当作初始文档使用, 当进入正常开发后(即注释稳定后), 记得逐步抛弃note分支。
  • 若你可以确认, 分支中没有除你自己的提交以外的提交。(如果项目只有自己在做开发, 则这个是必然的, 无需往后看了)

    此时无需处理srackhall-note分支, 继续使用当前srackhall-note做开发, 并继续和srackhall分支共用stash即可。

  • main分支中有他人的commit混入(项目做起来后, 概率极大), 那么有以下多种方案, 可供选择:

    • 第一种:
      1. git checkout srackhall-note
      2. git [merge/rebase] main (这个工作量有点大了其实) (冲突数量极大, 因此不建议)
      3. 此时, 我们的执行结果(即代码内容), 就与 srackhall保持一致了。
      4. 继续在srackhall-note进行开发, 并通过stash向 srackhall 分支输送无注释版本。
    • 第二种:
      1. 在最开始打算处理main分支pr之前, 多建立一个note-computer分支。 并在 pull main之后 , checkout note-computer分支, 对 main分支执行 merge 操作。

        得到一个除我之外, 其他人对main分支的commit做的更改的合集。

      2. 在最后, 我们手动查看合集中的内容, 并手动的添加到 srackhall-note 分支中(复制粘贴大法), 然后手动提交一次, 将更改合集合入我们的 srackhall-note分支。
      3. 此时, 我们的执行结果(即代码内容), 就与 srackhall保持一致了。
      4. 继续在srackhall-note进行开发, 并通过stash向 srackhall 分支输送无注释版本。
    • 第三种:
      1. 结合第二种和第一种。
      2. 先通过第二种得知冲突具体位置。
      3. 然后在通过第一种中的 merge 来直接获取全部冲突, 然后无视掉具体冲突以外的(即接受为 srackhall-note, 若涉及大量文件,则不推荐此处理法), 然后着重处理具体冲突所在冲突文件(最终将其合并到位)。
    • 第四种:
      1. 放弃原有srackhall-note
      2. 在srackhall分支指针出, 开启新的srackhall-note-1分支, 并依次往上累加。 并始终以最大值为准。

.gitigonore

如果您不想让这些配置影响到您的仓库, 那么请在项目搭建之初, 就通过.gitignore文件来忽略它们(Srackhall也推荐大家这么做)。

放心, 这不会对您的项目产生任何影响, 您只需要在clone后, 在项目根目录重新执行这篇文章的操作就可以了。