Jujutsu - Système de gestion de versions distribué compatible Git, simple et puissant
(github.com/martinvonz)- Jujutsu est un système de gestion de versions utilisé pour copier le code, suivre les modifications et publier les changements d’un projet logiciel ; il a été conçu pour être facile à utiliser aussi bien pour les nouveaux utilisateurs que pour les plus expérimentés, et aussi bien pour de nouveaux projets personnels que pour de grands historiques et de grandes équipes
- Il sépare en interne l’interface utilisateur et les algorithmes de gestion de versions du système de stockage qui fournit le contenu ; actuellement, il utilise des dépôts Git comme couche de stockage, ce qui le rend compatible avec les outils basés sur Git
- Git ne stocke que les commits et les fichiers, tandis que les bookmarks (branches) et les autres métadonnées de niveau supérieur sont stockés en dehors de Git dans un dépôt personnalisé
- Le backend Git par défaut utilise la bibliothèque Rust gitoxide ; il peut récupérer des branches depuis des dépôts Git distants, pousser vers le distant, et créer des commits qui ressemblent à des commits Git ordinaires
- Il utilise le modèle working-copy-as-a-commit, qui représente la copie de travail comme un vrai commit ; les modifications de fichiers sont automatiquement enregistrées comme un commit normal puis amendées à chaque changement ultérieur
- les commandes n’échouent pas à cause d’une working copy sale
git stashn’est pas nécessaire- il est possible de définir un message de commit pour le commit de la copie de travail avant même d’avoir terminé le travail
- Toutes les opérations du dépôt sont enregistrées avec un instantané de l’état du dépôt après l’opération ; il est possible de restaurer un état antérieur du dépôt, d’annuler une opération à l’unité, et de revert une opération spécifique qui n’est pas la plus récente
- Les conflits sont enregistrés comme des objets de premier ordre, au même titre que les commits ; une opération qui génère un conflit est donc tout de même considérée comme réussie et peut ensuite être traitée via un workflow unifié de résolution des conflits
- Lorsqu’un commit est modifié, tous ses descendants sont automatiquement rebasés sur le nouveau commit ; les résultats de résolution de conflits sont aussi propagés aux descendants, et les bookmarks ainsi que la copie de travail qui pointent vers les commits rebasés sont mis à jour
- Il n’y a ni index explicite ni staging area ; la sélection des commits s’appuie sur le langage revset, et le format de sortie est géré par un langage de templates configurable par l’utilisateur
- Pour la réécriture d’historique, il propose
jj describepour éditer le message de n’importe quel commit,jj diffeditpour modifier les changements d’un commit sans checkout,jj splitpour scinder un commit, etjj squash -i --from X --into Ypour déplacer une partie des changements vers un autre commit - La réplication concurrente sûre est une fonctionnalité expérimentale ; elle est conçue pour éviter qu’un dépôt ne soit corrompu lors de l’utilisation de systèmes de fichiers distribués ou d’outils de sauvegarde comme Dropbox ou
rsync, avec pour objectif, dans le pire des cas, d’exposer un conflit entre les états local et distant jjest un système de gestion de versions expérimental ; la compatibilité Git est stable, mais il peut encore y avoir des fonctionnalités en cours de développement, une UX non optimale et des lacunes de workflow dans certains modes d’usage- Les fonctionnalités sont déjà largement abouties, mais la prise en charge des submodules Git n’est pas encore terminée, plusieurs bugs de performance existent, et il n’y a pas de prise en charge native des workflows basés sur l’e-mail
- Avant la version 1.0.0, des changements de workflow et des modifications non rétrocompatibles du format sur disque sont prévus ; pour ces changements de format, le projet essaie de fournir soit une mise à niveau transparente, soit, sur demande, une commande ou un script de migration
- C’est un logiciel open source sous licence Apache 2.0 ; ce n’est pas un produit soutenu par Google, et le support est assuré par la communauté
2 commentaires
Jujutsu - un DVCS simple et puissant compatible avec Git
Je l’avais publié il y a un an et demi, et le sujet est de nouveau remonté sur HN.
Avis de Hacker News
Content de le voir ici. Je suis passé à jj il y a environ 2 ou 3 semaines et je n’ai aucune envie de revenir en arrière. J’ai dû pas mal changer ma façon de penser mon travail, mais j’aime beaucoup le flux proposé par
jjJe n’ai plus à réfléchir séparément à ce que je vais committer : toutes les modifications de fichiers sont automatiquement reflétées dans le commit de copie de travail. Bien sûr, il y a des moments où ce n’est pas ce qu’on veut, donc il existe des fonctions pour diviser un commit en deux ou déplacer des changements, et j’aime le fait que toutes les opérations agissent sur des commits
jj logest excellent pour voir une carte complète de plusieurs branches, on peut résoudre seulement une partie des conflits puis passer à une autre branche, et les ID abrégés de changesets sont pratiques. Par exemple, dansjj log, on peut repérer le changeset à rebaser puis lancerjj rebase -s qr -d master, ce qui est plus rapide que de taper tout le nom de la brancheIl est indiqué qu’on peut l’utiliser avec des backends comme Dropbox, mais j’aimerais voir apparaître un système facile à utiliser avec IPFS. Pour les gros volumes de données, on ne peut pas stocker 1 To sur GitHub, et je mets LFS de côté parce qu’il est payant
Les personnes qui veulent utiliser un dataset l’ont de toute façon en local, donc IPFS, où la source de téléchargement n’est pas unique mais se compte en milliers, est une solution naturelle. S’il utilisait IPFS pour le dépôt de données, je migrerais tout de suite ; sinon, je vois peu d’intérêt à l’examiner
Jujutsu a commencé comme le projet personnel de son auteur, et c’est maintenant son projet à plein temps chez Google. Il a été présenté à Git Merge 2022
Jujutsu: A Git-Compatible VCS - Git Merge 2022:
Video:
https://youtu.be/bx_LGilOuE4
Slides:
https://docs.google.com/presentation/d/1F8j9_UOOSGUN9MvHxPZX...
J’utilise jj quotidiennement depuis presque un an, et je trouve l’expérience nettement meilleure que celle de Git. Comme je suis assez pointilleux sur la séparation des changements en commits atomiques, le rebase automatique est une fonctionnalité clé
Les conflits peuvent être enregistrés dans les commits, donc il n’est pas nécessaire de s’arrêter au milieu d’un rebase pour les corriger comme avec Git ou Mercurial. Même si l’on modifie ou supprime un commit, jj rebase automatiquement tous les commits descendants et, contrairement à Git rebase, il gère aussi plusieurs enfants, comme Mercurial evolve
Les commandes de base pour manipuler l’historique des commits sont également bonnes. Avec
jj move|restore, on déplace ou copie les changements d’un commit vers un autre ; avecjj split, on découpe un commit ; avecjj rebase, on déplace des commits. Comme tout se trouve dans l’historique des commits, sans arbre de travail ni index, on peut tout traiter avec les mêmes commandes et les mêmes optionsLe journal des opérations est aussi excellent, ce qui permet d’annuler la plupart des actions sans problème. C’est tout le contraste avec Git, où pour corriger un mauvais rebase ou un
commit --amend, il faut fouiller dans le reflog pour retrouver le bon commit et réparer manuellement les refsLes points les plus gênants sont que le commit automatique de la copie de travail essaie parfois de committer des fichiers non désirés, et qu’il n’y a pas de détection des renommages, ce qui rend les merges moins élégants qu’avec Git. Cela dit, un commit cassé se corrige assez facilement avec
jj split|restore, et les développeurs de jj réfléchissent aussi au problème des renommagesJ’apprécie le fait que, même si le résultat d’une opération produit des conflits, cette information soit enregistrée dans le commit et que l’opération soit considérée comme réussie, les conflits pouvant être résolus plus tard. Je travaille depuis une dizaine d’années sur des algorithmes d’édition collaborative et, idéalement, j’aimerais que des outils comme Git finissent par être remplacés par une approche fondée sur les CRDT
Avec les CRDT, on peut faire du pair programming avec les mêmes outils, et mieux gérer des merges complexes comme les conflits avec soi-même qui peuvent apparaître dans Git. C’est aussi un modèle plus puissant
Cela dit, les CRDT textuels modernes résolvent automatiquement les éditions simultanées sans conflit, alors qu’en collaboration offline sur du code, on veut généralement que les conflits apparaissent pour qu’un humain les résolve lui-même. Les CRDT conservent davantage d’informations sur l’historique d’édition que Git, donc c’est théoriquement possible, mais pour bien faire, il faudrait sans doute intégrer les conflits eux-mêmes au modèle de données des fichiers texte, et je ne sais pas très bien comment cela s’articulerait avec les éditeurs modernes
On dirait que jj a trouvé une approche du même genre, donc j’ai hâte de voir à quel point cela fonctionne en pratique. J’ai l’impression qu’on se rapproche un peu du rêve d’un dépôt de code basé sur les CRDT
git bisectQuand on a un bug reproductible et une cause complexe, il me semble utile de déterminer quel commit a introduit le bug afin de voir quel changement en est la cause. Au minimum, c’est un bon moyen d’avoir une première intuition sur ce qu’il faut corriger
Aujourd’hui,
git bisectfonctionne au mieux lorsque tous les commits peuvent être compilés et exécutés. S’il y a des commits contenant des marqueurs de conflit qui empêchent la compilation ou l’exécution, il faut beaucoup plus d’intervention manuelleJe me demande comment on pourrait adapter l’équivalent de
git bisectà ce scénario. Scanner simplement les chaînes de marqueurs de conflit pourrait ne pas convenir : un document peut expliquer des marqueurs de conflit, ou dans certains langages de balisage,=======peut être utilisé légalement comme soulignementCela semble entrer en conflit avec l’idée que l’historique de gestion du code source est un artefact important, et qu’un ensemble de patches devrait être organisé en une suite de changements progressifs et atomiques avant de quitter la machine de développement
Cela dit, la plupart des développeurs autour de moi traitent déjà l’historique Git comme un historique d’annulation infini d’éditeur, donc cette approche risque aussi de consacrer cet état de fait
Je me demande comment vous voyez fonctionner l’historique à long terme, et s’il sera plus utile ou moins utile qu’aujourd’hui
Le fait que la copie de travail soit automatiquement commitée semble séduisant au début, mais il y a beaucoup de situations où ce n’est pas idéal
Si un nouveau fichier généré apparaît et qu’il n’a pas encore été ajouté à
.gitignore, il sera commité automatiquement ; et si l’on ajoute un fichier à ignorer sur une branche puis que l’on passe à une autre, il peut rester dans la copie de travail sans être dans.gitignore, et donc être commité automatiquementPar ailleurs, il est beaucoup plus simple de ne commiter que certains fichiers en les mettant en staging que de scinder un commit plus tard
Cette idée est aussi bien ancrée dans ma tête, mais je ne sais pas si elle est vraiment juste. En pratique, il arrive assez souvent de corriger l’index puis d’amender un commit a posteriori, et on pourrait aussi le faire en amont
Si l’on ne peut de toute façon pas éviter complètement l’édition a posteriori, peut-être qu’un flux de travail unique pour ce type d’édition serait préférable. Je ne l’ai pas encore essayé, mais l’approche semble assez convaincante pour remettre en cause une convention que l’on tient pour acquise et qui n’aide peut-être pas vraiment
Je n’ai aucun cas d’usage où tous les fichiers créés ou modifiés doivent toujours entrer dans le commit
Quand on change de branche et qu’un fichier reste dans la copie de travail sans être dans
.gitignore, j’y vois un échec de Git. Il faudrait quelque chose comme un.local.gitignoreen plus de.gitignore. Les fichiers à ignorer qui ne concernent que moi sont très courants et n’ont pas vocation à aller dans le.gitignoredu projet. Il existe des moyens de le faire, mais ils sont tous maladroits ; cela devrait être fourni simplement par défautCela reste intéressant. Je n’ai jamais aimé le staging de Git, mais je n’avais pas rencontré les cas mentionnés ici ; je comprends seulement maintenant qu’il faut une étape intermédiaire entre le système de fichiers et les commits
.gitignore, ils sont retirés du commit anonyme de copie de travail lors du commit automatique suivantLe fait qu’un fichier entre dans le commit anonyme de copie de travail puis en ressorte, au lieu de ne jamais être ajouté au départ, n’est pas très intuitif ; mais si ce commit anonyme est invisible pour la plupart des utilisateurs, cela ne devrait pas faire de différence
La documentation traite explicitement plusieurs des cas qui vous inquiètent :
https://github.com/martinvonz/jj/blob/main/docs/git-comparis...
À quelques cas particuliers près, cela fait des années que j’utilise très peu Git en ligne de commande. Au quotidien, je m’appuie sur l’intégration intégrée aux IDE comme IntelliJ, et j’ai du mal à comprendre pourquoi on s’infligerait tout cela manuellement
Dans l’éditeur, je peux sélectionner des lignes pour faire des commits partiels, voir toutes les branches, fusionner, cherry-pick, commiter ou amender, pull les mises à jour et modifier les tags en une seule action au clavier
Cela dit, j’ai l’impression d’être minoritaire ici. D’autant plus avec l’ambiance selon laquelle Git serait une compétence indispensable et qu’un vrai programmeur devrait pouvoir taper les commandes les yeux fermés ; je me demande pourquoi
Cette compétence est indépendante de l’environnement : consulter un dépôt sur une machine distante se fait comme en local, il n’est pas nécessaire de réapprendre l’intégration VCS de chaque éditeur, et je peux continuer à utiliser les outils que je connais
Les opérations données en exemple sont tout aussi faciles en ligne de commande, donc je ne vois pas l’intégration à l’éditeur comme quelque chose de spécial. Et si l’on doit faire des opérations étranges et avancées, comme manipuler le reflog, il y a de fortes chances qu’il faille de toute façon ressortir la ligne de commande
Bien sûr, je n’ai rien contre les gens qui utilisent une GUI. Si un outil les rend productifs, ce n’est pas à moi de juger ; mais puisque la question était posée, je réponds simplement, sans prétendre que ma méthode est meilleure
C’est le contexte le plus fréquent dans lequel les gens disent qu’il faut « apprendre la CLI Git »
Il y a encore quelques jours, il y avait un exemple de quelqu’un qui voulait utiliser GitHub Desktop pour éviter d’apprendre les commandes Git : https://www.reddit.com/r/learnprogramming/comments/15b7pra/s...
Grâce à son approche qui met d’abord en avant la compatibilité avec Git, Jujutsu me paraît plus solide que tout ce que j’ai vu jusqu’ici comme candidat au remplacement de Git
En lisant l’explication sur la compatibilité Git, ce qui m’a intrigué, c’est qu’elle semble surtout se concentrer sur le cas d’usage où les utilisateurs de Jujutsu accèdent avec jj à des dépôts Git hébergés sur GitHub, etc. À l’inverse, je me demande s’il est aussi possible d’accéder avec Git à des dépôts Jujutsu natifs
La plupart des développeurs étant déjà habitués à la CLI Git, en exploitation réelle il y aura probablement des développeurs qui utilisent à la fois jj et Git sur la même base de code. Ou alors je me demande si, dans un scénario opérationnel réaliste, on utilise toujours Git comme stockage backend, plutôt qu’une base de données Jujutsu native, afin de permettre l’accès depuis les deux CLI
Ce backend existe surtout pour garantir qu’il sera possible, plus tard, d’ajouter des fonctionnalités qui ne seraient pas faciles à intégrer au backend Git
Si je travaille et contribue à un projet qui utilise déjà Jujutsu, il est raisonnable que ce soit moi qui m’adapte au projet, plutôt que le projet qui s’adapte à mon workflow
Grâce à l’approche compatibilité Git d’abord, Jujutsu me paraît plus solide que les candidats au remplacement de Git que j’ai vus jusqu’ici
Je m’interroge sur la gestion des conflits. Je sais que pmeunier a consacré beaucoup d’efforts à formaliser la théorie des patchs pour Pijul, et des notions de patch ou de conflit malsaines ou problématiques peuvent entraîner de gros problèmes. Il me semble que c’est ainsi que sont apparus les problèmes de performance de Darcs
Ce serait bien que la page de comparaison du wiki du dépôt explique le traitement des conflits de Pijul un peu plus en détail que simplement dire qu’il est « similaire »
Stocker les conflits symboliquement de cette manière permet de les reproduire plus tard et peut aussi permettre de résoudre automatiquement certains conflits, mais cela ne traite pas le problème de la résolution du contenu réel des conflits
Si quelqu’un l’implémente, on pourrait peut-être utiliser Pijul comme backend de jj et obtenir le meilleur des deux mondes
La réplication sûre via rsync, Dropbox ou un système de fichiers distribué, c’est une bonne chose. Ces derniers temps, je penche de plus en plus vers des systèmes compatibles avec une simple synchronisation
Parce qu’on peut les déposer n’importe où, avec n’importe quel outil, et ça fonctionne tout simplement. C’est toujours agréable de voir un nouvel outil prendre cette direction
J’ai entendu dire que ce genre de problème existait, mais je ne l’ai jamais rencontré directement. Je me demande quelles conditions de concurrence peuvent apparaître entre Git et des outils comme rsync/Dropbox et poser problème
Heureusement que la copie de travail est automatiquement commitée. C’est une fonctionnalité dont on avait besoin depuis longtemps
Bravo à Martin pour les efforts consacrés à créer un outil élégant