如何用 git worktrees 管理 Flutter 的 master、stable 与 PR 评审多条分支工作流
【免费下载链接】flutterFlutter makes it easy and fast to build beautiful apps for mobile and beyond项目地址: https://gitcode.com/GitHub_Trending/flutter41/flutter
Flutter 仓库的贡献者经常需要在 master(主开发分支)、stable(锁定最新稳定版,用于复现问题)以及若干临时 PR 评审分支之间来回切换。在单一克隆里切换分支,会触发 flutter artifacts 重新下载、flutter tool 重新编译,还常常需要 stash 未完成的改动;维护多份克隆则会让同一份源码重复.git目录。Flutter 官方贡献文档 Git & Worktree Workflow Guide 给出的方案是 git worktrees:多个工作目录各自检出不同分支,共享同一个 bare 仓库,再配合fswitch命令按终端切换环境。本文按该文档整理一条可执行的操作路径:搭好多分支 worktree 布局,然后用它完成 PR 评审、stable 问题排查和分支清理。适用环境为 Linux、macOS 或 Windows,需要 git,并遵循 Flutter 的远程命名约定:upstream指 flutter/flutter 上游,origin指你 fork 的仓库。
前提:一个已配置 upstream 与 origin 的 Flutter 克隆
先按 Setting up the Framework development environment 搭好一个 Flutter 开发环境(前提包括 Linux/macOS/Windows、git、IDE 等)。worktree 工作流依赖两个远程配置正确,配置步骤来自同一文档:
- 克隆 flutter/flutter 后,把默认远程改名为
upstream:
git remote rename origin upstream- 在 GitHub 上 fork 该仓库后,把你的 fork 添加为
origin远程。文档中的占位符████████需要你替换为自己的 GitHub 用户名:
git remote add origin git@github.com:你的GitHub用户名/flutter.git- 验证两个远程指向了预期的仓库:
git remote -vGit & Worktree Workflow Guide 明确说明其示例遵循的约定:upstream(git@github.com:flutter/flutter.git)是拉取 master/beta/stable 的 fetch 目标;origin(git@github.com:<你的用户名>/flutter.git)是功能 PR 的 push 目标。
目标布局:共享 .bare 的多 worktree 目录
文档给出的目标目录结构如下(文档示例,路径取自作者机器,179637只是示例中的 PR 编号):
~/flutter/ ├── .bare/ (The bare repo or main tracking folder) ├── .git (pointer to .bare/) ├── fswitch.sh ("fswitch" command line with tab completion - win32:.ps1) ├── master/ (Always clean, main development branch) ├── stable/ (Locked to latest stable release for repros) ├── review-179954/ (Temporary folder for reviewing a PR) └── feature/new-widget/ (Long-running feature work)这套布局的机制文档中有明确说明:
- 所有 tree 共享
.baregit 仓库。各分支的源码文件需要从.bare解包,<tree>/bin/cached二进制会在你运行 flutter tool 时下载到对应 tree 中。 master/保持 always clean,只做主开发;stable/锁定最新 stable 版本,用于复现问题。- 每个 PR 评审建一个临时目录,审完删除;长期功能开发放
feature/子目录。
文档展示了一个文档示例的磁盘占用输出(各机器数值会不同,不要当作固定预期):
--- /Users/codefu/src/flutter --- 1.9 GiB [#############################] /master 932.7 MiB [############## ] /stable 738.2 MiB [########### ] /pr-review 487.0 MiB [####### ] /.bare文档推荐使用 flutter_worktree 脚本初始化该布局:它的安装脚本会创建好已检出 master/stable 的 tree,并生成fswitch.sh文件(Windows 上为.ps1变体)。后续各场景的具体操作都是标准的git worktree命令,可以直接在按上述方式搭建的布局中执行。
用 fswitch 让每个终端固定使用 master 或 stable
将fswitch.sh在 shell profile(例如~/.zshrc)中 source 之后,可以开多个终端,分别固定 master 和 stable:
fswitch master # 当前 shell 的 PATH 指向 master/bin fswitch stable # 当前 shell 的 PATH 指向 stable/bin它的作用是更新当前 shell 会话的 OS PATH 搜索路径,让 VS Code、dart analyzer 等工具找到对应版本的 Flutter;文档说明在 Windows、Linux 和 macOS 上切换时不会触发重新下载。注意这是修改当前 shell 环境的操作,source 进 profile 后每次开新终端都会执行。
文档中的警告:不要从根目录运行 vscode 等工具,否则工具可能卡在索引所有 worktree 上。
评审 PR:检出到临时 worktree,审完即删
文档指出的动机是在 github.com 网页上评审缺少 dart analyzer 和 agent 等工具,把 PR 检出到本地可以完整使用这些工具。189954是文档示例中的 PR 编号,替换为你要评审的编号:
# 1. Fetch the PR HEAD git fetch upstream pull/189954/head:pr-189954 # 2. Checkout the PR - automatically follows pull/189954/head git worktree add pr-189954 # 3. Perform the review cd pr-189954 # 4. Delete the worktree when done git worktree remove pr-189954检出后可以用git log HEAD -n1确认拿到的提交。文档给出的示例输出(来自一个 autoroll 提交,不代表你必须得到相同结果):
# commit d277b8d7652b1baaf5844dc70040c60914b9eb5c (HEAD -> pr-189954) # Author: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> # Date: Thu Jul 23 21:35:02 2026 +0000清理时有一个必须遵守的细节:删除前先切换到其他 worktree 或回到含.bare目录的根目录,再执行git worktree remove pr-189954。该命令会删除这个 worktree 的工作目录,评审用的临时源码一并移除。
如果本机装了gh工具,文档给出了更短的可选路径:
git worktree add prreview cd prreview gh pr checkout 189954功能开发:在独立 worktree 中开发并推送
接到一个新功能(文档示例用feature/new-widget作分支名,可换成自己的命名)时:
# Start a new worktree branched from latest HEAD git worktree add feature/new-widget # Switch and start work cd feature/new-widget code . # Push it upstream git push --set-upstream origin $(git branch --show-current) # ... get reviews, make changes, pass tests # Delete the tree when done git worktree remove feature/new-widget文档说明这样做的好处:在准备好之前不需要 stash 或上传改动,master、stable 和其他功能分支都可以独立更新,不会丢失feature/new-widget里的上下文。
在 stable 或旧版本上复现与排查问题
接手一个有复现步骤的 issue 时,最简单的路径是直接切到 stable 测试:
# Switch to stable branch fswitch stable如果想从某个基线开始 bisect,文档的做法是建一个专属 worktree。其中baseref是文档占位符,替换为你要用的起点 ref(提交、分支或 tag):
git worktree add bugHunt baseref fswitch bugHunt # updates the binaries in the environment PATH cd bugHunt # changes to the bugHunt worktree同样的git worktree add <目录> <起点>模式,文档在检出旧 stable/beta 时给出了具体写法:git worktree add beta upstream/beta,然后fswitch beta。排查流程文档给出的示例(从 issue 拿到 reprocode 后):
# Debug however you need to flutter run # Alternate to master and see if its already fixed? fswitch master flutter clean flutter run如果确认了 bug 并要提 PR,文档建议像功能开发那样新建一个 worktree 来提交,而不是在 stable/master 分支里倒腾改动。
在 worktree 中更新 PR 分支:rebase 与 --force-with-lease
PR 分支需要跟进上游时,文档明确 Flutter 适配 rebase 工作流:merge master 会产生非线性历史,可能让检查提交时序的自动化工具误判;rebase 保持线性历史,且冲突在你的单个提交内解决,便于之后 cherry-pick。更新序列(文档原样给出):
# Update your upstream master references and clean up deleted branches git fetch upstream --tags --prune # Start an interactive rebase on top of the fresh upstream master git rebase -i upstream/master交互式 rebase 会在编辑器里列出你的提交,可以用squash或fixup合并“typo fix”“wip”这类提交,然后按顺序重放到最新 upstream master 之上。
因为 rebase 改写了分支的提交历史,普通的git push会被拒绝,必须 force push。文档强调不要使用裸的git push -f,而要带 lease:
git push --force-with-leaselease 会让 git 检查自你上次 fetch 之后是否有人向该远程分支推过提交,避免覆盖协作者的工作。
限制与文档中已知的行为
- 一个分支不能同时被两个 worktree 检出。如果目标分支已在另一个 worktree 中,git 会拒绝切换并报错,文档给出的示例信息为:
fatal: 'master' is already used by worktree at '/Users/codefu/src/flutter/master'(路径为作者机器的示例值)。 - 不要在根目录运行 vscode 等索引工具,文档说明这会卡住索引过程。
- 每个 tree 的
bin/cached二进制是运行 flutter tool 时才下载到该 tree 的,多个 tree 会各自占用磁盘(参考上文文档示例的占用输出)。 git worktree remove会删除对应的工作目录,删除前需先离开该目录。
完成一轮工作后的收尾就是:评审用 tree 审完即git worktree remove,功能 tree 合入后同样删除,.bare、master/、stable/三个常驻结构保持不变,供下一轮 PR 评审和问题排查继续使用。
【免费下载链接】flutterFlutter makes it easy and fast to build beautiful apps for mobile and beyond项目地址: https://gitcode.com/GitHub_Trending/flutter41/flutter
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考