4 points par GN⁺ 2023-08-02 | 2 commentaires | Partager sur WhatsApp
  • 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 stash n’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 describe pour éditer le message de n’importe quel commit, jj diffedit pour modifier les changements d’un commit sans checkout, jj split pour scinder un commit, et jj squash -i --from X --into Y pour 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
  • jj est 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

 
xguru 2023-08-03

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.

 
GN⁺ 2023-08-02
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 jj
    Je 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 log est 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, dans jj log, on peut repérer le changeset à rebaser puis lancer jj rebase -s qr -d master, ce qui est plus rapide que de taper tout le nom de la branche

    • Je me demande ce qui se passe si l’on enregistre par erreur un fichier contenant des secrets et qu’il est automatiquement aspiré
    • Je me demande si on l’utilise simplement avec un dépôt GitHub
      Il 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
    • Je me demande s’il existe des cas d’utilisation réussis en équipe. J’aimerais savoir ce que ça donne quand deux personnes travaillent sur la même branche
  • 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...

    • Voir son projet personnel devenir un projet à plein temps chez Google doit être assez gratifiant
  • 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 ; avec jj split, on découpe un commit ; avec jj 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 options
    Le 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 refs
    Les 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 renommages

  • J’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

    • Vous devriez jeter un œil à Pijul. Il implémente en pratique la plupart de ce qui est évoqué ici. Pijul fonctionne au-dessus de patches qui sont des CRDT, et traite les conflits comme des concepts de premier ordre
    • Je me demande si vous n’avez jamais trouvé de valeur à git bisect
      Quand 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 bisect fonctionne 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 manuelle
      Je 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 soulignement
    • Je me demande comment cela se déroulera en pratique
      Cela 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é automatiquement
    Par ailleurs, il est beaucoup plus simple de ne commiter que certains fichiers en les mettant en staging que de scinder un commit plus tard

    • J’ai l’impression que ce projet remet en question l’idée reçue selon laquelle commiter seulement certains fichiers via le staging serait plus facile que scinder un commit après coup
      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
    • Même avis. En général, dans un répertoire de projet, j’ai plus de 10 fichiers supplémentaires comme des fichiers de sortie, des notes ou des scripts jetables. Quand j’ajoute des fichiers à un commit, je les choisis toujours par nom de fichier ; je n’ajoute pas tout ce qui est nouveau ou modifié
      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.gitignore en plus de .gitignore. Les fichiers à ignorer qui ne concernent que moi sont très courants et n’ont pas vocation à aller dans le .gitignore du projet. Il existe des moyens de le faire, mais ils sont tous maladroits ; cela devrait être fourni simplement par défaut
    • Pour le premier problème, il me semble qu’il suffirait de comparer facilement les fichiers déjà suivis et les nouveaux fichiers
      Cela 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
    • D’après ma seule lecture du README, je comprends que si l’on ajoute ces fichiers à .gitignore, ils sont retirés du commit anonyme de copie de travail lors du commit automatique suivant
      Le 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
    • Je ne vois pas très bien pourquoi ces points poseraient problème dans la conception de jj, ni pourquoi mettre certains fichiers en staging serait plus simple que scinder un commit plus tard
      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

    • J’ai toujours préféré utiliser les systèmes de contrôle de version en ligne de commande, et cela ne changera pas
      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
    • D’expérience, les intégrations d’IDE n’implémentent généralement pas toutes les fonctionnalités de la CLI Git. Cela s’est peut-être amélioré, mais dès qu’on dépasse les opérations de base clone/branch/commit/merge et que le nombre de développeurs ou de branches augmente un peu, on finit par revenir à la CLI Git pour résoudre les problèmes
    • Je ne sais pas si je suis un vrai programmeur, mais j’ai une peur irrationnelle qu’une GUI Git fasse quelque chose de travers. Même dans IntelliJ, j’utilise Git en ouvrant la CLI intégrée. Les vieilles habitudes ont la vie dure
    • Beaucoup de gens qui commencent tout juste à utiliser Git ne comprennent pas comment Git fonctionne, c’est-à-dire ce que sont les commits et les branches, ni ce qu’on peut en faire. Ensuite, ils blâment l’outil CLI et s’attendent à ce que GitHub Desktop rende tout compréhensible
      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...
    • Dans une équipe, il n’y a que deux catégories de personnes qui comprennent Git : celles qui utilisent la CLI, et celles qui commencent à cliquer sur des boutons sans comprendre Git
  • 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

    • D’après une note de bas de page du README, il n’y a actuellement presque aucune raison pratique d’utiliser le backend natif
      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
    • J’imagine qu’on s’attend soit à toujours utiliser Jujutsu comme frontend d’un dépôt Git, soit à utiliser un dépôt distant entièrement basé sur Jujutsu
      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 »

    • Il y a une explication un peu plus détaillée ici : https://github.com/martinvonz/jj/blob/main/docs/technical/co...
      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’aimerais qu’on explique davantage ce point
      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