PAYATHON 2026

如何使用 git 隔离产品版本并基于旧 commit 发布修复?

技术老齐

这次可以从当前生产版本对应的旧 commit 创建修复分支,无须重新 clone,也不用撤销已经合入 master 的五个功能分支。

从生产版本拉出独立的 hotfix 分支,只加入必要修复,测试通过后发布,再把修复带回后续开发分支。

先确定前后端各自的生产版本

创建分支前,先确认线上前端和后端分别对应哪个 commit。两个仓库的历史互相独立,生产版本通常对应不同的 commit SHA。

优先查上次生产发布的 tag、Jenkins 构建记录或部署记录。不要只凭提交日期推测,也不要直接使用测试环境当前运行的版本,因为其中可能已经包含尚未通过验收的功能。

如果之前没有记录 commit,部署时又手动改过文件,就要先核对线上产物和仓库代码,确认修复应基于哪个版本。

分支和 tag 各有用途:

  • 分支用于继续提交修改,例如 hotfix/v1.4.1。
  • tag 用于标记某次发布对应的提交,例如 v1.4.1。已经发布的 tag 应保留原来的指向。

下面的版本号和文件路径都是示例,执行时请替换为项目实际值。

从生产 commit 创建修复分支

在需要修改的仓库目录中执行:

git fetch origin --tags
git status

先处理工作区中尚未提交的改动,避免把其他开发内容混入修复,再创建分支:

production_commit='替换为该仓库生产版本的完整 commit SHA'

git switch -c hotfix/v1.4.1 "$production_commit"

这条命令会创建分支并切换工作区,不必先 checkout 到旧 commit。

如果生产版本已有 tag,也可以直接从 tag 创建:

git switch -c hotfix/v1.4.1 v1.4.0

以上两种方式任选一种。如果 Git 版本较旧,不支持 git switch,可以使用:

git checkout -b hotfix/v1.4.1 "$production_commit"

此时,工作区中的代码以生产版本为基础,master 后来合入的新功能不会自动进入这条分支。完成修复后,检查并提交:

git diff

git add path/to/changed-file
git diff --cached
git commit -m "Fix production issue"

git push -u origin hotfix/v1.4.1

前后端按各自的生产 commit 分别处理。如果只修改后端,前端可以继续使用原来的生产产物,无须为这次发布额外创建提交。

是否需要重新 clone?

重新 clone 也能实现目标,主要作用是提供另一个工作目录。Git 分支本身就能隔离不同的代码历史,可以按实际需要选择:

需求适合的方式
暂停当前开发,处理完修复再切回来在现有目录中使用 git switch
同时打开开发版本和修复版本使用 git worktree
需要完全独立的本地仓库或不同权限配置重新 clone
只查看或构建某个历史提交checkout 指定 commit,允许处于 detached HEAD 状态

如果想保留当前开发目录,可以使用 git worktree。在尚未创建 hotfix 分支时,在原仓库中执行:

production_commit='替换为该仓库生产版本的完整 commit SHA'

git worktree add -b hotfix/v1.4.1 ../project-hotfix "$production_commit"

这会创建工作目录 ../project-hotfix,并在其中检出修复分支。两个目录共享 Git 对象数据库,各自拥有工作区和暂存区。

这条命令可以替代前面的分支创建操作;如果同名分支已经存在,就不要重复执行。

让 Jenkins 构建明确的版本

如果现有 pipeline 始终 checkout master,需要调整为支持指定分支、tag 或 commit。

这次可以先让 Jenkins 构建 hotfix/v1.4.1。测试通过后,在最终提交上创建发布 tag:

git tag -a v1.4.1 -m "Production hotfix v1.4.1"
git push origin v1.4.1

正式发布时,要记录构建实际使用的完整 commit SHA。分支会继续前进,只记录分支名无法准确说明某次发布用了哪些代码。

两个仓库还需要记录经过联合测试的版本组合,例如:

产品发布Front-End RepositoryBack-End Repository
本次修复版本沿用的前端生产 commit SHA包含修复的后端 commit SHA

这份对应关系可以保存在 Jenkins 构建元数据或发布清单中。即使两个仓库使用相同名称的 tag,Git 也不会自动建立它们之间的关联。

尽量将测试通过的同一份构建产物部署到生产环境,并保存产物及其来源记录。旧 commit 能确定源码,构建结果还取决于依赖、SDK 和配置,这些也应尽量固定。

如果旧 commit 中没有当前使用的 Jenkinsfile,可以让 Jenkins 通过独立维护的构建定义检出目标源码,或调整 pipeline,让它能够构建该历史版本。

把修复带回后续开发

修复应通过提交带回后续开发分支,即使只改了两行,也方便检查是否遗漏。

如果修复是一个独立提交,可以从最新 master 创建分支,再执行 cherry-pick:

git fetch origin

git switch -c fix/forward-port-v1.4.1 origin/master

fix_commit='替换为 hotfix 修复提交的完整 SHA'
git cherry-pick "$fix_commit"

git push -u origin fix/forward-port-v1.4.1

然后按项目现有的代码审查流程合入 master。cherry-pick 会将该提交引入的修改应用到当前分支,并生成新的提交。

如果新版本中的相关代码已经改变,可能需要解决冲突或调整实现,再验证修复是否仍然有效。如果同时独立维护多个版本,也要确认哪些版本需要这项修复。

也可以将 hotfix 分支合并回 master。如果修复分支只包含需要带回的改动,团队又希望保留合并关系,就可以采用这种方式。

后续如何安排版本和环境

当前项目可以保留 master 继续开发,用短期 hotfix 分支修复生产问题,足以处理这次发布。

如果以后经常需要同时维护多个已发布版本,可以为仍受支持的版本建立维护分支,例如 release/1.4。后续修复从相应维护分支展开,每次发布再打 tag。

尚未通过验收的功能,需要在合入时控制范围。使用 feature branches 本身不能保证向后兼容,兼容性仍要通过接口设计、数据变更策略和测试来验证。如果团队要求 master 随时可发布,就应让未完成的功能继续留在分支中,或使用经过验证的 feature flags 控制开放。

Git 只负责代码版本。要让同事同时测试新功能版本和 hotfix,需要在 Jenkins 和 IIS 中安排不同的部署目标,并按需隔离配置、文件目录、应用程序池及测试数据。如果数据库结构已经随新版本改变,还要确认旧版代码能否使用当前数据库。

即使修复只有两行,也要验证问题场景,检查前后端版本组合。发布记录中应保留原生产产物和部署配置;涉及数据库迁移时,还要单独安排回退方式。

备注:内容仅供参考。