GitButler Logo
FeaturesVirtual Branches

Overview

Work on several branches at the same time, committing and stashing them independently and simultaneously.

The main feature of GitButler currently is our virtual branch functionality. Here is a quick video showing off some of what you can do when being able to work on multiple branches at the same time.

Virtual branches are just like normal Git branches, except that you can work on several of them at the same time.

Virtual Branches Example
An example of working on two branches at the same time, while pending upstream changes wait for you to merge them.

An example of working on two branches at the same time, while pending upstream changes wait for you to merge them.

You cannot use both GitButler virtual branches and normal Git branching commands at the same time, you will have to "commit" to one approach or the other.

The reason is that stock Git can only handle one branch at a time, it does not have tooling to use or understand multiple, so most commands having to do with the index or HEAD or branching (commit, branch, checkout, etc) may behave unexpectedly.

To understand why and how to get out of this, please read our integration branch docs.

Target Branch

With virtual branches, you are not working off of local main or master branches. Everything that you do is on a virtual branch, automatically.

Similar to GitHub, where you specify a default branch to use to merge your Pull Requests into by default, GitButler requires a "Target Branch". This is understood to be whatever your concept of "production" is. Typically what represents deployed, production code that cannot or should not be rolled back. Generally this would be something like origin/master or origin/main.

Once a target branch is specified, everything in your working directory that differs from it is branched code and must belong to a virtual branch.

This means that you don't have to create a new branch when you want to start working, you simply start working and then change the branch name later. There is no local "main" or "master" because it doesn't make sense. Everything is a branch, with work that is meant to eventually be integrated into your target branch.

Virtual Branches

You can easily work in a single branch at a time, but GitButler can handle several virtual branches at the same time. If you have 3 different changes in one file, you can drag each of the changes to a different virtual branch lane and commit and push them independently.

Each virtual branch is kept in a vertical lane, similar to a kanban board, and every file and difference is similar to a card that you can drag between the lanes until they are committed there.

Each time you commit on a virtual branch, GitButler calculates what that branch would have looked like if the changes you dragged onto it were the only things in your working directory and commits a file tree that looks like that. If you push that commit and inspect it on GitHub (or whatever upstream service you use to collaborate), it should look like that was the only change you made, even though you could potentially still have multiple branches applied in your working directory.

Applying and Unapplying Branches

Since there isn't just a single branch you can be on, you don't "switch" branches, which implies replacement. You simply "apply" branches, which takes whatever changes they represent and adds them to your working directory. If you don't want those changes in your working directory anymore, you can "unapply" them, which removes only those changes.

Virtual Branch Apply / Unapply
Click 'unapply' for any branch to stash it and remove it's changes from the working directory

To delete a virtual branch, you simply unapply it, then left click on it and choose "delete".

Merging Upstream

Eventually you will have work merged into the branch you chose as your target branch, which will need to be reconciled with all your virtual branches to keep them up to date with where they will eventually need to merge to.

Branch Commit List
Click 'Merge into common base' to integrate upstream changes into your virtual branches.

Upstream work will automatically be shown in your sidebar in the "Target" section. When you click "Merge into common base" (or the "Update" button next to your "Workspace" section), we will attempt to integrate that work with your existing virtual branches. Each branch, applied or unapplied, will try to be updated with the new work.

Update Workspace
Click 'Update workspace' to integrate upstream changes into your virtual branches.

For each virtual branch you have, we will show you if the incoming upstream work has conflicts with each branch. If there are conflicts, you can choose to stash the branch or go ahead and rebase with conflicts, which you can fix later.

If a virtual branch is entirely integrated into upstream, it will be removed and deleted when those changes are integrated. So you can just keep a virtual branch applied locally until it is integrated and it will go away automatically.

Conflicting Branches

If you do rebase work that has conflicts, the commit will be marked as being in a conflicted state and you can check it out and fix it whenever you wish.

Conflicts with commits
When your commits have conflicts

This is different from how you might have dealt with conflicts in Git before. If there is conflicting work in a commit, GitButler will ignore the parts that conflict and keep rebasing. In other words, rebases always work. Then you can focus resolving each conflicted commit, one at a time.

Conflicts with commits
Resolving a conflict

This will check out the conflicts into your working directory and you can let us know when you're done resolving it and we'll rebase everything above it.

The End

That is our general overview of how Virtual Branches works. We've found that it's way easier and faster than constantly switching back and forth between branches, managing branches all the time, and all the other overhead that comes with branching in Git, while still being able to easily create pull requests and integrate features.

Last updated on

On this page

Edit on GitHubGive us feedback