Jujutsu pour les développeurs pressés
(maddie.wtf)- Jujutsu (jj) est un système de gestion de versions qui offre des concepts et des commandes plus simples que Git, tout en fournissant des fonctionnalités puissantes
- Comme il utilise Git comme backend, il a l’avantage de pouvoir être utilisé en parallèle ou de permettre un retour facile à Git
- Des fonctionnalités comme les diffs empilés, le rebase facile et les révisions temporaires sont fournies naturellement
- Il s’appuie sur le concept de signets (bookmarks) plutôt que de branches, ce qui est plus intuitif pour les flux de travail en conditions réelles
- Sa gestion des conflits est souple et rend les tâches quotidiennes de gestion de versions beaucoup plus simples
Elevator Pitch
Jujutsu (jj) est un système de gestion de versions qui propose un modèle mental et une interface en ligne de commande bien plus simples que Git.
Sans sacrifier les fonctionnalités, on peut même le considérer comme plus puissant
Des fonctions comme les diffs empilés, le rebase simplifié et les révisions temporaires fonctionnent naturellement
Comme il utilise Git comme backend, vous pouvez commencer à l’utiliser à côté d’un dépôt Git en une seule ligne, et revenir à Git à tout moment
Cela n’affecte pas non plus la manière dont les autres utilisateurs manipulent le dépôt
Getting Started
- Après avoir installé l’outil en ligne de commande
jj, il est recommandé de configurer les informations utilisateur et l’autocomplétion du shell - Pour l’appliquer à un dépôt existant, il est préférable de repartir d’un nouveau clone ou de commencer dans un état sans modifications
- Dans un dépôt existant, la commande
jj git init --colocate .permet de créer en parallèle un dépôt Git et un dépôt Jujutsu - Les données du dépôt
jjsont stockées dans un dossier.jj/distinct du.gitde Git - La synchronisation des données entre Git et Jujutsu fonctionne globalement sans problème par défaut
- Attention toutefois : la commande
git clean -fdxsupprime le dossier.jj/ - Le suivi des branches distantes peut aussi être configuré d’un seul coup avec cette commande
How To Use It
L’interface en ligne de commande de Jujutsu est plus resserrée et concise que celle de Git
Les concepts de base sont simples, mais le flux de travail demande un petit temps d’adaptation
Les principales façons de l’utiliser sont expliquées à l’aide de procédures et d’exemples simples
Starting A New Revision
- Dans Git, un nouveau travail commence généralement par la création d’une branche, mais dans Jujutsu, on crée une nouvelle révision
- Refléter le dernier état du dépôt distant :
jj git fetch - Vérifier l’historique du dépôt :
jj log - Les révisions dans l’historique sont distinguées à la fois par un ID de révision propre à Jujutsu et par le hash de commit Git
- Pour démarrer un nouveau travail,
jj new maincrée une nouvelle révision au-dessus de la branche main actuelle - La révision en cours d’édition est désignée par le symbole
@ - Si un préfixe commun disparaît, le préfixe court de l’ID de révision change lui aussi en conséquence
Making Changes
- Quand vous modifiez un fichier, il est immédiatement inclus dans la révision correspondante (il n’y a pas de staging area séparée)
- Une fois les modifications terminées, ajoutez un message à la révision avec
jj describe -m "message" - Pour créer une nouvelle révision, utilisez
jj new(ou indiquez une révision précédente) jj commitest une opération combinantjj describe+jj new
Navigating
- Une révision vide créée avec
jj newest automatiquement abandonnée lors d’un déplacement - Pour supprimer explicitement une révision :
jj abandon <rev ID> - Pour annuler une suppression :
jj op undo - Pour revenir à une révision existante :
jj edit <rev ID> - Lors de la référence à une révision, vous pouvez aussi utiliser des expressions revset :
@: révision actuellex-: révision parentey+: révision enfantz::: tous les descendants de z
Branches (Bookmarks)
- Dans Jujutsu, il n’existe pas d’état où l’on “reste sur une branche” comme dans Git
- À la place, les signets (bookmarks) sont simplement des pointeurs vers une révision donnée
- Créer un nouveau signet :
jj bookmark create <nom> -r <révision> - Les signets ne se déplacent pas automatiquement lors d’un commit ; si nécessaire, il faut les déplacer séparément avec
jj bookmark move <nom> --to <révision> - Lors d’un push, le flag
--allow-newpermet d’autoriser la création d’une nouvelle branche distante - Si un signet diffère de l’état distant, il est marqué par
*et peut être synchronisé avecjj git push
Conflicts
- La gestion des conflits de Jujutsu est plus souple que celle de Git
- En cas de conflit, un marqueur
conflictedapparaît sur la révision concernée ainsi que sur ses révisions descendantes - Des marqueurs de conflit sont insérés dans les fichiers concernés, et il suffit de les supprimer pour résoudre le conflit
- Vous pouvez aussi corriger directement ou faire les modifications dans une nouvelle révision, puis fusionner avec
jj squash
Conclusion
Voilà comment effectuer plus simplement avec Jujutsu les 80 % d’opérations les plus courantes réalisées avec Git
Les usages plus généraux ou avancés seront proposés plus tard sous la forme d’un manuel de référence (Quick Reference)
Comme Git, la commande jj status est prise en charge
Pour toute question ou retour, l’adresse e-mail indiquée dans le corps de l’article peut être utilisée
1 commentaires
Avis Hacker News
Pour celles et ceux qui se demandent si ça vaut le coup d’apprendre jj, il y a un point sur lequel j’aimerais insister
Quand on parle de jj sur Hacker News, les gens se divisent en deux groupes : ceux qui ne l’ont pas encore essayé et ceux qui le recommandent très vivement
On voit très rarement quelqu’un utiliser jj pendant une semaine puis revenir à git
Presque tous ceux qui l’ont essayé sérieusement ont fini par l’adopter
J’espère qu’aujourd’hui sera l’occasion pour vous d’essayer jj
La transition est bien plus simple qu’on ne l’imagine, et j’ai gardé ma productivité dès le premier jour, sans avoir besoin de revenir une seule fois aux commandes git au bout d’une semaine
Je suis devenu plus productif en très peu de temps, au point de me demander comment je faisais avant avec git
Pour ma part, git ne me gêne absolument pas du point de vue de la productivité
Je n’utilise pas les commandes git longuement chaque jour, et dans la plupart des cas cela ne me pose aucun problème
Si votre travail demande beaucoup de manipulations du dépôt, jj peut être meilleur, mais ce n’est pas mon cas
C’est un peu comme recommander à tout le monde d’essayer bim, qui est très proche de vim mais avec quelques fonctions en plus
Mais je ne me demande pas combien de fois en plus je dois taper
i, et je n’ai pas besoin d’autocomplétion JuliaQue ceux pour qui jj est meilleur en profitent
jj est clairement une avancée côté interface de VCS, mais pour les utilisateurs avancés de git il y a quelques limites
L’absence de prise en charge de gitattributes est gênante si vous avez besoin de filtres comme git-crypt ou git-lfs
La compatibilité sur Windows, notamment pour la gestion des fins de ligne, peut aussi être moins bonne
Et des outils externes comme git-annex ou git-bug ne s’intègrent pas à l’oplog et peuvent aussi salir l’historique
J’ai justement eu l’expérience de l’utiliser pendant plus d’une semaine avant de revenir à git
Personnellement, je préfère le workflow avec staging area ; la plupart des gens n’aiment pas le staging de git, mais pour moi ce n’était pas un avantage suffisamment grand pour l’abandonner avec jj
Je pourrais sans doute changer mes habitudes, mais pour l’instant je ne me sens pas tenu d’adopter jj
Je reste ouvert à l’idée de réessayer un jour
Si je suis revenu à git après avoir utilisé jj pendant quelques mois, c’est à cause des performances
Les opérations jj prenaient plusieurs secondes, alors que git restait instantané quelle que soit la taille du projet
J’avais aussi l’impression que jj ajoutait un peu de complexité mentale, et revenir à git m’a semblé beaucoup plus léger
C’est peut-être simplement lié à mes longues années d’habitude avec git
Le simple fait de dire « de toute façon il n’y a que deux catégories » ressemble déjà au discours typique des évangélistes de jj
Ce qui me rend fou avec jj, c’est que les modifications sont forcément ajoutées automatiquement au staging
SVN fonctionnait comme ça à l’époque, et j’ai toujours eu l’impression que git avait énormément amélioré les choses en rendant le staging explicite
Il reste toujours plus de modifications dans un dépôt, et il est normal dans git de ne sélectionner que ce qu’on veut mettre dans le prochain commit
Dans jj (comme dans SVN), cela demande des manipulations pénibles, comme sortir temporairement certaines modifications avant de valider
C’est aussi un vrai dilemme pour moi
Le staging m’a toujours agacé, donc j’avais déjà du mal avec ça même sous Mercurial
Quand l’ajout automatique est utile dans plus de 90 % des cas, c’est au contraire pratique, mais le problème ce sont les fichiers qu’on ne peut pas mettre dans
.gitignoreDésactiver l’auto add est gênant, le laisser activé l’est aussi
Aucune des deux options n’est totalement propre
Le workflow de JJ est un peu différent : par exemple, on crée d’abord un commit de base, puis on empile dessus des commits anonymes pendant qu’on travaille
Quand on est prêt, on remet tout en forme avec
jj squashoujj splitJ’utilise
jj commit -i, l’option-idans plusieurs commandes, ainsi quesnapshot.auto-track="none()"dans la configJe faisais quelque chose de similaire avec Mercurial
En pratique, si on utilise beaucoup la fonctionnalité absorb, les fichiers ou hunks inutiles sont ignorés automatiquement
La commande
jj newne correspond-elle pas au workflow que vous recherchez ?jj suit correctement même les branches qui ne sont pas en head dans l’arbre, ce qui permet aux rebase et aux merge de se faire de manière fluide sans avoir besoin de stash
J’ai du mal à m’habituer à l’ajout automatique des changements
Il m’arrive en local de modifier temporairement certains fichiers pendant le développement sans aucune intention de les commit
Avec git, tant qu’on ne fait pas de staging, ils ne seront jamais commit ni push, ce qui est rassurant
Avec jj, j’ai l’impression qu’il faut penser à les retirer du staging ou faire particulièrement attention
C’est peut-être une question d’habitude, mais je préfère clairement désigner moi-même ce que je vais commit
Je me demande si je n’ai pas mal compris jj
Dans jj, on peut séparer les changements avec
jj splitCe qu’on sélectionne devient la première révision, le reste la seconde
Quand on a travaillé sur plusieurs choses à la fois puis qu’on veut les découper en petites révisions, c’est bien plus simple qu’avec git
Comme avec git, on peut créer une nouvelle révision (
jj new), faire des changements, puis déplacer exactement les parties voulues avecjj squash -iConceptuellement,
@est la révision courante et@-celle d’avant, donc on peut voir ça un peu comme la working copy et la staging area de gitL’auto-staging de jj n’est pas toujours une bonne chose
J’aimerais que la documentation officielle de jj et les débutants expliquent plus clairement qu’on peut facilement désactiver ce comportement par défaut
Dans
~/.jjconfig, il suffit d’écrire[snapshot]
auto-track = "none()"
comme ceci
En général, après avoir travaillé, j’utilise
jj splitpour relire et organiser ce qui doit être commitCe workflow se rapproche du
add -pde gitLe commit tout en haut peut servir de working copy qu’on ne push en général pas
Et même en changeant de branche sans stash, ce qui est en cours reste bien préservé
Oui, cette habitude est aussi difficile à changer pour moi
L’argument rationnel en faveur de ce changement, c’est qu’il ne faut pas exécuter du code dans un état non tracké
Les changements significatifs devraient être conservés dans des commits, et le reste ne devrait pas être gardé sans trace
Le problème, c’est quand les réglages à l’échelle du dépôt et les réglages locaux ne sont pas séparés, VSCode étant l’exemple typique
Dans ce cas, on a besoin de modifications spécifiques à l’environnement qu’il ne faut pas commit, ce qui complique les choses
Si c’est ce type de workflow que vous voulez, vous pouvez traiter le
@de jj comme l’index de git, puis faire un squash vers@-au moment du commit pour obtenir un effet proche degit add --patchJ’essaie de faire passer l’équipe à jj, mais sans succès pour l’instant
J’aimerais qu’il existe une page qui montre d’un coup d’œil à quel point les tâches complexes de git deviennent simples avec jj
Quelque chose d’aussi simple qu’un elevator pitch
Je me dis aussi qu’il faudrait sans doute que je fasse moi-même une démo
Il ne me semble pas que les opérations git les plus courantes soient plus faciles dans jujutsu
En revanche, jujutsu propose de nouveaux workflows qui sont impossibles ou pénibles avec git
Et ça ne parle pas forcément immédiatement aux développeurs déjà très habitués à git
Je n’aime pas particulièrement git non plus
À une époque, je n’utilisais que mercurial, mais aujourd’hui git est déjà gravé dans mon cerveau
Même si Jujutsu a un avantage clair, je n’y vois pas encore assez d’intérêt pour m’occuper du setup initial, comme les couleurs complexes ou mes scripts habituels
Une comparaison concrète d’une tâche type entre jj et git m’a beaucoup aidé à comprendre
https://lottia.net/notes/0013-git-jujutsu-miniature.html
Je recommande aussi quelques bons liens utiles
https://v5.chriskrycho.com/essays/jj-init/
https://v5.chriskrycho.com/journal/jujutsu-megamerges-and-jj-absorb/
https://ofcr.se/jujutsu-merge-workflow
Vous aimerez probablement ce que je vais bientôt ajouter à ce billet
Je compte le publier prochainement en bas de page ainsi que dans un billet séparé
Après quelques semaines avec jj, j’ai même créé un script automatique pour les messages de commit
Aujourd’hui, j’ai voulu porter le même script sur un ancien dépôt git, et j’ai réalisé que dans git il fallait du code pour déterminer automatiquement s’il s’agissait d’un commit ou d’un amend
Avec jj, grâce à la structure de commits immuables, le script était extrêmement simple
J’ai simplement recloné le dépôt avec jj
Je me suis débarrassé presque instantanément de cette confusion entre commit et amend
https://codeberg.org/jcdickinson/nix/src/branch/main/home/common/scripts/jj-auto.fish
git fonctionne suffisamment bien
Il y a juste une petite courbe d’apprentissage, mais une fois qu’on l’a appris, tout devient compréhensible
Honnêtement, dans 95 % des cas il suffit de connaître pull, add, reset, branch et commit
Dans mon workflow, les stacked diff sont indispensables
C’est idéal pour empiler du travail futur sans rester bloqué en attendant des reviews
Le setup n’est pas difficile dans git, mais ajouter des changements en bas de la pile et tout restacker est un véritable enfer
Quand on travaille à plusieurs, il est indispensable de bien maîtriser rebase et squash
Impossible d’y échapper tant qu’on n’a pas convaincu toute l’équipe de ne plus les utiliser
Surtout quand plusieurs personnes développent dans l’urgence sur une même branche, les habitudes git deviennent vite pénibles
C’est confortable à la base, mais dans les situations complexes, les problèmes sont nombreux
Il suffit de vivre quelques situations un peu atypiques pour voir les faiblesses de git
Cela fait environ deux semaines que j’utilise jj, et c’est la première fois que je gère confortablement le versioning uniquement en ligne de commande
Avec git, je passais toujours par une GUI (Git Graph dans VSCode) et beaucoup de clic droit
Avec jj, il m’a suffi de lire le tutoriel pour adopter tout de suite une ligne de commande cohérente
En revanche, pour éviter de copier-coller sans cesse des id dans le log de jj, il va sans doute falloir apprendre le langage revset
Même situation pour moi
J’utilise git depuis longtemps, mais dès que ça devenait un peu complexe, je passais toujours par une interface
Cela fait presque un mois que j’utilise uniquement la CLI de jj et j’en suis assez satisfait
En revanche, la documentation officielle de jj semble écrite en supposant des connaissances préalables, donc cela peut être déroutant pour les débutants
J’espère voir apparaître davantage de blogs et de tutoriels
J’aimerais aussi mieux apprendre le langage revset et rebase
J’apprécie la CLI concise, la résolution de conflits et l’oplog
Moi aussi, le copier-coller des identifiants me gênait, mais depuis que j’utilise jjui(https://github.com/idursun/jjui), c’est bien plus fluide
On finit par travailler très vite, un peu comme si on parcourait simplement le log
À mon avis, la meilleure fonctionnalité de jj, c’est undo
Dans git, undo est difficile parce que la commande dépend du type d’erreur commise
Avec jj, un simple
jj undosuffitEt comme ce n’est pas lié au système backend, on peut utiliser jj seul en local sans aucun impact pour ses collègues
Je ne comprends pas bien ce qu’est jj
Je me demande si ce n’est qu’un frontend pour les gens qui trouvent git déroutant
On parle d’abstraction du backend, mais l’outil me semble tellement influencé par git que j’ai du mal à l’imaginer sur des systèmes comme Perforce ou Piper, où les commits sont imposés avec des numéros séquentiels
Le principe working copy = commit me semble empêcher tout contrôle qualité
Le sens même d’un commit, c’est de ne pousser que ce qui est intentionnel, et avec une structure pareille, il devient encore plus difficile de distinguer les « commits poubelle »
Git comme jj semblent tous deux faibles sur les très gros projets, et rien ne paraît régler le problème de prolifération des commits
Je me demande quel problème jj résout réellement, ou si ce n’est qu’un frontend correspondant aux préférences de son auteur
Le backend Piper fonctionne au contraire de façon plus naturelle encore que le backend Git
Les commits jj ne correspondent pas parfaitement un à un aux commits git, donc il ne faut pas partir sur ce malentendu
En pratique, quand on parle de « commit », il faut plutôt comprendre « diff nommé », et les changements avant push peuvent toujours être facilement réécrits et réorganisés
C’est bien plus simple qu’un rebase ou qu’une édition d’historique dans git
Pendant mon travail, je crée facilement plusieurs commits pour des expérimentations, de la documentation, etc., alors qu’avec git j’aurais dû les entasser de force dans un stash ou une branche temporaire
jj est plus qu’un frontend git
C’est un système de contrôle de version, agnostique vis-à-vis du backend
Le backend principal étant git, on peut donc basculer immédiatement sur un dépôt existant
J’utilise git depuis avant l’arrivée de GitHub, mais depuis que j’ai adopté jj, impossible pour moi de revenir à git
Jj est plus simple tout en étant plus puissant
En réalité, il faut comprendre working copy = commit comme « l’index est lui aussi un commit »
Par exemple, pour commencer à travailler sur une feature x, on peut créer un nouveau commit avec
jj new -m "working on feature x" trunk, puis empiler encore un commit vide au-dessusLe travail en cours va dans la working copy (
@), puis on le « déplace » (squash) vers le commit précédent (@-) ; au lieu des options complexes de git comme add-p ou reset, tout se fait au travers du diff entre commitsGrâce à cette structure, on peut découper et réorganiser les commits de façon plus souple et plus puissante qu’avec l’index de git
Le problème de la prolifération des commits tient davantage à la culture pull request, et jj ne peut le résoudre que partiellement
La working copy n’est pas poussée aveuglément sur GitHub ; on peut la relire et la nettoyer au moment d’ajouter la description du commit
J’ai essayé jj quelques jours, mais je suis déjà suffisamment satisfait de lazygit ainsi que de mon workflow et de mes scripts existants
Jj est intéressant et original, mais à moins d’être en train de découvrir le versioning, je vois mal ce qui motive vraiment à changer
J’utilise toujours le diff de Lazygit, mais même en état detached HEAD cela ne pose absolument aucun problème
JJ s’intègre très bien avec git et permet de tout faire beaucoup plus facilement, sans avoir à mémoriser des commandes compliquées
Le fait que les fichiers non commit suivent automatiquement lors du passage d’une branche à l’autre est la meilleure fonctionnalité
C’est extrêmement pratique pour passer du développement à la correction de bug puis à des modifications de texte
Si un agent IA fait des changements, il suffit d’utiliser un worktree séparé
Le fait de pouvoir ajouter la description du changement (= le message de commit) avant même d’avoir terminé, pour l’apercevoir dans l’arbre, est aussi vraiment excellent
Dans l’ensemble, JJ est remarquablement bon