flutree is a Go CLI to manage Git worktrees for multi-package Flutter workflows.
- π Features
- π¦ Installation
- π§ Requirements
- ποΈ Commands Reference
- π οΈ Quickstart
- π Recent CLI adjustments
- βοΈ Advanced Usage
- π Version and update
- π§ͺ Testing
- π€ Non-interactive behavior
- ποΈ Registry
- ποΈ Project structure
- π€ Contributing
- π License
- π Acknowledgments
- Multi-package Management: Handle complex Flutter monorepos with multiple packages efficiently
- Git Worktree Integration: Seamless integration with Git's worktree functionality
- Parallel Operations: Execute operations across multiple worktrees in parallel
- VSCode Workspace Generation: Automatically generate workspace files for IDE integration
- Package Override Support: Manage
pubspec_overrides.yamlfiles for development workflows
brew tap EndersonPro/flutree
brew install EndersonPro/flutree/flutreeUpgrade:
brew update
brew upgrade flutree
# or via flutree helper command
flutree updatego build -o flutree ./cmd/flutree
./flutree --help- Go
>=1.22(for local build from source) - Git available in
PATH
Run from inside a Git repository:
flutree create feature-login --branch feature/login --root-repo repo --scope . --yes --non-interactive
flutree add-repo feature-login --repo core-pkg --scope . --non-interactive
flutree list
flutree --version
flutree update --check
flutree pubget feature-login
flutree pubget feature-login --force
flutree complete feature-login --yes --forceIf you omit --branch, branch defaults to feature/<normalized-name>.
Package worktrees reuse the exact same branch token as root (--branch value, or the default when omitted).
Use --yes on create with --non-interactive to approve the dry plan in automation and CI scripts.
Default destination root is ~/Documents/worktrees, generating:
~/Documents/worktrees/<worktree-name-slug>/
- Every subcommand supports command-scoped help via
--helpand-h. create --no-packageis now an explicit root-only mode:- package selection is skipped in interactive mode,
--no-packageconflicts with--packageand--package-base(fail-fast input error).
add-repois the command for attaching repositories after a workspace already exists.- Before syncing branches from
originduringcreate, the CLI now asks for confirmation:- Yes β sync from
originand continue with worktree creation. - No β skip remote sync entirely and continue from local refs.
- Yes β sync from
list --globalalways uses global registry scope, regardless of current directory.list --global --allincludes unmanaged worktrees across all globally selected repositories.
create now runs a strict two-phase flow before mutation:
- first, it renders a full dry plan preview (repos, branches, paths, commands, and output files);
- second, it asks for one final confirmation token gate before
git worktree addand file/registry writes.
For automation/non-interactive runs, create --non-interactive requires explicit --yes and --root-repo.
If the target branch already exists, non-interactive runs also require --reuse-existing-branch.
Use --no-package when you need a root-only workspace and no package metadata flow.
--no-package cannot be combined with --package or --package-base.
In interactive mode, after selecting Apply changes, create asks whether local branches should be synced from origin before worktree creation.
If the answer is Yes, create syncs before worktree creation and fails fast if sync cannot be completed.
If the answer is No, create skips remote sync and continues from local refs.
For deterministic package targeting during create, use --package and optional --package-base.
If you forget to include a repository at create time, attach it later with add-repo.
Example with root env propagation:
flutree create feature-login --scope . --root-repo root-app --copy-root-file ".env.local" --yes --non-interactiveDisable workspace generation when needed:
flutree create feature-login --scope . --root-repo root-app --yes --non-interactive --no-workspacePackage override generation rules:
flutree createwrites onepubspec_overrides.yamlin the selected root worktree.pubspec.yamlis not modified.
VSCode workspace output is MVP-only and includes folders entries only.
settings, tasks, and launch are intentionally not generated.
Use --no-workspace to skip .code-workspace output entirely.
All subcommands support:
--help-h
Creates a managed worktree and stores metadata in a global registry.
Usage:
flutree create <name> [options]
| Flag | Type | Default | Description |
|---|---|---|---|
--branch |
string | feature/<name> |
Target branch name |
--base-branch |
string | main |
Base branch for worktree creation |
--scope |
string | . |
Directory scope used to discover Flutter repositories |
--root-repo |
string | Root repository selector (required in non-interactive mode) | |
--workspace |
boolean | true |
Generate VSCode workspace file |
--no-workspace |
boolean | false |
Disable VSCode workspace generation |
--yes |
boolean | false |
Acknowledge dry plan automatically in non-interactive mode |
--non-interactive |
boolean | false |
Disable prompts |
--reuse-existing-branch |
boolean | false |
Reuse existing local branch in non-interactive mode |
--no-package |
boolean | false |
Root-only mode (skip package selection and package metadata) |
--package |
string | Package repository selector (repeatable) | |
--package-base |
string | Override package base branch as <selector>=<branch> (repeatable) |
|
--copy-root-file |
string | Extra root-level file/pattern to copy into each worktree (repeatable). By default .env and .env.* are copied when present |
Attaches additional repositories to an existing managed workspace and regenerates pubspec_overrides.yaml.
Usage:
flutree add-repo <workspace> [options]
| Flag | Type | Default | Description |
|---|---|---|---|
--scope |
string | . |
Directory scope used to discover Flutter repositories |
--repo |
string | Repository selector to attach (repeatable). Required in non-interactive mode | |
--package-base |
string | Override package base branch as <selector>=<branch> (repeatable) |
|
--copy-root-file |
string | Extra root-level file/pattern to copy into attached worktrees (repeatable). Default includes .env and .env.* |
|
--non-interactive |
boolean | false |
Disable prompts |
Lists managed worktrees. By default, scope is current repo when available (fallback to global outside a repo).
Use --global to force global registry scope from any location.
Usage:
flutree list [options]
| Flag | Type | Default | Description |
|---|---|---|---|
--all |
boolean | false |
Include unmanaged Git worktrees |
--global |
boolean | false |
Force global registry scope regardless of current directory |
Remove-only completion flow (removes worktree and keeps local branch). If a recorded path is already missing, completion performs stale registry cleanup and still succeeds.
Usage:
flutree complete <name> [options]
| Flag | Type | Default | Description |
|---|---|---|---|
--yes |
boolean | false |
Skip interactive confirmation |
--force |
boolean | false |
Force worktree removal |
--non-interactive |
boolean | false |
Disable prompts |
Runs pub get for all managed package repos in parallel, then runs root last. Includes interactive loading feedback on TTY.
Usage:
flutree pubget <name> [--force]
| Flag | Type | Default | Description |
|---|---|---|---|
--force |
boolean | false |
Clean cache and remove pubspec.lock before pub get |
Stable version output:
flutree --version
flutree versionSingle source of truth policy:
- Release Please is the canonical source for release versioning.
VERSIONis auto-managed by the release PR and mirrors release-please version output.- Packaging injects this value into CLI output (
flutree --version). - Release gate enforces
tag == VERSION == flutree --version. .release-please-manifest.jsonandVERSIONare expected to stay aligned.
Brew-only update flow:
flutree update --check
flutree update
flutree update --applyflutree update is equivalent to flutree update --apply.
Current update automation scope is Homebrew only (non-brew channels are out of scope in this release).
Exit code contract for version/update paths:
0: success1: brew/precondition/process failure onupdate2: input/cancel validation failures
Release contract verification commands:
./scripts/check_version_contract.sh
./scripts/check_version_contract.sh --tag v$(cat VERSION)
ARCH=arm64 ./scripts/package_macos.sh build
./scripts/verify_macos_binary.sh dist/flutree-$(cat VERSION)-macos-arm64.tar.gz --expected-version $(cat VERSION)go test ./...Example of manual test flow:
go build -o ./flutree ./cmd/flutree
./flutree list
./flutree create demo --scope . --root-repo <repo> --yes --non-interactive
./flutree complete demo --yes --forcecreaterequires final confirmation in interactive mode.create --yesis only auto-approval in--non-interactivemode.create --non-interactivewithout--yesfails fast by design.create --non-interactivealso requires explicit--root-reposelector.create --non-interactiverequires--reuse-existing-branchwhen the target branch already exists.completerequires confirmation unless--yesis passed.complete --non-interactivewithout--yesfails fast by design.
0: success1: operational/precondition/process/git/update failure2: input or user-cancelled flow
Global registry file:
~/Documents/worktrees/.worktrees_registry.json
Writes are atomic and schema-validated.
cmd/flutree/
internal/
app/
domain/
infra/
runtime/
ui/
docs/
usage.md
architecture.md
More details:
docs/usage.mddocs/architecture.md
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with Bubble Tea for interactive UI
- Inspired by the need to manage complex Flutter monorepo workflows