GitButler has come up with an entirely new way to work on multiple branches: simultaneously.

What are virtual branches and how did we come up with them? Here's some behind the scenes gossip about a cool new idea coming soon to the land of Git workflows.

But first, watch the demo:

My alpha product demo for virtual branches. It's an actual background, even though it looks like a green screen.

We're closing in on releasing an alpha build of our new GitButler client with virtual branch functionality. Here's a little behind the scenes of how a startup builds a cool new idea.

What are Virtual Branches

First of all, what are virtual branches? Also, why did we name them like this?

Virtual branches are similar to Git branches, except that you can be on several at the same time. So instead of having to determine if you are on a bug fix branch or your feature branch or a coworkers feature branch that you're reviewing, you can actually apply all of them as though they were merged but not have to commit a merge into your history or unroll a test merge.

So why "virtual branches"? Well, we wanted to come up with a name that implies that the branches are lighter weight than Git branches in that you can move between the work on them much easier. We thought of all the following names as well:

  • Stacked branches
  • Union branches
  • Smart branches
  • Integrated branches
  • VIP (virtually integrated proxy) branches

We nearly went with "smart branches" but "virtual" won out in the end. Maybe another blog post on this ridiculous decision making process at a later date.

How did you come up with a new branching model?

GitButler is building a next generation version control system that sits within the Git and GitHub world. This means that it's meant to be compatible with Git data transfer protocols, but it can keep data and structures that are not stored in the Git database.

Our first builds were around watching changes to your filesystem and recording every file change so you didn't have to do 'WIP' commits. Once that was working well, we started looking at Git commands we wanted to come up with better tools for. One of the first was branches, since that's what most people use every day.

My first shot at a branches interface was rather similar to how GitHub displays your branches. It had ahead/behind information, authors, last commit date, etc. It was conceived to be a better git branch, but not much more.

Our first working branching screen

In my mind, it was innovative. This isn't how git branch shows you data, but it's more or less the same data that most Git clients have around branching. In my mind, I cared about different information of my branches than most Git clients give you. I hate log graphs, because I've never answered a valuable question with them. I care about ahead/behind data from a target branch, or other branch comparisons.

When Matthias started, he challenged us about this model. What is really innovative about it? Is this really solving the problems that modern developers have in a compelling way? Is it really saving people time or friction?

They are great questions.

Rethinking the problem

This helped us think backwards, rewind what we thought we knew about branching and version control. What do developers really want to do? Branching in Git is great, way better than previous tools, but what biases are clouding our judgement here, what assumptions are we not recognizing as poorly grounded?

What struck me is how often developers stash, pull and pop. How often we commit bug fixes into feature branches because it's a pain to separate them. How much time we actually spend managing our branches so that we can use them.

So I thought, "what if you could be on several branches at the same time"?

It's an interesting question. What actually stops us from doing this?

From a technical Git perspective, it's mostly that we only have one index file. There is only one staging area that can be committed into the next commit on a branch. But what if each entry in that index could be earmarked for a different branch? What if you could commit only the earmarked work that was staged for some of the entries?

To take it a step further, what if each hunk of your changes can be earmarked for a different branch?

So I put together an internal demo. I wrote a proof of concept using the Rugged library in Ruby over the course of a long weekend and presented the concept internally. Here is my internal demo pitch:

Building the feature

Once we had something concrete to talk about and think about, we all decided this would be worthwhile to build out. So for the last few weeks, we've been working hard on figuring out how to build this.

Kiril pitching a Kanban style layout for our virtual branches

First we sketched. We often use Excalidraw for rough concepts, then whiteboard things out to discuss the concepts in more detail, and then once we've figured out the rough direction, our design-master Ian comes up with tons of options for us to discuss in Figma.

We decided that a kanban style board for our branch lanes would make the most sense for splitting out work in progress into multiple virtual branches.

One of my early Excalidraw concepts, for us all to ponder.
The team discussing the different approaches, in fast forward.
A million dreams, by Ian.

Once we had some good ideas about how we wanted this all to work, we got to the coding part.

We started with basic drag and drop issues, trying to see if we could get the UI to work the way we wanted with our Svelte frontend (we're using Tauri for our app). We started with some dummy data that was pulled from our project's pull requests and then implemented a backend that could provide that data structure.

Kiril and Matthias's dragging and dropping working, but no real data yet. Also, light mode.

Once Nikita and I got the data actually reading and writing properly, with all the fun Git (libgit2 via the Rust git2 library) stuff working, we finally had something that is pretty close to useable.

Our internal demo once Nikita and I got the branch application and stashing functionality working.

From my initial internal demo trying to sell the team on the concept on May 23rd, to the functioning external demo that I shot on the 4th of July, our team has been working on this for only about 45 days and we've really excited about how cool it is and how quickly we were able to get it working.

Next Steps

While we're very close to having something to get into people's hands, there are still some relatively common edge cases that we need to work out first. We're hoping to get this to our alpha testers in the next few weeks. Go ahead and sign up for our waiting list if you're interested in being an alpha tester.

We hope you've enjoyed this short journey through the making of a feature. Let us know if you want to know anything else about our startup life. :)