(NOTE: Before starting this article, you may want to review part one and part two of the Butler Flow series.)
A deeper dive: integration, conflicts, and example patterns
Let’s explore some patterns you might adopt with Butler Flow, especially around integrating branches, resolving conflicts, and structuring your work.
Pattern: feature + fix workstreams
Suppose you have two kinds of work going on: features and fixes/iterations. With virtual branches, you can maintain a “fix branch” (virtual branch) that gets small urgent patches, and a “feature branch” for a bigger feature. Locally, you can apply the fix branch on top of your feature branch and test. If the fix branch is merged, it is disposed; your feature work continues with that fix baked in.
Thus, virtual branching gives you flexible layering of workstreams.
Pattern: experimental features/toggles
You might start an experimental virtual branch but not merge it just yet. Meanwhile, you continue with mainline work. Because branches can be applied and un-applied, you can test what happens when your experimental work is layered on top of your primary branch. If it fails, you roll it back; if good, you eventually merge. The ability to layer/unlayer gives you safety.
Conflict resolution - early, collaborative
Because applying another branch triggers conflicts early, you get a safety net: you and your teammate can talk through conflicts before the PR stage. Instead of surprise late-stage merge conflicts, you can resolve dependencies and coordinate earlier.
For non-trivial conflicts, the branches can be un-applied, re-applied, or isolated until ready. The idea is to localize conflict resolution and avoid polluting master.
Dependency branching & ordering
If branch B depends on branch A, you can apply A first, then apply B on top. Because branches are isolated, you maintain clarity about what’s layered. If you have multiple branches that depend on each other, the ordering matters — but Butler Flow supports composition. This gives you more flexibility than a flat linear branch model.
Example scenario: a day in the life with Butler Flow
Here’s a fictional (but realistic) day using Butler Flow in a team of developers working on a product backend + frontend.
-
Morning Stand-up Alice picks up a story to implement a search feature. Bob has started a fix for a production bug. Carol is working on an API refactor. The main branch is stable and up to date.
-
Alice begins work Alice edits files; GitButler creates virtual/AliceSearch. She codes away.
-
Bob's bug fix Bob starts virtual/BugFix123. He pushes it, triggers a PR, review is underway.
-
Alice wants to integrate Bob’s fix Without switching branches, Alice applies Bob’s branch to her working directory. She sees a minor conflict in shared modules, resolves it, and continues. Now Alice’s working directory includes her search changes + Bob’s bug fix. She tests the combined behavior.
-
Carol's refactor Carol’s branch virtual/RefactorAPI is pushing large changes. Alice optionally applies that too, but maybe defers until later.
-
Alice asks for a review Alice pushes virtual/AliceSearch, opens a PR against main. Bob reviews. Meanwhile, she might pull in Carol’s changes for testing before final merge.
-
Bob’s bug fix merges Bob’s branch is approved and merged into main. GitButler sees that virtual/BugFix123 is integrated, so it disposes it from Alice’s local context — the applied changes remain, but the virtual branch itself disappears. Alice doesn’t need to manually prune it.
-
Alice finishes and merges After review, Alice’s changes merge into main. GitButler auto-cleans virtual/AliceSearch. Her workspace is clean. She starts the next change; a new virtual branch is auto-created.
Through this flow, Alice never had to switch contexts awkwardly, Bob’s fix was layered and tested early, conflicts were resolved early, and cleanup happened automatically.
Common objections, FAQs, and counterpoints
Below are some concerns you may hear or have, and responses to them.
“But isn’t this just layering patch sets or rebasing?”
Virtual branching abstracts over patch sets and rebasing, but gives you additional composability: you can stack unmerged branches, test combinations, and dispose of them automatically. It’s more flexible and safer than juggling rebases or hand-crafted patch order.
“What about CI and merging definitions?”
You still need a CI pipeline. PRs from virtual branches should run your tests and checks. The target branch merge process (squash, rebase, or merge) still matters. Butler Flow doesn’t eliminate merging discipline; it complements it.
“Doesn’t this hide complexity behind a tool?”
True. You need to trust and understand what GitButler is doing. But the abstraction is fairly thin - virtual branches map to changesets, applications are merges / rebases under the hood, and cleanup is deterministic. With monitoring and good tooling, you can mitigate “magic” surprises.
“Does it work with code reviews, GitHub, GitLab, etc.?”
Yes, insofar as branches pushed upstream can be reviewed in standard PR flows. Virtual branches are a local abstraction; the remote ends up as normal Git branches (or commits) for review and merging.
“What about large refactors and architectural changes?”
You can still do big work. But you’ll want to break them into smaller chunks as much as possible to preserve the integrability advantages. Use virtual branches to layer parts progressively, test in stages, and merge incrementally
Tips for adopting Butler Flow in your team
If you like the sound of Butler Flow, here are some steps to ease adoption:
-
Start with a pilot team Pick one team or a feature where the benefits of early merging and integration are pressing. Let them try Butler Flow first.
-
Train developers on virtual branch thinking Use workshops, pair programming, and example scenarios to help people internalize the idea of applying branches vs switching branches.
-
Integrate with your existing CI pipeline Make sure your CI tests work well when virtual branches are applied; ensure merge hooks, linting, code scanning, etc., are compatible.
-
Define merge/branching policies up front Without switching branches, Alice applies Bob’s branch to her working directory. She sees a minor conflict in shared modules, resolves it, and continues. Now Alice’s working directory includes her search changes + Bob’s bug fix. She tests the combined behavior.
-
Monitor and measure Track metrics - time from code commit to deployment, number of merge conflicts, branch lifetime, developer satisfaction. See if Butler Flow gives you measurable improvement.
-
Iterate and refine As with everything in building codebases, as you use it you may discover anti-patterns (e.g. too many branches stacked, complex dependency graphs). Adjust policies to keep branches focused, short-lived, integrable.
-
Encourage collaboration early Because integration is cheap, encourage developers to apply each other’s branches early. Use pair programming or “merge previews” as a habit.
Conclusion
Butler Flow is not a magic wand. It won’t solve every development pain. But for modern teams hungry to ship fast, reduce merge friction, and keep developer experience pleasant, it offers a compelling hybrid model of branching.
By combining the simplicity of GitHub Flow with richer branch composability via virtual branches, Butler Flow enables:
- Early integration and conflict visibility
- Minimal context switching
- Automatic cleanup
- Safer, more confident merges
If your team frequently runs into merge conflicts, or struggles with branch management overhead, or simply wants to accelerate its shipping cadence, Butler Flow is worth considering. Check out our documentation and reach out to the team on discord for more tips and tricks!

Written by PJ Hagerty
PJ Hagerty is a well-known figure in the tech industry, particularly within the developer relations and DevOps communities. He's also Head of Developer and Community Relations at GitButler.



