Copilot Co-Authorship: New Standards for AI in Commit Messages
GitHub's update on 'Co-authored-by: Copilot' in commit messages signals a shift in how AI contributions are officially recognized.

The relentless march of software development demands tools that don’t just keep pace, but actively propel us forward. For decades, Git has been the de facto standard, a powerful but often inscrutable behemoth. Now, a new contender, jj (Jujutsu), is stepping onto the scene, not as a replacement for Git’s distributed magic, but as a sophisticated, developer-centric layer that promises to fundamentally alter our day-to-day version control experience. If you’ve ever wrestled with complex rebasing, found yourself lost in Git’s labyrinthine history, or simply wished for a more forgiving and intuitive way to manage your code changes, jj warrants your immediate attention. It represents a compelling vision for the future of version control, one that prioritizes developer productivity and a less error-prone workflow.
At the heart of jj’s innovation lies a radical reimagining of the working directory. In Git, your working copy is a transient state, a canvas upon which you craft changes that will eventually be committed. This separation, while familiar, can lead to a disconnect and a reliance on staging areas that often feel like an unnecessary hurdle. jj elegantly dissolves this barrier by treating the working copy itself as a commit.
This isn’t just a semantic trick; it has profound implications for how you interact with your code. Every modification you make to your files, from the smallest typo fix to a major refactor, is automatically and immediately recorded. This means you’re never truly “uncommitted.” Instead, you’re constantly iterating on the latest version, with jj diligently tracking every iteration.
The concept of “change IDs” is central to this. Unlike Git’s mutable SHA-1 commit hashes, which can change when history is rewritten (think rebasing), jj assigns stable, unique identifiers to each logical unit of work. This immutability of change IDs provides a much more robust foundation for referencing and manipulating history. Imagine telling a colleague, “Can you review change ID abcd123?” – that ID will always refer to that specific set of modifications, regardless of whether it’s been rebased, squashed, or split. This stability significantly reduces cognitive overhead and makes communication about code changes more reliable.
Consider the command jj new. In jj, this doesn’t create an empty commit in the traditional sense. Instead, it finalizes your current working copy as a new commit, and presents you with a fresh, empty working copy ready for your next set of changes. This seamless transition between “working” and “committed” is remarkably fluid. Similarly, jj edit <ident> doesn’t just check out a commit; it rewrites history, placing the specified revision at the tip of your current branch, and intelligently handles the re-application of subsequent changes.
This “working copy as a commit” philosophy also underpins jj’s approach to history editing. Operations like jj describe -m "Fix bug in user auth" allow you to modify the commit message of your current working copy or any historical revision. The power truly emerges with commands like jj squash, which can move changes from your current working copy into its parent commit, or combine multiple commits into one. Conversely, jj split allows you to break down a monolithic commit into smaller, more digestible units of work, promoting cleaner, more focused commits. This granular control over your commit history, without the fear of breaking references, empowers developers to sculpt their commit logs into coherent narratives of their progress.
One of the most frustrating aspects of traditional version control, especially Git, is how it handles merge conflicts. When a conflict arises, your workflow grinds to a halt. You’re blocked, forced to resolve the conflict before you can proceed with your work, commit, or even pull new changes. This can be a significant productivity drain, particularly in collaborative environments.
jj tackles this head-on by treating conflicts as “first-class objects.” This means you can continue working, committing, and even rebasing with unresolved conflicts. jj doesn’t see conflicts as a fatal error but as an informational state. When a conflict occurs, jj meticulously records it. You can then switch to other branches, make new commits, or continue developing on a parallel track, all while the conflicted state is preserved.
This capability is revolutionary. Imagine a scenario where you’re working on a feature, and an urgent bug fix needs to be addressed on the main branch, which also happens to conflict with your current work. In Git, you’d have to pause your feature development, resolve the conflict (potentially imperfectly to get unblocked), fix the bug, and then try to re-apply your feature work. With jj, you can simply commit your current work (even with the conflict), switch to the main branch, fix the bug, and then, when you return to your feature branch, you can address the conflict at your leisure, with all the context of your other ongoing work preserved.
The jj op log command further enhances this. It provides a detailed, chronological log of all repository operations – commits, rebases, squashes, edits, and even conflict resolutions. This detailed operation history is the backbone of jj’s powerful undo and redo capabilities. With jj undo, you can revert any repository action, stepping back through your history with confidence. jj redo allows you to re-apply those undone operations. This safety net is invaluable for experimentation and for recovering from mistakes without the fear of irreversible data loss.
This focus on making version control more forgiving and less disruptive fundamentally changes the developer experience. It encourages more frequent commits and a more iterative development process, where the fear of breaking things or getting stuck in conflict purgatory is significantly reduced.
Crucially, jj is not an island. It’s designed to work with Git, not entirely replace it. The jj git init --colocate command allows you to initialize jj within an existing Git repository. This means you can use both jj and Git side-by-side. jj uses Git as its backend storage, syncing its operations to Git branches and commits. This makes adoption remarkably smooth, as your existing Git remotes and infrastructure remain functional.
You can use jj for your day-to-day local workflow and then use standard Git commands to push and pull from remote repositories. jj bookmarks, for instance, are directly mapped to Git branches. jj bookmark create <name> creates a new bookmark that translates into a Git branch, simplifying remote collaboration.
However, this co-existence also means understanding the interplay. While jj offers a more ergonomic interface, the underlying Git concepts still exist. Teams adopting jj will need to invest in understanding how jj abstracts Git’s complexities and how to effectively communicate their work using jj’s terminology and workflows.
The jj ecosystem is rapidly growing, with a generally positive sentiment on platforms like Hacker News and Reddit. Developers praise its intuitive history editing, automatic conflict resolution, and the sheer ease with which complex Git operations like rebasing and squashing become manageable. It’s often described as a “nicer Git UI” or a more intelligent layer on top of Git.
Despite its promise, jj is still under active development (as of early 2026, it remains in the 0.x version range). This means some features are still maturing, and there can be occasional churn in commands or their behavior. Performance, while generally excellent for typical development workflows, might lag behind native Git on extremely large repositories with vast histories or massive binary assets. IDE and tooling integration, while improving, is not yet as mature or ubiquitous as Git’s. Furthermore, specific enterprise workflows heavily reliant on Git-specific GUIs or niche CI/CD integrations might face temporary hurdles. Teams with rigid requirements for using only Git CLI directly for all operations might also find the benefits of jj diminished if they cannot adopt it locally.
jj represents a significant leap forward in how we interact with version control. By fundamentally rethinking the working copy and elevating conflicts to first-class citizens, it delivers a local development workflow that is both more powerful and significantly less frustrating than traditional Git. The ability to experiment freely, rewrite history with confidence, and never be truly blocked by conflicts is a game-changer for developer productivity and well-being.
Is jj a complete replacement for Git? Not precisely. It’s more accurately a highly intelligent, developer-focused front-end that leverages Git’s robust distributed capabilities. For individual developers or teams willing to embrace a new mental model and workflow, jj offers a compelling upgrade. It streamlines common, often painful, version control tasks into intuitive commands, turning what were once sources of frustration into manageable steps.
While it’s still evolving, and its full integration with the broader developer tooling landscape is ongoing, jj’s core philosophy and implemented features offer a clear glimpse into the future of version control. It’s a future where your VCS actively helps you build and refine your code, rather than getting in your way. If you’re looking for a more ergonomic, powerful, and forgiving way to manage your codebase, exploring jj is not just an option; it’s an imperative. It’s time to unlearn some Git habits and embrace a more intelligent approach to managing your code’s journey.