Git is a (in)famously polarizing tool, and there are as many distinct Git workflows as there are developers that use Git. However, since Git has the most mindshare of any extant VCS tool, it’s worth finding ways to make it more comfortable to use.
One Git usage pattern that I think is underused is the “branchless” workflow. The idea here is pretty intuitive if you’ve used trunk-based development: there’s just one “main” branch that everything gets merged into. No feature branches, no release branches, no hotfix branches.
The “branchless” workflow is, in a nutshell: You work in a stack of atomic commits which are all eventually intended to be merged into a single trunk branch. Each commit can become a pull request, and each pull request consists of a single commit.
When you’re working on a commit, incremental changes are amended into the commit, instead of being added as a new commit. Commits can be “stacked” in your local copy, and you jump between them to make changes. Commits can also be reordered or moved to change the dependency relationship between commits.
I’ve been using a “branchless” workflow in a Mercurial environment for a few years, and wasn’t aware until recently that it was possible to do the same thing in Git. My favorite tool so far that implements “branchless git” is, fittingly, git-branchless. Since a picture speaks a thousand words, here’s a screencast of git-branchless in action:
In my opinion, the key features of git-branchless are:
- Navigation commands for moving between commits (e.g.
- The ability to view the local graph of commits (
- The ability to automatically rebase commits following an amend (
What are the benefits of the branchless workflow?
- It makes it feasible to use a stacked diff workflow on top of Git.
- It’s more manageable to maintain a set of dependent commits, swap between them, and have “child” commits automatically get updated with the changes of their parents.
- Commits can be more easily reordered. e.g. You can move a commit within your local tree of commits, and all its children will move with it.
What are the downsides of the branchless workflow?
- It’s amend-heavy, which git doesn’t handle very well by default. Under the hood, amending a commit in Git actually creates a new commit with updated contents, which means you lose the history of the old commit unless you have an external system that can track it.
- You’re swimming upstream (no pun intended) against common git patterns. Github doesn’t support this workflow well, for example, since you need to have a branch to open a pull request.
- The ecosystem is still pretty new. The tools aren’t rock-solid yet, and it’s too soon to know if they’ll have staying power.
I would not recommend using git “branchlessly” unless you have an external helper tool – the built-in commit, amend, and rebase commands just aren’t suited to it. However, there is a growing ecosystem of commands that support this workflow. Aside from git-branchless, there’s:
- epage/git-stack: Stacked branch management for Git
- Stacked Git
- ezyang/ghstack: Submit stacked diffs to GitHub on the command line
- And more…
I ended up sticking with git-branchless, since it works quite well with Gerrit (the Git review tool that I use at work). I’ve made a few contributions to git-branchless, so at this point I’m biased (😄), but it’s one of the better new tools that I’ve picked up recently. Highly recommended!