There is life after Git
Background
In my professional work, Azure DevOps (ADO) ended up being the forge of choice. While ADO is reliable for standard Git workflows, it falls short when it comes to stacked Pull Requests (PRs) — a feature I personally find essential for iterative and fast-paced development. Reviews can be slow and first of all require your peers to allocate time for them. I prefer to keep momentum by building on top of submitted changes, even as feedback is pending. Managing code review changes with Git rebase quickly becomes unwieldy, especially with several PRs stacked. I also value a clean, readable and a single-branch history (squashed merges), so I avoid using plain regular Git merges to main branch to prevent clutter.
Trying to have stacked PRs with Git and ADO - well, this ends up being painful.
Jujutsu
Recently, I discovered Jujutsu, a version control system that works seamlessly with Git, but redefines how you work with it a bit. Jujutsu stands out for its instant rebasing capabilities, which make handling stacked changes and branch management far more efficient. This has transformed my workflow, allowing me to maintain clarity and order in my commit history, even as I juggle multiple branches.
This post isn’t a Jujutsu primer — if you’re new to it, I recommend Steve’s Jujutsu Tutorial for a practical introduction. Here, I’ll share how Jujutsu fits into my engineering routine and the patterns I’ve developed around it. You will need some understanding how Jujutsu works and how it’s different from Git to follow this blog.
Popular workflows
Jujutsu opens the door to workflows that are hard to achieve with plain Git. As detailed in Steve’s Jujutsu Tutorial, you’ll find “Real-world workflows” and “More advanced workflows” sections that showcase how to manage parallel development, stacked changes, and rebasing—all while keeping your history tidy. These patterns are especially useful for those that want to move quickly without sacrificing codebase clarity.
Parallel vs sequential PR branches
My approach is inspired by the “Working on all of your branches simultaneously” workflow from the Steve’s Jujutsu Tutorial, but I’ve tailored it for my own needs to the point where I think it became slightly distinct and worth sharing.
I often have several PRs in flight. Some PR-candidate branches end up being independent and could be reviewed or merged separately. In my version history they form parallel lines of work. Others are stacked, with each branch depending on the one below. This flexibility lets me adapt to the needs of each feature or fix.
For example, stacked feature branches where feature-2
sits on top of
feature-1
branch might look like this:
If you are not familiar with Jujutso log output, the version history is
displayed as an ASCII graph with the oldest changes at the bottom and the most
recent at the top. The special @
character indicates the reviesion your
current working copy “sees”; it’s what you are currently working on.
In contrast, an independent PRs can be visualized as:
Extracting what’s non-essential
When I start a feature, I (usually) branch off master
. As I keep working on,
I often spot areas that need improvement or refactoring—sometimes unrelated to
the feature itself. Instead of mixing these changes into the feature branch, I
use Jujutsu’s seamless rebasing to “bubble them down” closer to master
,
prepping them for a separate PR. This keeps my feature branches focused and
makes feature PR reviews easier for everyone.
I use several techniques to achieve this:
-
splitting changes into smaller parts (PR-related and PR-unrelated) using
jj split
, -
rebasing the isolated PR-unrelated changes on top of
master
or somewhere before the PR changes start usingjj rebase -r <revisions> --after master
or similar,
The result is a layered structure: improvements land in the first PR, followed
by the core feature changes in the next. The jj log
command gives a clear
view of this progression, making it easy to track what’s happening.
For example, let’s imagine that changes zp
and t
from the feature-2
branch turn out to be unrelated to the feature itself and are also in the area
that does not affect the feature-1
changes in any way.
I can split them out and rebase them on top of the master
like so:
jj rebase -r zp::t --after master
jj bookmark --create refactoring-first -r t
Giving me this:
The refactoring-first
bookmark now can be made to a PR, allowing for the
feature-2
branch to remain a lot more focused on the peformance improvement
changes only.
Branches for distant future
Sometimes, longer-term work-in-progress branches are unavoidable. This happens often when I’m prototyping new ideas that aren’t ready for review or integration. You know, things like:
- switching to a new library or framework,
- refactoring a large chunk of code, or
- demoing features and code changes that are still under discussion, etc.
These branches need to stay out of the main flow until they’re mature.
Jujutsu makes it easy to manage these long-time WIP (work in progress)
branches. I create an empty change as a kind of future merge point,
representing what master
will look like after all active PRs are merged. I
give this change a ----
(four dashes) description so it visually stands out
in the jj log
.
For example, imagine that my history of changes also have two long-living
experimental branches: wip-db-framework
and wip-new-ui
, in my workflow I
would maintain a structure like this:
I give this empty change ----
a special treatment:
- I never have any source files changes in it (it always remains empty)
- it always merges (is a parent of) all the active PR branches
- it’s a starting point for all the longer-living WIP branches
So all the long-term WIP branches fork off this merge point. This is where how
Jujutsu operates becomes extremely effective - it persists the structure of
history (shall I say future?) despite the changes applied to the feature
branches beneath the conventional merge point ----
.
This setup has several benefits. Jujutsu’s auto-rebasing and conflict detection quickly highlight when changes in active branches might clash with ongoing work.
It also provides a clear visual map of how all branches relate, helping me track progress and integration.
To sum up the above, the main elements of the workflow I use are:
- Isolation of general changes - when working on a feature I regularly
identify changes that can and should be applicable to
master
but are not strictly related to that feature - they form a “bottom” part of the version tree - Parallel feature development - the general chnges follow by a set of parallel (or stacked if needed) feature branches. Ideally - parallel ones as they offer greater flexibility in sending the for reviews as PR. Ideally - parallel ones as they offer greater flexibility in sending the for reviews as PRs
- Single merge point - a special empty change, merging all the active feature branches
- Long-term WIP branches - branches that are not ready for PRs yet, but are worth keeping around. They all fork of the merge point.
Here is how this can be visualized:
For most of the time, the actual change I’m typically changing (editing source code etc) is located somewhere within the established version tree structure. Not at the tips of it. For instance, within one of the feature branches I’m working on, like that:
Reading conflicts as signals
If my working copy has two or more parallel feature branches, and Jujutsu
indicates a conflict exactly at the ----
revision, it is a signal that the
feature branches (I plan to submit as PRs) would not be deliverable to the
master
in an independent order as intended. A merge conflict would appear
after one of them lands to master
and another one awaits for that. I can see
this at instant, before the Git-based ADO would be able to figure this out and
signal it to me. I’m a step ahead of the game.
If, however a conflict appears above the ----
revision, it means that
changes in the PR branches are not conflicting with each other, but the WIP
branches would be affected by what’s changed. That’s a useful signal to have
too. It measn I can safely push my feature branches for review and let the
collaborative review start taking place. In the meantime - I can sort out
fixing the conflicts in the WIP branches (which at this point still remain
private to me). I can decided if this is urgent or not, and whether I want to
do it now or later.
With Jujutsu, I always have a bird’s-eye view of all of my branches and their paths toward the main development branch.
Saving changes remotely
The final piece of my workflow is pushing changes frequently. I do not want any of the work I’ve made remain on my machine only, even if some of them are not for PRs yet.
Once branches (bookmarks in Jujutsu’s terminology) are created and have been pushed to the remote repository, I can always re-push them with a single Jujutsu command:
jj git push --tracked
Super convenient.
Conclusion
I hope this walkthrough has given you a clear sense of how Jujutsu fits into my daily workflow. For me, it’s more than just another tool—it fundamentally changes how I manage version history now; it helps keep my projects version trees clean and readable.
Previously, I tried to achieve similar results using Git alone, mostly relying
on git rebase
. That approach quickly became complicated and error-prone,
often requiring temporary branches and a fair bit of luck to avoid conflicts
during routine history maintenance. Conflicts would appear here too every now
and then, but in contract to how they are handled in Git, Jujutsu’s support
makes them non-disruptive events.
Switching to Jujutsu also shifted my perspective on the version control system can play. With Jujutsu, the version tree isn’t just a record of what’s been done, like a log of the past — it becomes a mini roadmap for the incomming changes as well. A future that at instant adopts to what is about to become the current state of the trunk. Jujutsu makes maintaining it a breeze and ensure that my work always follows a clear, well-defined path toward landing in the main development branch when the time is right.
I also like the fact that for my peers in the company, the workflow I use remains pretty much my private business. The fact I manage my working copies with Jujutsu does not affect them in any way they might not want (you know - a new fancy tool to learn etc). The PRs come in a sensible shape and order, often they can review them in any sequence they prefere (that’s because I like parallelize my PRS as much as possible). They see a clean Git history on their ends.
Recommended reading
If you’re interested in exploring modern version control workflows, I highly recommend diving into the resources below. They offer practical insights and deeper technical context for Jujutsu and its capabilities. Whether you’re looking to improve your branching strategy or simply curious about the new tool, these links are a great to read: