All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
2.1.0 - 2026-09-08
checkoutis worktree-aware: when the branch has a worktree, it reports the path and offers it to the calling shell instead of switching the current worktree's branch.--worktreecreates a missing worktree first and records git-flow as its creator,--forceclears a plain directory out of the way,--no-cdsuppresses only the shell handover, and--quietdrops the shell-init tipshell-init {bash|zsh|fish}prints a shell wrapper that turns that handover into an automaticcd. It defines both agitand agit-flowfunction, so the documentedgit flow …form navigates too, and it scopes the navigation variable to a single command rather than exporting itworktree addnow points atshell-initwhen the navigation channel is unused, and gains--quietto suppress that tip<type> start --worktreecreates the new branch in its own worktree instead of checking it out, records git-flow as its creator, and offers the path to the calling shell.--worktree-pathputs it somewhere else and implies--worktree,--no-worktreeopts out,--no-cdsuppresses only the shell handover, and--quietdrops the shell-init tip. Combining the three is not an error: the one that appears last on the command line wins, which is specific to these flags — every other--x/--no-xpair in git-flow still prefers the positive flag whatever the ordergitflow.branch.<type>.worktreemakes worktree creation the default for a topic branch type, sostartneeds no flag.initwrites the key for topic branch types only<type> list --worktreesappends a column reporting each branch's linked worktree: its path relative to the main worktree root,[n]for the number of changed entries,(unmanaged)for a worktree git-flow did not create,(missing)for one that is no longer present at its recorded path, and-for a branch with no linked worktree — including a branch checked out in the main worktree, since the column reports linked worktrees. The count is ofgit status --porcelainentries rather than files, so an untracked directory counts once however many files it holds. Without the flag the output is unchangedfinish --ff-only(andgitflow.<type>.finish.ff-only) makes a fast-forward into the parent a precondition rather than a strategy: if the parent carries any commit the topic branch does not — a true divergence, or merely being ahead — finish aborts before touching any local branch, tag or the working tree, so what lands on the parent is exactly the tested topic tip. It is rejected in combination with--ff,--no-ff, or a squash strategy, it suppresses the rebase of a rebase strategy rather than rewriting the topic branch to make it land, and it constrains the upstream merge only, not the automatic child updatesfinishanddeletefree a branch's linked worktree as part of deleting the branch, instead of leaving a stale checkout behind or failing outright because Git refuses to delete a branch that is still checked out somewhere. A worktree git-flow created is removed; one created by hand (git worktree add) is kept, with its HEAD detached from the branch so the directory and every file in it, including uncommitted work, survive untouched.--keep-worktreeroutes even a git-flow-created worktree through the detach path instead of removing it, and--force-worktree/-Wallows removing one with uncommitted or untracked changes; neither flag has a git config equivalent. Both commands refuse up front, before any destructive step, if the worktree has a merge, rebase, bisect, cherry-pick, or revert in progress. Running finish or delete from inside the worktree being freed first redirects the operation to the parent branch's own worktree (or the main worktree) so the worktree is left untouched until the free step, and reports the new location viaGIT_FLOW_CD_FILEif the invoking shell was standing there. A rebase-strategy finish is refused outright against a topic branch with its own separate worktree, and a child base branch due for auto-update is refused the same way if it has its own separate worktree — both before the merge starts
startno longer checks the new branch out when it creates a worktree for it: Git allows a branch in only one worktree at a time, so the invocation worktree stays where it was. Without a worktree,startchecks the branch out exactly as beforeworktree listnow reads every worktree's provenance in one bulked lookup instead of onegit configcall per row, so the cost of the listing no longer scales with the number of worktrees
- The EXIT STATUS section of the
git flow <type> checkoutmanpage documented codes 1/2/3/4 that the command has never returned; it now documents the actual 1/2/3/5/6 finishcollected the auto-update child base branches in Go's randomized map order, so with more than one auto-update child the order they were updated in, the order they were reported in, and the order recorded in merge state (the resume order after a conflict) all varied between identical runs; children are now processed in sorted order, matchingintegratefinishleft you on the parent branch, so areleaseorhotfixfinish ended onmaininstead of ondevelopas git-flow-avh does — even under--keep, where nothing is deleted and the checkout served no purpose. It now ends on the integration branch: the last auto-update child of the parent, or the parent itself when it has none. The branch is derived from the configured topology rather than a hardcoded name, so it works for custom branch names too, and finish reports the branch it leaves you on- The
git flow <type> listmanpage documented a[pattern]argument with shell-style globbing, a*current-branch marker and remote tracking information that the command has never had, plus a trailing period on the empty-result message and exit codes it has never returned; it now documents what the command actually does and the codes 0/1/2/3 it actually returns. The same[pattern]argument is gone from the topic-subcommand list in thegit flowmanpage overviewbuilt each of its lists by ranging over the branch configuration map, so on a stock repository the topic branch type sections — and, with more than one trunk or child base branch, those lists too — came out in Go's randomized map order and varied between identical runs. Everything is now listed alphabetically by branch type name, including the type reported for an active topic branch that matches more than one configured prefixconfig listcategorized the configured branches by ranging over the branch configuration map, so on a stock repository the topic branch type sections — and, with more than one trunk or child base branch, those lists too — came out in Go's randomized map order and varied between identical runs. Trunk branches, child base branches and topic branch types are now each listed alphabetically by branch type name, matchingoverviewconfig listpresented every started topic branch as a branch type with no parent, start point or prefix. Eachstartrecords a runtimegitflow.branch.<branch>.basekey, which the config parser turns into an entry with no type, and the listing put anything that was not a base branch in the topic type section. It now lists the configured topic branch types only- Worktree path comparison ignores case on Windows, where two spellings of one location differing only in case were treated as different paths. The refusal to remove or detach the main worktree, the refusal to delete a registered worktree, and the detection that the shell is standing inside a worktree being removed all failed to fire on a case mismatch
- The shorthand
git flow finishaccepted--merge-messageand--update-messagebut built its merge strategy without them, silently ignoring both flags even though the per-type command surface honored them as documented - Zsh tab completion for the
git flow <type> ...form (as opposed togit-flow <type> ...) tried to invoke a nonexistentflowcommand; the dispatcher's word-shifting now gets the same fixup already applied for the bash and fish bridges
2.0.0 - 2026-08-09
- Shared, committable configuration:
init --sharedwrites the git-flow setup to a.gitflowfile at the repository root and copies it into local config, so a team's branch model can live in the repository instead of every clone --sharedon everyconfig add,edit,rename, anddeleteverb edits the shared.gitflowfile and re-syncs local configconfig synccopies.gitflowinto local config, andconfig statusreports drift between the two (exit code 6 when they differ)- A fresh clone carrying a
.gitflowis offered activation on first run — prompted when interactive, applied automatically withgitflow.shared.autoInit, and topic branch types declared only in the shared file get working commands before activation - Shell tab completion for both the
git-flowandgit flowinvocations, covering bash, zsh, and fish init --initcreates the repository when run outside one, with an interactive prompt offering the same when the flag is absent; the new repository's initial branch is the resolved git-flow trunk rather thaninit.defaultBranch
- Breaking:
git flow versionnow prints2.0.0 (git-flow-next)instead ofgit-flow-next version 2.0.0, so the first whitespace-separated token is a bare version number as tooling written against git-flow-avh expects. Scripts matching the old string must be updated - Release archives now contain a plain
git-flow/git-flow.exebinary instead of a version- and platform-suffixed filename, so it works as thegit flowsubcommand without renaming after extraction
- Boolean git-config values now follow git-config(1) rules:
yes,on, and non-zero integers are truthy and matching is case-insensitive. Previously only the literaltruecounted, so a setting likegit config gitflow.release.finish.push yeswas silently a no-op config editno longer resets boolean settings that were not passed, so editing one field can no longer silently clear an unrelated one such asautoUpdate- Interactive
initnow stores entered branch prefixes verbatim instead of appending a slash, so answeringfeature_producesfeature_loginrather thanfeature_/login - Hooks and filters run from a linked worktree now resolve a relative
gitflow.path.hooksorcore.hooksPathagainst that worktree and execute with it as their working directory, instead of pointing at the main checkout - Commands run outside a git repository now report a git error suggesting
git init(exit code 3) instead of a git-flow-not-initialized error steering togit flow init - Adding a base branch now rolls back its saved configuration when creating the git branch fails, leaving no orphaned config and keeping the command safe to retry
- The
configcommand group is no longer preempted by first-run shared-config activation, including its nestedadd,edit,rename, anddeletesubcommands --sharededits now warn when an untrustedgitflow.path.hooksis withheld from local config, matching whatconfig syncalready reported- Declining the "create a repository?" prompt now reports a decline instead of an internal probe failure
- git-flow-next now builds on every Go target OS; terminal detection previously had no implementation for aix, solaris, illumos, and plan9
1.2.0 - 2026-08-01
git flow integratecommand to merge changes from a parent branch into a topic branch, with options resolved from anintegrateconfig namespacefinishnow pushes the finished branches and release tag to the remote after merging, honoring push optionsupdate --continueandupdate --abortto resume or cancel an update interrupted by conflictsfinishnow detects and auto-clears stale merge state left by a previous interrupted operationdeletenow fetches and runs a remote sync-check before deleting a branch (--fetch,gitflow.<type>.delete.fetch)startcan derive the branch name from a configured version filter- Windows arm64 build target
finishnow runs a stricter pre-merge sync check: it aborts when the parent (merge-target) branch or the topic branch is behind or has diverged from its remote (with a diverged-specific message), while tolerating either being ahead;--forceskips the checkfinishnow treats a fetch failure against a reachable-but-failing remote as fatal (was a silent note); the error names the cause and suggests--no-fetch/--forcestartnow fetches by default before creating a branch (skipped silently when no remote is configured); disable with--no-fetchorgitflow.<type>.start.fetch false. Shares the unified fetch resolution (default → config → flag) withfinish- Commands now refuse to act on merge state owned by a foreign operation and on structurally-incomplete state, returning exit code 3 instead of proceeding destructively
initnow fails fast when the git user identity is missing- Branch names are validated with
git check-ref-format, and dots are now allowed in base branch names - Branch names are resolved case-insensitively while preserving their original case
- Leaf commands now reject unexpected positional arguments
delete,rename, andfinishare gated when git-flow is uninitialized- Base-branch config cleanup is scoped to local config and treats a missing key as a no-op
finish --abortis a no-op when no merge is in progress- Hooks and filters now run on Windows (executed via
sh)
1.1.0 - 2026-04-06
- Push-option support for publish command (
--push-option/-o) - Support for configurable hooks directory via
gitflow.path.hooksandcore.hooksPath
- Validate remote exists before any state-changing delete operations
- Validate remote before remote operations (publish, track, finish sync)
- Check if remote exists before attempting to delete remote branch
- Skip fetch when no remote is configured
- Use empty commit instead of README.md when initializing empty repositories
- Default to empty version tag prefix during init
- Thread config correctly into tag creation step during finish
1.0.0 - 2026-02-08
--no-verifyoption for finish command to skip git hooks during merge--merge-messageand--update-messageoptions for finish command with placeholder support- Git config support for merge message options (
gitflow.<type>.finish.mergeMessage,gitflow.<type>.finish.updateMessage) - Configuration scope flags for init command (
--local,--global,--system,--file) --forceoption for init command to allow reconfiguration- Remote sync check before finish to ensure local branch is up-to-date with remote
- Default fetch behavior changed to
truefor finish command
- Hooks now receive correct positional arguments
0.3.0 - 2026-01-14
- Add hooks and filters system for customizing git-flow operations
- Pre/post hooks for start, finish, publish, track, delete, and update actions
- Version filters for topic branches on start
- Tag message filters for topic branches that create tags on finish
- Add
publishcommand for topic branches to push branches to remote - Add
--squash-messageoption for custom squash commit messages on finish - Add config support for force deletion (
gitflow.branch.<type>.forceDelete)
- Fix worktree support for hooks, filters, and merge state
- Fix shorthand
git flow publishcommand (was returning "not implemented") - Fix
git flow <type> finishto allow optional branch name (uses current branch)
0.2.0 - 2026-01-11
- Add
trackcommand for topic branches to track existing remote branches - Add
--fetchoption for topic branch finish command
- Create base branches in dependency order during init
- Fix docs link in README.md
- Optimize binary size (~50% reduction)
0.1.1 - 2025-09-24
- Minor bug fixes and improvements
0.1.0 - 2025-09-16
- Initial release of git-flow-next
- Support for feature, release, hotfix, and support branch workflows
- Fully customizable base and topic branches with configurable prefixes and relationships
- Configurable merge strategies: merge, rebase, or squash when finishing branches
- Flexible configuration via git config or command-line flags
- Conflict recovery: resolve conflicts and continue where you left off
- Automatic updates to child branches (e.g., develop syncs from main)
- Compatibility with existing git-flow-avh repositories