Stop Using git checkout
Git 2.23 introduced two commands that replace the two different jobs git checkout used to do: git switch — change or create…
Jujutsu is an experimental version control system designed to be both powerful and user-friendly. Created by Martin von Zweigbergk, it started as a hobby project in 2019 and has since evolved into a full-time project at Google. While it's not an official Google product, it's gaining traction and support from developers both inside and outside the tech giant.
Project website: https://martinvonz.github.io/jj/latest/
Repo: https://github.com/martinvonz/jj
Git Compatibility: Jujutsu can use Git repositories as a storage backend, meaning you can start using it on your existing Git projects without migrating to a new format. This interoperability is a huge plus for gradual adoption.
Working Copy as a Commit: Unlike Git's staging area, Jujutsu automatically records changes to files as commits. This "snapshot" design simplifies the mental model and eliminates the need for features like stashes.
First-Class Conflict Handling: Conflicts are treated as normal objects in Jujutsu, allowing operations to succeed even when conflicts arise. This approach enables smoother rebasing and merging workflows.
Automatic Rebasing: When you modify a commit, Jujutsu automatically rebases any descendants onto the new commit. This feature, combined with the conflict handling, makes "patch-based" workflows much more manageable.
Powerful History Rewriting: Commands like jj describe, jj split, and jj squash offer flexible ways to edit commit messages, split commits, or move changes between commits without complex rebasing operations.
Operation Logging and Undo: Jujutsu records every operation performed on the repository, making it easier to debug issues and undo mistakes.
As developers, we're always on the lookout for tools that can streamline our workflow and make complex tasks more manageable. Jujutsu seems to bring that philosophy to version control. Here are a few ways it could improve our daily work:
Simplified Branching: Jujutsu's "anonymous" branches mean you don't need to name every small feature branch. This could be a game-changer for rapid prototyping or exploring multiple implementation ideas.
Easier Conflict Resolution: The ability to commit work with unresolved conflicts could make it easier to hand off tricky merges to team members or revisit them later without blocking your current task.
Improved Collaboration: The automatic rebasing feature could reduce the friction of integrating changes from multiple team members, especially on long-running feature branches.
Better History Management: For those of us who like to keep a clean, meaningful Git history, Jujutsu's tools for rewriting and reorganizing commits look very promising.
While Jujutsu is exciting, it's important to note that it's still in active development:
git blame equivalents are not yet implemented.If you're intrigued and want to give Jujutsu a spin on your projects, here's how to get started:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo install jujutsu
jj git init --git-repo .jj commands instead of git. For example:
jj status instead of git statusjj log instead of git logjj new to create a new commit (similar to git commit)Remember, you can always fall back to Git commands if needed, as Jujutsu keeps your Git repository intact.
Let's start by creating a new Jujutsu repository:
mkdir jj-tutorial
cd jj-tutorial
jj init
This creates a new Jujutsu repository in the current directory.
In Jujutsu, you start by creating a new change:
echo "Hello, Jujutsu!" > hello.txt
jj new
The jj new command creates a new change based on the current working copy.
Let's see what Jujutsu has recorded:
jj status
You should see that hello.txt has been added.
Add a description to your change:
jj describe -m "Add hello.txt file"
This is similar to creating a commit message in Git.
Check the history of your repository:
jj log
You should see your new change with the description you just added.
Let's modify our file and update the change:
echo "Welcome to Jujutsu!" >> hello.txt
jj diff
The jj diff command shows you the changes in your working copy.
In Jujutsu, you can easily update an existing change:
jj squash
This command incorporates the new modifications into the existing change.
Now, let's create a new change on top of the previous one:
echo "Learning Jujutsu is fun!" > learning.txt
jj new
jj describe -m "Add learning.txt file"
While Jujutsu uses anonymous branches by default, you can create named branches:
jj branch create feature-branch
This creates a new branch pointing to the current change.
You can easily switch to different changes:
jj new @-
This command moves you to the parent of the current change.
Jujutsu makes it easy to modify earlier changes:
jj edit @-
echo "Updated hello from Jujutsu!" > hello.txt
jj squash
This modifies the earlier change and automatically rebases the later change on top of it.
If conflicts occur during rebasing, Jujutsu allows you to commit the conflicts and resolve them later:
jj status # Check for conflicts
# Edit conflicted files
jj squash # Resolve conflicts
When you're ready to share your work:
jj git push
This pushes your changes to the default remote (if configured).
To get changes from a remote:
jj git fetch
jj rebase -d @remote
This fetches changes and rebases your local changes on top of the remote changes.
Jujutsu introduces several novel concepts that set it apart from traditional version control systems like Git.
In Jujutsu, there's a distinction between "changes" and "commits":
Example:
$ jj log
@ 92dcef39 change1 (no description set)
| 8adbb2e1 main Add feature X
o 3ba17825 root
Here, 92dcef39 is the Change ID, while the full 40-character hash (not shown) would be the Commit ID.
In Jujutsu, your working directory is always represented as a commit:
Example:
$ echo "New content" > file.txt
$ jj status
Working copy changes:
M file.txt
Jujutsu doesn't require you to name every branch:
Example:
$ jj new
$ jj log
@ 71e9c3f1 (no description set)
| 8adbb2e1 main Add feature X
o 3ba17825 root
Here, 71e9c3f1 is on an anonymous branch.
Jujutsu maintains a log of all operations performed on the repository:
Example:
$ jj op log
@ 92f38cd1 martinvonz@google.com 2023-07-09 14:30:22.000 -07:00
| edit working copy
o 7abcd123 martinvonz@google.com 2023-07-09 14:25:10.000 -07:00
| add new file
Conflicts in Jujutsu are treated as normal objects:
Example:
$ jj merge other-branch
Merge resulted in conflicts
$ jj status
The working copy is conflicted
Conflicted files:
file.txt
$ jj commit -m "Merge with conflicts"
Jujutsu uses a powerful query language called "revsets" for selecting revisions:
Example:
$ jj log -r "author(alice) & description(fix)"
This shows commits authored by Alice that have "fix" in the description.
When you modify a commit, Jujutsu automatically rebases its descendants:
Example:
$ jj edit abc123
# Make changes
$ jj squash
Rebased 2 descendant commits
Jujutsu supports multiple workspaces within a single repository:
Example:
$ jj workspace add ../feature-x
Created workspace "feature-x"
Jujutsu is designed with a pluggable backend system, allowing it to use different storage mechanisms:
This abstraction allows Jujutsu to potentially support other backend types in the future.
The operation log is a central component in Jujutsu's architecture:
The operation log is stored as a directed acyclic graph (DAG) of operations, each pointing to a "view" of the repository state.
The Store component acts as an interface between the high-level operations and the underlying storage:
Jujutsu uses a transaction system to manage changes to the repository:
MutableRepo within a transaction.Jujutsu is split into two main components:
This separation allows for potential future development of other interfaces (e.g., GUI, TUI) using the same core library.
Jujutsu makes extensive use of immutable data structures:
Conflicts are represented as first-class citizens in the data model:
Jujutsu implements a powerful query language for selecting revisions:
MutableRepo.MutableRepo within the transaction.Jujutsu is designed to operate without locks, enabling safe concurrent operations:
The architecture is designed to be extensible:
While introducing novel concepts, Jujutsu maintains compatibility with Git:
Git:
git add to stage changes.git commit creates a new commit with staged changes.Jujutsu:
jj new creates a new change (similar to a commit).jj describe adds or updates the description of a change.Git:
git log shows commit history.Jujutsu:
jj log shows change history.Git:
git branch and git checkout for branch operations.Jujutsu:
jj branch for branch operations, jj new to switch contexts.Git:
Jujutsu:
Git:
Jujutsu:
Git:
git rebase -i) for complex history rewriting.git commit --amend for simple modifications.Jujutsu:
jj edit, jj squash, jj unsquash for flexible history rewriting.Git:
git reflog.Jujutsu:
jj op log to view operation history.jj undo and jj op undo for powerful undo capabilities.Git:
Jujutsu:
jj git push and jj git fetch for synchronization.Git:
Jujutsu:
Git:
Jujutsu:
Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.
Take a look at vroni.com
Looks really cool. I would consider using it if it wasn’t a Google project.