Skip to content

ZelAnton/jjRun

Repository files navigation

JjRun

Typed .NET API for the jujutsu (jj) version control system. Built on ProcessKit for safe child-process lifetime guarantees and async streaming.

Status

Pre-1.0. The workflow-complete API (status, log, diff, show, new, describe, edit, abandon, restore, squash, rebase, git fetch/push/clone, op log/undo/restore, bookmark list/set/delete) is in place. See CHANGELOG.md for what's covered.

Requirements

  • .NET 10.0 or later
  • A working jj binary on PATH (or an explicit path via JjOptions.JjExecutable)
  • AOT-compatible

Installation

dotnet add package JjRun

(Available on NuGet.org once released.)

Quickstart

using JjRun;
using ProcessKit;

var jj = new Jj(ProcessRunner.Default, new JjOptions { WorkingDirectory = "/path/to/repo" });

// Describe the current change
await jj.DescribeAsync("Implement feature X");

// Create a follow-up change
await jj.NewAsync(message: "Tests for feature X");

// Stream the log as typed records (parsed from a private template — never human output)
await foreach (var entry in jj.LogAsync(revisions: "main..@", limit: 50))
    Console.WriteLine($"{entry.ChangeId} {entry.AuthorName} {entry.DescriptionFirstLine}");

// Sync with the remote
await jj.Git.FetchAsync(remote: "origin");
await jj.RebaseAsync(revision: "@-", destination: "main@origin");
await jj.Bookmark.SetAsync("main", revision: "@-");
await jj.Git.PushAsync(remote: "origin", bookmark: "main");

// Roll back if anything looked wrong
await jj.Op.UndoAsync();

To clone a repo when no local working directory exists yet, use the static factory:

var jj = await Jj.GitCloneAsync(
    ProcessRunner.Default,
    "https://github.com/owner/repo.git",
    "/path/to/clone");

Command map

jj command API Shape
jj status jj.StatusAsync Task<ProcessResult<string>>
jj log (raw) jj.LogRawAsync IAsyncEnumerable<string>
jj log (typed) jj.LogAsync IAsyncEnumerable<JjLogEntry>
jj diff jj.DiffAsync Task<ProcessResult<string>>
jj show jj.ShowAsync Task<ProcessResult<string>>
jj new jj.NewAsync Task<ProcessResult<string>> (throws on fail)
jj describe jj.DescribeAsync Task<ProcessResult<string>> (throws on fail)
jj edit jj.EditAsync Task<ProcessResult<string>> (throws on fail)
jj abandon jj.AbandonAsync Task<ProcessResult<string>> (throws on fail)
jj restore jj.RestoreAsync Task<ProcessResult<string>> (throws on fail)
jj squash jj.SquashAsync Task<ProcessResult<string>> (throws on fail)
jj rebase jj.RebaseAsync Task<ProcessResult<string>> (throws on fail)
jj git fetch jj.Git.FetchAsync Task<ProcessResult<string>> (throws on fail)
jj git push jj.Git.PushAsync Task<ProcessResult<string>> (throws on fail)
jj git clone Jj.GitCloneAsync (static) Task<Jj> (throws on fail)
jj op log (raw) jj.Op.LogRawAsync IAsyncEnumerable<string>
jj op log (typed) jj.Op.LogAsync IAsyncEnumerable<JjOperationEntry>
jj op undo jj.Op.UndoAsync Task<ProcessResult<string>> (throws on fail)
jj op restore jj.Op.RestoreAsync Task<ProcessResult<string>> (throws on fail)
jj bookmark list (raw) jj.Bookmark.ListRawAsync IAsyncEnumerable<string>
jj bookmark list (typed) jj.Bookmark.ListAsync IAsyncEnumerable<JjBookmarkEntry>
jj bookmark set jj.Bookmark.SetAsync Task<ProcessResult<string>> (throws on fail)
jj bookmark delete jj.Bookmark.DeleteAsync Task<ProcessResult<string>> (throws on fail)

Every method takes a CancellationToken and runs jj --no-pager under the hood. Typed overloads use a private unit-separator template and never parse human-readable jj output.

License

This project is licensed under the MIT License.

About

simple JJ .NET API

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors