Jujutsu para desenvolvedores ocupados
(maddie.wtf)- Jujutsu (jj) é um sistema de controle de versão que oferece conceitos e comandos mais simples do que o Git, mas com recursos poderosos
- Como usa o Git como backend, tem a vantagem de poder ser usado em conjunto ou de voltar facilmente ao Git
- Recursos como diffs em pilha, rebase fácil e revisões temporárias são oferecidos de forma natural
- Em vez de branches, ele usa o conceito de bookmarks, o que é mais intuitivo para o fluxo de trabalho do dia a dia
- A forma de lidar com conflitos é flexível e torna muito mais simples as tarefas cotidianas de controle de versão
Elevator Pitch
Jujutsu (jj) é um sistema de controle de versão que oferece um modelo mental e uma interface de linha de comando muito mais simples do que o Git.
Sem sacrificar funcionalidades, e na prática dá até para dizer que ele é mais poderoso
Recursos como diffs em pilha, rebase fácil e revisões temporárias funcionam de forma natural
Como usa o Git no backend, dá para começar a usá-lo lado a lado com um repositório Git com uma única linha e voltar ao Git a qualquer momento
Também não afeta a forma como outras pessoas lidam com o repositório
Getting Started
- Depois de instalar a ferramenta de linha de comando
jj, é recomendável configurar as informações do usuário e o autocompletar do shell - Ao aplicar em um repositório existente, é melhor fazer um novo clone ou começar a usá-lo quando não houver mudanças pendentes
- Em um repositório existente, é possível criar repositórios Git e Jujutsu em paralelo com o comando
jj git init --colocate . - Os dados do repositório
jjficam armazenados em uma pasta.jj/, separada da.gitdo Git - A sincronização de dados entre Git e Jujutsu normalmente funciona sem problemas
- Mas é preciso cuidado, porque o comando
git clean -fdxapaga a pasta.jj/ - O rastreamento de remote branches também pode ser configurado de uma vez com esse comando
How To Use It
A interface de linha de comando do Jujutsu é mais enxuta e concisa que a do Git
Os conceitos básicos são simples, mas o fluxo de trabalho exige um pequeno período de adaptação
A seguir estão os principais modos de uso com procedimentos simples e exemplos
Starting A New Revision
- No Git, um novo trabalho normalmente começa com a criação de uma branch, mas no Jujutsu a abordagem é criar uma nova revisão
- Refletir o estado mais recente do repositório remoto:
jj git fetch - Ver o histórico do repositório:
jj log - As revisões no histórico são identificadas por um ID de revisão próprio do Jujutsu e por um hash de commit do Git
- Para começar um novo trabalho, use
jj new mainpara criar uma nova revisão em cima damainatual - A revisão que está sendo editada no momento é indicada pelo símbolo
@ - Se um mesmo prefixo deixar de existir, o prefixo curto do ID da revisão também muda junto
Making Changes
- Ao editar arquivos, eles são incluídos imediatamente naquela revisão (não há staging area separada)
- Quando terminar as alterações, adicione uma mensagem à revisão com
jj describe -m "mensagem" - Para criar uma nova revisão, use
jj new(ou especifique uma revisão anterior) jj commité uma operação combinada dejj describe+jj new
Navigating
- Uma revisão vazia criada com
jj newé descartada automaticamente ao se mover para outro lugar - Excluir explicitamente uma revisão:
jj abandon <rev ID> - Desfazer a exclusão:
jj op undo - Voltar para uma revisão existente:
jj edit <rev ID> - Ao referenciar revisões, também é possível usar revset expressions:
@: revisão atualx-: revisão paiy+: revisão filhaz::: todos os descendentes de z
Branches (Bookmarks)
- No Jujutsu, não existe o estado de “estar em uma branch” como no Git
- Em vez disso, os bookmarks são apenas ponteiros para uma revisão específica
- Criar um novo bookmark:
jj bookmark create <nome> -r <revisão> - Mesmo após um commit, o bookmark não se move automaticamente; se necessário, ele deve ser movido separadamente com
jj bookmark move <nome> --to <revisão> - Ao fazer push, a criação de uma nova branch remota precisa ser permitida com a flag
--allow-new - Se o bookmark estiver diferente do remoto, ele será mostrado com
*e poderá ser sincronizado comjj git push
Conflicts
- A forma de tratar conflitos no Jujutsu é mais flexível do que no Git
- Em caso de conflito, a marcação
conflictedaparece na revisão e também nas revisões descendentes - Arquivos com conflito recebem marcadores de conflito, e a resolução é feita removendo esses marcadores
- Também é possível editar diretamente ou fazer mudanças em uma nova revisão e depois juntar tudo com
jj squash
Conclusão
Até aqui, foi mostrado como realizar de forma mais simples no Jujutsu os 80% de tarefas mais comuns feitas com Git
No futuro, usos gerais e avançados devem ser apresentados em formato de handbook de referência rápida (Quick Reference)
Assim como no Git, o comando jj status também é suportado
Dúvidas ou feedback podem ser enviados para o e-mail mencionado no texto
1 comentários
Comentários do Hacker News
Para quem está se perguntando se vale a pena aprender jj, há um ponto que eu queria enfatizar
Quando se fala de jj no Hacker News, as pessoas se dividem em dois grupos: as que ainda não tentaram e as que recomendam fortemente
Quase nunca vi alguém usar jj por uma semana e depois voltar para o git
Quase todo mundo que realmente usou com seriedade acabou ficando com jj
Espero que hoje seja o dia em que você experimente jj
A mudança é muito mais simples do que parece; eu consegui manter a produtividade já no primeiro dia e, em menos de uma semana, não precisei voltar aos comandos do git nenhuma vez
Em pouco tempo fiquei mais produtivo e hoje só me pergunto como eu usava git antes
Para mim, o git não é nem um pouco incômodo em termos de produtividade
Também não passo muito tempo por dia usando comandos do git e, na maioria dos casos, ele não atrapalha meu trabalho
Se você precisa manipular muito o repositório com git, jj pode ser melhor, mas esse não é o meu caso
É parecido com sugerirem que eu experimente obrigatoriamente o bim, que é muito parecido com o vim, mas com alguns recursos a mais
Só que eu não me importo em digitar mais alguns
i, nem preciso de autocomplete de JuliaQuem acha jj melhor, que aproveite
jj é claramente um avanço na UI de VCS, mas, para usuários avançados de git, há algumas limitações
Sem suporte a gitattributes, fica inconveniente se você precisa de filtros como git-crypt ou git-lfs
A compatibilidade no Windows, incluindo tratamento de fim de linha, também pode ser pior
Além disso, ferramentas externas como git-annex e git-bug não se integram ao oplog e podem bagunçar o histórico
Eu realmente usei por mais de uma semana e depois voltei para o git
Pessoalmente, prefiro o workflow da staging area; a maioria das pessoas odeia o staging do git, mas, para mim, isso não foi um ganho grande o bastante para abandonar em troca do que o jj oferece
Talvez eu consiga mudar de hábito, mas por enquanto não estou particularmente preso ao jj
Continuo aberto a tentar de novo algum dia
Eu usei jj por alguns meses e voltei para o git por causa de problemas de desempenho
As operações no jj levavam vários segundos, enquanto no git tudo era imediato, independentemente do tamanho do projeto
Também tive a sensação de que usar jj me deixava mentalmente um pouco mais sobrecarregado, e voltar para o git foi um alívio
Isso pode ter relação com a minha longa experiência usando git
Só existem dois tipos de pessoa, né? Isso por si só já soa como fala típica de evangelista de jj
O que me deixa maluco no jj é que as mudanças são sempre adicionadas automaticamente ao staging
O SVN funcionava assim antigamente, e eu sempre senti que o git melhorou muito ao tornar o staging explícito
Sempre existem mais mudanças no repositório, e no git é natural selecionar apenas o que você quer colocar no próximo commit
No jj (e no SVN), isso exige trabalho manual incômodo, como tirar temporariamente alterações de cena antes de commitar
Para mim isso também é um dilema
Staging sempre foi uma chateação, e eu sofria com isso até quando usava Mercurial
Quando você precisa de auto add em mais de 90% dos casos, isso até ajuda, mas o problema são os arquivos que não dá para colocar no
.gitignoreSe você desliga o auto add, fica incômodo; se deixa ligado, também fica meio estranho
Nenhum dos dois lados é totalmente limpo
O workflow do JJ é um pouco diferente; por exemplo, você cria primeiro um commit base e vai empilhando commits anônimos em cima para trabalhar
Quando estiver pronto, organiza tudo com
jj squashoujj splitEu uso
jj commit -i, a opção-iem vários comandos esnapshot.auto-track="none()"na configuraçãoEu fazia algo parecido quando usava Mercurial
Na prática, se você usa bastante o recurso absorb, arquivos ou chunks desnecessários costumam ser ignorados automaticamente
O comando
jj newnão seria adequado para o workflow que você quer?O jj rastreia corretamente até branches que não estão no head da árvore, então rebase e merge funcionam de forma suave sem precisar de stash
Não é fácil se acostumar com a adição automática de mudanças
Às vezes eu altero localmente certos arquivos só durante o desenvolvimento, sem intenção de commitar
No git, se eu não fizer staging, sei que aquilo nunca vai ser commitado nem enviado por push
No jj, parece que eu precisaria desfazer o staging de algo ou tomar mais cuidado
Pode ser questão de hábito, mas eu me sinto mais confortável definindo claramente só o que vou commitar
Talvez eu tenha entendido o jj de forma errada
No jj, você pode dividir as mudanças com
jj splitO que você selecionar vai para a primeira revisão, e o resto fica na segunda
Se você trabalhou em várias coisas ao mesmo tempo e depois separou em revisões pequenas, isso é muito mais fácil do que no git
Como no git, você pode criar uma nova revisão (
jj new), fazer alterações e depois mover exatamente o que quiser comjj squash -iConceitualmente,
@é a revisão atual e@-é a anterior, então dá para pensar nisso como a working copy e o stage do gitO auto staging do jj nem sempre é uma coisa boa
Seria bom se a documentação oficial do jj e quem apresenta a ferramenta deixassem mais claro que o valor padrão pode ser desativado facilmente
No
~/.jjconfig, basta colocar[snapshot]
auto-track = "none()"
assim
Eu normalmente reviso e organizo o que vai ser commitado com
jj splitdepois de trabalharEsse workflow funciona de forma parecida com
add -pdo gitO commit do topo pode ser usado como uma espécie de working copy que você normalmente não envia por push
Você também pode trocar de branch sem stash que o que estiver em andamento continua preservado
Sim, esse hábito também foi difícil de mudar para mim
O argumento racional para mudar é que você não deveria rodar código em estado untracked
Mudanças significativas devem ficar em commits, e o resto é melhor não registrar
O problema aparece quando a configuração do repositório e a configuração local não ficam separadas, e o VSCode é um bom exemplo disso
Nesses casos, você acaba precisando de mudanças específicas do ambiente que não devem ser commitadas, o que complica tudo
Se você quer esse tipo de workflow, pode tratar o
@do jj como o index do git e, na hora do commit, fazer squash em@-para obter algo parecido comgit add --patchEstou tentando migrar o time para jj, mas sem sucesso
Seria ótimo ter uma página que mostrasse de forma imediata o quanto tarefas complexas do git ficam mais fáceis no jj
Algo quase como um elevator pitch
Também estou achando que talvez eu precise demonstrar isso pessoalmente
Parece que muitas das tarefas comuns do git não ficam necessariamente mais fáceis no jujutsu
Em vez disso, o jujutsu oferece workflows novos que seriam impossíveis ou trabalhosos no git
Isso pode não ser tão convincente para desenvolvedores já acostumados com o git
Eu também não gosto particularmente do git
No passado eu só usava Mercurial, mas hoje o git já está completamente internalizado na minha cabeça
Mesmo que o Jujutsu tenha alguma vantagem clara, ainda não senti que valha o esforço de cuidar da configuração inicial, como esquema de cores complexo e scripts com os quais já estou acostumado
Uma comparação de uma tarefa representativa entre jj e git me ajudou bastante a entender
https://lottia.net/notes/0013-git-jujutsu-miniature.html
Também recomendo alguns links úteis
https://v5.chriskrycho.com/essays/jj-init/
https://v5.chriskrycho.com/journal/jujutsu-megamerges-and-jj-absorb/
https://ofcr.se/jujutsu-merge-workflow
Acho que você vai gostar da próxima parte que vou adicionar a este post em breve
Pretendo colocá-la embaixo na página e também em um post separado em pouco tempo
Usei jj por algumas semanas e até fiz um script de mensagem de commit automática
Hoje fui portar o mesmo script para um repositório git antigo e percebi que, no git, eu precisava de código para detectar automaticamente se era um commit ou um amend
No jj, por causa da estrutura de commits imutáveis, o script ficou muito simples
Então simplesmente clonei o repositório de novo com jj
Foi uma libertação instantânea da confusão entre commit e amend
https://codeberg.org/jcdickinson/nix/src/branch/main/home/common/scripts/jj-auto.fish
O git funciona bem o suficiente
A curva de aprendizado existe, mas, depois que você aprende, tudo faz sentido
Sinceramente, em 95% dos casos, basta saber
pull,add,reset,branchecommitNo meu workflow, stacked diff é essencial
É ótimo para continuar empilhando trabalho futuro sem ficar bloqueado esperando review
No git, configurar isso não é difícil, mas adicionar mudanças na parte de baixo da pilha e depois fazer restack de tudo é um verdadeiro inferno
Quando se trabalha em equipe, dominar rebase e squash é indispensável
É impossível fugir disso até convencer o time inteiro a não usar
Especialmente quando várias pessoas estão desenvolvendo às pressas na mesma branch, os hábitos do git começam a incomodar
No básico ele é confortável, mas, em situações complexas, tem muitos problemas
Basta passar por alguns casos mais peculiares para perceber os pontos fracos do git
Estou usando jj há umas duas semanas e é a primeira vez que me sinto confortável usando controle de versão só pela linha de comando
Quando eu usava git, quase sempre dependia da GUI (Git Graph no VSCode) e de clicar com o botão direito
Com jj, bastou ler o tutorial para entrar direto em uma linha de comando coerente
Mas, para evitar ficar copiando e colando IDs o tempo todo no log do jj, acho que vou precisar aprender a linguagem de revset
Estou numa situação parecida
Usei git por muito tempo, mas sempre resolvia as coisas mais complexas pela UI
Já faz quase um mês que uso só a CLI do jj e estou bem satisfeito
Ainda assim, a documentação oficial do jj parece escrita assumindo conhecimento prévio, então às vezes pode confundir iniciantes
Tomara que apareçam mais blogs e tutoriais
Também quero aprender melhor revset e rebase
Gosto bastante da CLI enxuta, da resolução de conflitos e do oplog
Eu também achava ruim ficar copiando e colando IDs, mas depois que comecei a usar o jjui(https://github.com/idursun/jjui) ficou muito mais fluido
Acabei passando a trabalhar rapidamente, quase como se estivesse percorrendo o log
Acho que o melhor recurso do jj é o undo
No git, desfazer coisas é difícil porque o comando muda conforme o tipo de erro
No jj, basta um
jj undoE você nem fica preso ao sistema de backend; dá para usar jj localmente sozinho sem afetar os colegas
Estou confuso sobre o que exatamente é o jj
Será que é um frontend para quem se perde com git?
Dizem que abstrai o backend, mas ele ainda parece tão influenciado por git que tenho dificuldade de imaginá-lo em sistemas como Perforce ou Piper, que impõem commits com numeração sequencial
Esse design de working copy = commit me parece tirar o controle de qualidade
O sentido original de commit é registrar apenas o que foi intencionalmente preparado, e com essa estrutura parece ficar ainda mais difícil distinguir "commits lixo"
Tanto git quanto jj parecem frágeis para projetos grandes e não parecem impedir a proliferação de commits ruins
Quero entender que problema o jj realmente resolve, ou se ele é só um frontend moldado pela preferência do autor
O backend do Piper, na verdade, funciona de forma ainda mais natural do que o backend do Git
Os commits do jj não correspondem perfeitamente aos commits do git, então não precisa partir dessa premissa
Na prática, quando se fala em “commit” aqui, a ideia é mais de um “diff com nome”, e mudanças antes do push podem ser reorganizadas e reescritas com muita facilidade
Isso é muito mais prático do que rebase e edição de histórico no git
Eu costumo criar vários commits experimentais, de documentação etc. durante o trabalho, e no git teria que enfiar isso em stash ou em branches temporárias
jj é mais do que um frontend para git
É um sistema de controle de versão e é agnóstico ao backend
O backend mais comum é o git, o que permite migrar imediatamente em repositórios já existentes
Eu uso git desde antes do GitHub existir, mas depois de usar jj não consigo mais voltar para o git
O jj é mais simples e ao mesmo tempo mais poderoso
working copy = commit deve ser entendido mais como “o index também é um commit”
Por exemplo, ao começar a trabalhar na feature x, você cria um novo commit com
jj new -m "working on feature x" trunke coloca mais um commit vazio por cimaO trabalho entra na working copy (
@) e você o “move” para o commit anterior (@-) com squash; em vez de opções complexas comoadd -peresetdo git, tudo é tratado como diff entre commitsEssa estrutura torna a divisão e a organização de commits mais flexíveis e poderosas do que o index do git
O problema da proliferação de commits está mais ligado à cultura de pull requests, e o jj só consegue resolver isso até certo ponto
A working copy não vai ser enviada cegamente para o GitHub; você pode revisar e organizar tudo ao adicionar a descrição do commit
Testei jj por alguns dias, mas já estou satisfeito o bastante com meu lazygit, meu workflow atual e meus scripts
O jj é interessante e tem ideias boas, mas, a menos que você esteja começando agora com controle de versão, falta motivação para mudar
Ainda uso o diff do Lazygit, mas ficar em detached HEAD não é problema nenhum
O JJ é muito compatível com git e facilita muito fazer tudo sem decorar comandos complexos
O fato de arquivos não commitados se moverem automaticamente junto ao trocar de branch é, para mim, o melhor recurso de todos
Fica muito fácil alternar entre desenvolvimento, correção de bug e mudanças de texto
Se um agente de IA fizer alterações, dá para usar worktrees separados
Também é ótimo poder colocar a descrição da mudança (= mensagem de commit) antes de terminar e já ver isso na árvore
No geral, o JJ é excelente