Jujutsu (jj) Version Control System

repository·main·Indexed 12 days ago

https://github.com/jj-vcs/jj

An experimental, next-generation version control system compatible with Git. Jujutsu introduces modern abstractions including a working-copy-as-a-commit model, first-class conflicts, automatic rebasing of descendants, and an operation log for easy undoing of actions.

Tokens
142.3K
Snippets
437
Records
635
Agent score
94%

What's inside Jujutsu

  1. What is Jujutsu (jj)?

    main

    Jujutsu is a version control system (VCS) designed to be easy to use for both new and experienced developers. It abstracts the user interface and version control algorithms from the underlying storage systems.

    Key characteristics include:

    • Git Compatibility: It uses Git repositories as a default storage layer, making it compatible with existing Git-based tools. Note that while commits and files are stored in Git, higher-level metadata like bookmarks (branches) are stored in custom storage outside of Git.
    • Inspiration from other VCS: It incorporates features from Git (speed/efficiency), Mercurial/Sapling (revset language, no explicit staging area, anonymous branches), and Darcs (conflicts as first-class objects).
    • Innovative Features:
      • Working-copy-as-a-commit: Changes are automatically recorded as commits and amended on every subsequent change, eliminating the need for a staging area or stashes.
      • Operation log & undo: Every operation (commits, pulls, pushes) is recorded, allowing you to undo mistakes easily.
      • Automatic rebase and conflict resolution: Descendants are automatically rebased when a parent is modified, and conflict resolutions propagate through descendants.
  2. Explore community-built tools for Jujutsu

    main

    Jujutsu has a growing ecosystem of community-maintained tools that extend its functionality across different interfaces (GUI, TUI, IDE plugins, and CLI wrappers).

    Note: These tools are community-maintained; the Jujutsu project does not review, endorse, or guarantee their quality or security.

  3. Explore community-built tools for Jujutsu

    main

    Jujutsu has a growing ecosystem of community-maintained tools, including GUIs, TUIs, IDE plugins, and CLI utilities.

    Warning: These tools are community-maintained; the Jujutsu project does not review, endorse, or guarantee their quality or security.

    GUI Tools

    • GG: A cross-platform GUI designed for easy graph manipulation.
    • JayJay: A native macOS GUI built with Rust and SwiftUI. Features include a DAG graph view, Myers diff with syntax highlighting, side-by-side diffs, conflict resolution, bookmark manager, command palette, and AI commit messages. It also provides the jj-diff Rust crate as a standalone engine.
    • LightJJ: A fast, keyboard-driven browser UI.

    TUI (Terminal User Interface) Tools

    • LazyJJ: A TUI inspired by lazygit.
    • JJ TUI: An unopinionated TUI built in OCaml.
    • JJ UI (jjui): A terminal user interface for working with Jujutsu.
    • JJ-FZF: A tool centered around the jj log graph view. It provides diff previews, evolution-log browsing, op-log browsing, and numerous key bindings for operations like rebase, undo, and handling divergent commits.
    • VisualVJJ (vjj): An interactive terminal fzf wrapper for Jujutsu.

    IDE Plugins

    • Visual Studio Code:
      • Jujutsu Kaizen: Aims to bring Jujutsu UX to the VS Code UI, focusing on parity with the built-in Git extension (e.g., Source Control view operations).
      • VisualJJ: Provides native integration for Jujutsu (not relying on Git colocation). Note: This tool is not open-source.
      • JJ View: An open-source extension providing a Git-style SCM view, interactive visual commit history graph, and built-in commands for squashing, abandoning, and absorbing modifications. Includes native Gerrit integration.
    • JetBrains (IntelliJ IDEA, etc.):
      • Selvejj: Integrates Jujutsu as a first-class VCS within JetBrains IDEs.
      • Jujutsu plugin for IntelliJ IDEA: Native IntelliJ integration.

    CLI & Editor Utilities

    • Diffedit3: A web-based alternative to Meld for diffing.
    • Hunk.nvim: A Neovim-based diff-editor used as an alternative to the default :builtin diff-editor.
    • jj-hunk: A CLI tool for programmatic hunk selection. It allows splitting, committing, and squashing selected hunks without an interactive editor, making it suitable for scripts and AI agents.
    • PSCompletions: A PowerShell completion manager that can provide completions via psc add jj or improve the official completion menu.
  4. Handle conflict markers and exit codes in merge tools

    main

    jj determines the state of a conflict based on the merge tool's exit code and the presence of conflict markers in the $output file.

    Exit Code Behavior

    • Exit code 0: jj assumes the conflict is fully resolved.
    • Non-zero exit code: jj assumes the merge should be canceled.

    If you use a tool that returns a non-zero exit code (e.g., 1) to indicate that some conflicts remain (rather than a total failure), you must tell jj to expect conflict markers in the output by using the merge-tools.TOOL.merge-conflict-exit-codes option.

    Working with Conflict Markers

    For tools that do not resolve conflicts themselves (like vimdiff), you can enable merge-tools.TOOL.merge-tool-edits-conflict-markers = true.

    When this is enabled:

    1. jj populates the output file with conflict markers before starting the tool.
    2. If conflict markers remain in the output file after the tool exits, jj treats the conflict as only partially resolved and parses the markers to update the state.
    3. The conflict is only considered fully resolved when no markers remain.

    You can also customize the marker style per tool using merge-tools.TOOL.conflict-marker-style (matching the values available in ui.conflict-marker-style).

    [merge-tools.mytool]
    # Tell jj that an exit code of 1 means 'partial success with markers'
    merge-conflict-exit-codes = [1]
    
    [merge-tools.vimdiff]
    # Populate output with markers before starting vimdiff
    merge-tool-edits-conflict-markers = true
  5. How Sparse Patterns v2 rule ordering works

    main

    Sparse Patterns v2 uses an ordered list of rules. When determining if a file is included or excluded, jj evaluates the rules in reverse order (from bottom to top), and the first matching rule wins.

    Example rule set:

    include:dir:foo
    exclude:dir:foo/bar
    include:dir:foo/bar/baz
    exclude:dir:foo/bar/baz/qux

    Resulting behavior:

    • foo/file.txt: Included (matches include:dir:foo)
    • foo/bar/file.txt: Excluded (matches exclude:dir:foo/bar)
    • foo/bar/baz/file.txt: Included (matches include:dir:foo/bar/baz)
    • foo/bar/baz/qux/file.txt: Excluded (matches exclude:dir:foo/bar/baz/qux)
  6. Understand the Non-distributivity of the `..` Operator

    main

    The .. operator (ancestor exclusion) does not distribute over the union (|) operator on its left side.

    Specifically, (A | B).. is equivalent to A.. & B... It means "commits that are not ancestors of A and not ancestors of B". This is different from A.. | B.., which means "commits that are not ancestors of A or not ancestors of B".

    Example Logic: If you have commits C and B that both have parent A:

    • (C|B).. results in commits that are neither ancestors of C nor ancestors of B.
    • C.. | B.. results in a union of the two sets.
    Given this history:
        D
        |\
        B C
        |/
        A
        |
        root()
    
    (C|B).. ⇒ {D}
    
    Note that:
    C.. ⇒ {D,B}
    B.. ⇒ {D,C}
    C.. | B.. ⇒ {D,C,B}
    (C|B).. = C.. & B..
  7. Understand the security risks of repository configuration

    main

    Jujutsu (jj) allows configuration to be stored within a repository (repo config) or a workspace. An attacker can exploit this by including malicious commands in the .jj/repo/config.toml file of a repository they distribute (e.g., via a zip file).

    If a user unzips such a repository and runs a command that triggers the malicious configuration—such as jj fix if a tool is configured to run a specific command—the attacker can gain full control over the user's system.

    Example of a malicious configuration:

    [fix.tools.foo]
    command = ["malicious", "command"]

    Users should be cautious when unzipping and running jj commands in repositories received from untrusted sources, as the repository's own configuration can dictate what commands are executed on your machine.

  8. The Same-change Rule for automatic conflict resolution

    main

    Jujutsu implements a "same-change rule" to improve user experience: if all sides of a conflict propose the exact same change, Jujutsu automatically considers the conflict resolved to that value.

    While this behavior matches Git and Mercurial, it is technically "lossy" in terms of conflict algebra. In specific edge cases (such as rebasing a commit onto a commit with the same changes and then rebasing back), this can lead to lost changes. However, this is preferred for general usability.

  9. Combine string patterns with logical operators

    main

    You can combine string patterns and other revset expressions using logical operators:

    • ~x: Matches everything except x (NOT).
    • x & y: Matches both x and y (AND).
    • x ~ y: Matches x but not y (EXCEPT).
    • x | y: Matches either x or y (OR).

    Example: bookmarks(~glob:"ci/*") matches all bookmarks except those starting with ci/.

    ~x
    x & y
    x ~ y
    x | y
  10. What are bookmarks in Jujutsu?

    main

    Bookmarks are named pointers to revisions, conceptually similar to Git branches. They allow you to reference a specific point in history without affecting the identity of the target revision.

    Key behaviors:

    • Automatic Movement: Bookmarks automatically move when revisions are rewritten (e.g., via jj rebase).
    • Revision Arguments: You can pass a bookmark name to commands expecting a revision. For example, jj new main creates a new revision on top of the main bookmark.
    • No Checkout Concept: Unlike Git, there is no concept of an 'active' or 'checked-out' bookmark in Jujutsu.
    • Git Mapping: When using a Git backend, Jujutsu maps bookmarks to Git branches. jj git push --bookmark foo pushes the foo bookmark to the foo branch on the remote.
    jj new main
  11. How the `docs-build-deploy` script works

    main

    The .github/scripts/docs-build-deploy script is a wrapper around uv run mike deploy. It sets up necessary environment variables and passes arguments to mike.

    If you need more control, you can run uv run mike ... commands directly. If you are serving the site from a custom URL (not https://docs.jj-vcs.dev/), you may need to adjust the site_url in mkdocs.yml to ensure the version switcher works correctly.