改进 Git flow 来管理 Bitbucket 上的私有 TypeScript 依赖

在目前的工作中,Bitbucket 同时被我们用作代码仓库和私有 NPM 仓库。通过 git+ssh 指定 tag 来安装依赖,对于纯 JavaScript 的项目十分方便。

随着部分依赖开始使用 TypeScript,基于现有使用方式,需要对这部分依赖采取下面的一种方式进行管理。

  1. 直接将编译后的 dist 文件提交到主分支上。
  2. postinstall 中进行编译。当依赖被安装后,就会自动编译。

但无论哪种方式,都会有一些瑕疵。

  • 直接将 dist 提交到主分支上,在做 Code review 时会额外多出许多文件干扰,项目结构也不优雅。
  • 通过 postinstall 的方式对于纯 JavaScript 的项目就需要额外安装 typescript,同样不优雅。

出于人力以及迁移仓库的成本考虑(我们有近 100 个依赖,且每个依赖有许多版本并且被不同的服务引用),对此只能通过改进 Git flow 来解决上述瑕疵。

目标

重新设计的 Git flow 需要满足以下目标。

  1. 开发分支上不需要编译后 dist 文件。
  2. 不需要通过 postinstall 的方式来编译。
  3. 引用的方式不发生改变,还是通过 git+ssh 指定 tag 的方式安装依赖。
  4. 需要考虑到 hotfix 的情况。

Git flow 改进

为了实现上述目标,下面是改进后的 Git flow。

对于正常的开发,当代码合并到 master 后,先推送 src tag 并修改 .gitignore 临时创建 build 分支。随后在 build 分支编译并且打上正式 tag,正式 tag 包含 dist 文件,可以被其他服务引用。

当需要进行 hotfix 时,就可以从对应的 src tag 上切出分支进行 fix,之后再以相同的步骤合入 master 分支。

Pipeline 脚本设置

上述的 Git flow 在代码合并之后有打 tag、修改 .gitignore、编译再发布的步骤。即便有文档说明,在实际操作上也很容易出错。因此十分有必要将这些步骤自动化。利用 Bitbucket Pipeline 在代码合入 master 分支时自动执行。

下面是示例代码。

  1. Pipeline 部分
yaml 复制代码
branches:
  master: # 当合入主分支时才会触发
    - step:
        name: build
        deployment: Build # 以 Deployment 的方式执行,名字可以随意指定
        script:
          - git remote set-url origin ${BITBUCKET_GIT_SSH_ORIGIN}
          - ./scripts/build.sh # 实际执行的脚本
  1. 打 tag 以及编译脚本。

pipeline 中的 build.sh,整个 Git flow 的核心。实现打 src tag、编译以及推送编译后的正式 tag。

tag 的版本遵循 semver 规则,当前 tag 为 package.json 中的 version。下一个版本则来源于分支名的前缀,比如分支名为 major/xxxx 即下一个版本升级主版本号;如果是 feature/xxx 则为 minor。利用 npm version 命令升级标签。

sh 复制代码
#!/usr/bin/env bash

set -e
# Create tags in the bitbucket pipline, env from bitbucket pipeline
source_branch=$(git log --format=%B -n 1 $BITBUCKET_COMMIT | awk '{print $3}')

if [[ -n $source_branch ]]; then
  # PART 1: Get the next tag
  echo "Triggered by pull request ${source_branch}"

  if [[ ${source_branch} == feature/* ]]; then
    level=minor
  elif [[ ${source_branch} == bugfix/* ]]; then
    level=patch
  elif [[ ${source_branch} == hotfix/* ]]; then
    level=prerelease
  elif [[ ${source_branch} == major/* ]]; then
    level=major
  else
    echo "Nothing happen on branch: ${BITBUCKET_BRANCH}"
    echo "Source branch: ${source_branch}"
  fi

  if [[ ! -z ${level} ]]; then
    # PART 2: Create src-tag and push back
    current_version=$(node -e "console.log(require('./package.json').version)") && echo "Current version - ${current_version}"
    echo "Crated version on branch: ${BITBUCKET_BRANCH}. Tag: ${current_version}"

    next_version=$(npx semver ${current_version} -i ${level})
    source_tag=v${next_version}-src

    echo "Build source tag: ${source_tag} on branch: ${BITBUCKET_BRANCH}"
    # Create the source tag and push back
    npm version ${next_version} --no-git-tag-version # This will not create a git tag just update the version in the package.json

    git add --all
    git commit -m "[skip ci] ${current_version} --> ${next_version}" # [skip ci] Will not trigger this pipeline again
    git tag -am "[skip ci] source tag: ${source_tag}" ${source_tag}
    git push origin ${BITBUCKET_BRANCH} ${source_tag}

    # PART 3: Add the dist folder and create release tag
    # Add the dist folder
    sed -i 's/dist//g' .gitignore

    # build ts
    npm run build

    # push to tag
    git add --all
    git commit -m "[skip ci] Build release tag: ${next_version} on branch: ${BITBUCKET_BRANCH}"
    git tag -am "[skip ci] release tag: ${next_version}" ${next_version} # only push the tag
    git push origin refs/tags/${next_version}
  fi
fi

Shell 脚本最好放在 Deployment 中执行。因为 Deployment 是阻塞队列,可以保证同一时间只有一个脚本在运行,从而避免 tag 重复冲突的问题。

同时对于开发分支的命名也需要做一定的限制。比如可以使用 husky 等工具。

拓展

这一套 Git flow 可以在任何的代码托管工具使用,即便没有类似 Pipeline/GitAction 的触发方式同样也可以通过跑脚本的方式实现。同时可以实现自动打 tag 的功能。

虽然没有完美的 Git flow,但一套合适的 Git flow 也可以让我们的工作更加规范,提高工作的效率。

本文由mdnice多平台发布

相关推荐
zzzll11112 小时前
Spring Boot 实现数据脱敏:自定义注解 + Jackson 序列化器
java·spring boot·后端
vx-Biye_Design6 小时前
SSM伴侣动物伴护星小程序06330-计算机课程设计、毕业设计
spring boot·后端·elasticsearch·小程序·架构·课程设计·idea
2分钟速写快排8 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
面向Google编程8 小时前
Apache Iceberg Variant 类型:v3 半结构化数据不再「二选一」
大数据·后端
jason成都9 小时前
Spring WebFlux 适配达梦新方案|dm‑r2dbc:Netty 异步传输的实验性 R2DBC 驱动
java·后端·spring
云泽80810 小时前
Git 版本控制系统(下):从 .git 目录结构到冲突解决机制详解
大数据·git·elasticsearch
北岛贰10 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
IT_陈寒13 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端
小兵金林14 小时前
AI 生成代码的思考与实践
后端·ai编程
码事漫谈14 小时前
DeepSeek 明天又降价(涵历史价格对比)
后端