Sobre o projeto
9vcs é um sistema de controle de versão construído sobre o 9P, o protocolo do Plan 9, através da biblioteca Go 9p do autor. Destina-se a uma pequena equipe confiável que deseja um controle de versão real sem uma plataforma de hospedagem. O histórico é mantido como um conjunto de patches endereçados por conteúdo, em vez de snapshots; o README aponta para o PLAN.md para a justificativa do design e limita-se ao uso prático. O vocabulário deliberadamente não segue o modelo do GitHub: não há clone, push, pull, fork ou pull request, e uma folha de dicas mapeia os termos usuais para os equivalentes do 9vcs.
Requisitos e instalação
O único requisito é o Go 1.26.5 ou posterior. Tanto o 9vcs quanto a biblioteca 9p na qual ele se baseia são em Go puro, utilizando apenas a biblioteca padrão, sem daemon, banco de dados ou serviços externos. Binários pré-compilados são publicados na página de Releases como arquivos tar.gz para linux/amd64, linux/arm64, darwin/arm64 e darwin/amd64, cada um com um checksum .sha256 para verificação; o arquivo contém o binário, a LICENSE e o README. A compilação a partir do código-fonte é feita com um único comando go build contra cmd/9vcs. Alternativamente, alguns instaladores estão disponíveis.
Fluxo de trabalho solo
Após executar init em um diretório, o comando status imprime uma linha por caminho alterado, usando A para novo, M para modificado, D para deletado e U para conflito não resolvido; ele reporta apenas o que está "sujo", não o diff. Movimentações não são rastreadas como renomeações — um arquivo movido aparece como uma deleção mais uma adição, correspondendo a como o patch subjacente o armazena. O diff mostra alterações ao nível de linha na árvore de trabalho, pode fazer diff contra outro ponto ou comparar dois pontos diretamente sem envolver a árvore de trabalho. O log lista os patches registrados, do mais novo para o mais antigo, com autor, fingerprint ou status de assinatura, e os caminhos afetados. O record cria um patch. Não há área de staging ou etapa de index: a própria árvore de trabalho é a área de staging, e o record a compara com o head atual.
Branches e merge
O branch lista, cria a partir do HEAD ou de outra branch ou hash, e o checkout alterna ou cria e alterna com a flag -b. O merging produz conflitos reais de grafo de patches — forks ao nível de linha, conflitos binários com um arquivo sidecar de comparação e corridas de modificação/deleção — em vez de um diff de texto raso de três vias. Um merge limpo é concluído com record. Um merge com conflito deixa marcadores de conflito inline nos arquivos de texto afetados, enquanto conflitos binários recebem um arquivo sidecar nomeado conforme o caminho e um hash curto para comparação; o usuário edita e então registra. Um merge pode ser abortado, restaurando a árvore de trabalho exatamente ao seu estado pré-merge e limpando o estado do merge, independentemente de o merge ter vindo do comando merge ou do apply.
Padrões de ignore
Um arquivo .9vcsignore na raiz do repositório funciona como o .gitignore e destina-se a ser registrado e compartilhado. Um padrão por linha; linhas em branco e comentários com hash são ignorados. Padrões sem barra correspondem em qualquer profundidade, padrões contendo barra são ancorados à raiz do repositório, e uma barra final restringe a correspondência a um diretório real. Negação com ponto de exclamação e padrões de estrela dupla não são suportados explicitamente. Os padrões de ignore apenas mantêm novos arquivos fora do record e diff, e adicionar um padrão posteriormente nunca faz com que um arquivo já registrado apareça como deletado.
Uso em equipe
Cada instalação gera um par de chaves Ed25519 de longa duração no primeiro uso, e o identity show imprime o fingerprint que os colegas trocam fora de banda para autorizar uns aos outros. Quem hospeda o histórico compartilhado executa o serve em uma porta; o servidor lê o arquivo .9vcs/authorized-peers no repositório atual, com uma linha de fingerprint e permissão por colega, onde as permissões são read (apenas pull de histórico), propose (leitura mais postagem de um bundle assinado na área de ofertas) e write (tudo, incluindo a movimentação de uma ref de branch). Não há comando add-collaborator — trata-se apenas de editar esse arquivo — e o arquivo é lido uma vez na inicialização, portanto, as alterações exigem um reinício, o que é importante ao revogar uma chave possivelmente comprometida.
O serve executa em primeiro plano, sem daemon de segundo plano. Um push de rede recusa-se a mover a branch atualmente verificada na máquina que serve, portanto, o host deve manter uma branch diferente verificada ou usar um diretório reservado para servir. Um novo colega começa com init e import, passando o fingerprint de um peer, um host e porta, além do nome da branch; o import é apenas fast-forward e puxa a branch e cada patch e blob de que ela depende transitivamente. O reconcile é o comando de sincronização contínua: ele faz pull se o peer estiver à frente, push se o lado local estiver, e em caso de divergência real, busca o que está faltando e pede ao usuário para fazer o checkout e merge localmente, em vez de resolver via rede. Ambos os comandos podem fixar um fingerprint de peer explicitamente; caso contrário, usam um armazenamento local de trust-on-first-use que solicita a confirmação uma vez para um novo endereço, verifica endereços conhecidos silenciosamente e recusa veementemente um fingerprint que mude repentinamente.
Troca offline e propostas
Bundles movem alterações sem qualquer servidor em execução: export escreve um bundle assinado em um arquivo para e-mail, chat ou mídia removível, e o destinatário o inspeciona com bundle show (assinante, mensagem, patches), importa-o para verificar a assinatura e armazená-lo localmente sem tocar em nenhuma ref, revisa com diff e então o aplica e registra. O import nunca move uma ref por si só. Peers com apenas permissão de propose podem enviar diretamente usando offer, que posta um bundle assinado no servidor do mantenedor; o mantenedor lista as ofertas pendentes, aplica uma para buscar, verificar e armazenar localmente, integra-a com apply e a remove da fila. Como as ofertas existem apenas dentro do namespace do servidor ativo, o mantenedor conecta-se à sua própria instância de serve e, portanto, precisa de seu próprio fingerprint no arquivo authorized-peers também.
Janelas para 9sh e manipulação de namespace
Normalmente, o repositório é resolvido subindo a partir do diretório atual, como no git. Dentro do 9sh, um shell no estilo Plan 9, a flag -C colocada antes do nome do comando oferece uma segunda rota: ela tenta o caminho contra o namespace do 9sh primeiro — um caminho relativo sob local, ou um caminho absoluto que pode resolver para qualquer coisa que o 9sh tenha vinculado — antes de recorrer a um caminho literal do SO. Fora de uma sessão 9sh, a flag comporta-se como git -C.
Recuperação
Caminhos de recuperação documentados cobrem a abortagem de um merge ou apply, o registro ou descarte manual de alterações não commitadas que bloqueiam um checkout, merge ou apply, a restauração de caminhos individuais para seu estado registrado no head com restore (um caminho sem estado registrado é removido, portanto, reverter uma renomeação significa nomear ambos os caminhos) e a nova fixação de um fingerprint de peer que mudou legitimamente.
Status do projeto
O README distingue o uso do 9vcs com uma equipe do desenvolvimento da própria ferramenta, que segue o desenvolvimento baseado em trunk com branches de curta duração, um master protegido onde ninguém faz push diretamente, CI cobrindo build, vet, gofmt e testes com race habilitado antes do merge, merges apenas do tipo squash e deleção automática de branches. O versionamento segue o semver para releases, atualmente na faixa v0.x. Abaixo de v1.0.0, não há promessa de compatibilidade para o formato de patch e bundle no disco, que pode mudar sem um caminho de migração; a partir de v1.0.0, qualquer patch ou bundle registrado sob um formato lançado deverá permanecer decodificável, com futuras mudanças incompatíveis tratadas por despacho de versão real e ferramentas de migração fornecidas. Um changelog registra o que cada release entrega.
Comments
0 Rating appears after 10 ratings
Sign in to join the discussion.