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.

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:

Stacked PRs version history

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:

Parallel PRs version history

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 using jj 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:

Parallel PRs version history

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:

Parallel PRs version history

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:

  1. 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
  2. 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
  3. Single merge point - a special empty change, merging all the active feature branches
  4. 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:

Parallel PRs version history

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:

Parallel PRs version history

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.

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: