Uma lista curta e incompleta, sem utilidade para ninguém. Veja bem, os mantenedores modernos do Git estão fazendo um ótimo trabalho e removeram muitas arestas. Não preciso usar apenas –ff-only ou configurar precomposeunicode e, para todos os outros momentos difíceis, geralmente existe uma opção de comando para torná-los menos terríveis. Ao mesmo tempo, o Git tem problemas pequenos e grandes, e muitas das falhas são agora fundamentais. Deixe-me explicar: sha1 foi uma má escolha na época, sim, sha1 já era considerado obsoleto pela comunidade criptográfica antes do Git começar a usá-lo, e sim, era sabido que qualquer primitiva criptográfica tem um tempo de vida útil e qualquer software que dependa dela deve se preparar para o pior. O Git escolheu usar a pior opção desde o primeiro dia, e esse não é o problema. O problema é que o uso do sha1 pelo Git é muito difícil de ser alterado, pois certos detalhes estão embutidos nos formatos em disco. A moral aqui é “trate seus identificadores como strings opacas” junto com “às vezes um prefixo sha1 não prejudica ninguém”. Enfim, onde estávamos? Ah, formatos em disco.
Cada formato de dados no Git é único. Cada estrutura de dados serializada em disco foi elaborada pelos melhores artesãos de código conhecidos pelo homem, é por isso que uma das extensões do Git envolve “inserir coisas depois de um nome de arquivo que termina com um caractere nulo” porque “apenas use json” é um pouco demais para suportar. Eu entendo a aversão ao XML e até o JSON é ruim em relação a carimbos de data e hora, mas bem, não há motivo para o Git não poder usar um formato para quase tudo, exceto que o Git é escrito em C e, portanto, não podemos ter coisas boas. Não altere seu e-mail ou seu nome, acho que quando você lê lkml, a ideia de spam não é tão preocupante, mas colocar nomes e e-mails em cada commit significa que toda vez que alguém muda de nome ou de e-mail, eles podem muito bem ser uma pessoa completamente diferente para o repositório. Com certeza, quando você armazena nomes nos arquivos, precisa reescrever o histórico quando alguém muda de endereço de e-mail, mas em outro universo, você usaria um UUID e um arquivo chamado .gitauthors que mapeia um para o outro – e você nem precisaria colocar endereços de e-mail no arquivo, poderia simplesmente colocar URLs do GitHub ou algo similar. Em uma nota semelhante, seria bom poder ter vários autores em uma mensagem de commit. É uma das poucas vezes no Git em que apenas um de cada coisa é permitido. Existem dois mecanismos diferentes para quase todos os recursos, não que haja muitos recursos, mas vale ressaltar que os submódulos e o LFS funcionam de maneiras completamente diferentes. Submódulos? Eles são um arquivo no repositório com um tipo especial dentro das árvores. O Git sabe, ao fazer checkout, que o arquivo é especial e pode executar outros comandos. Em seguida, ele não executa esses comandos e a pessoa que usa submódulos começa a chorar. Enfim, LFS? Manipulado por um programa de filtro definido em .gitattributes. Ao contrário dos atributos do Git, esse modo permite que os usuários realmente especifiquem o comportamento, em vez de estar escondido em arquivos ocultos no armazenamento de objetos ou no diretório .git. A razão pela qual o LFS e os submódulos funcionam de maneira diferente é que eles são implementados em níveis diferentes do Git. Os submódulos estão dentro do Git, o LFS é escrito sobre as ferramentas C e apenas um dos mecanismos é projetado para outros programas usarem. Há uma história semelhante com os cabeçalhos de commit do Git e os cabeçalhos de trailer de commit do Git. Os trailers podem ser editados pelo usuário e os cabeçalhos embutidos não são fáceis de editar, alterar ou adicionar. Portanto, ninguém se preocupa com isso. Existem duas maneiras de usar o Git, e ambas são ruins também. Ao escolher entre microsserviços e monorepositórios, é uma escolha falsa. Na verdade, você está se perguntando “como contornamos o fato de o Git não suportar checkouts de subárvore” ou “como contornamos o fato de os submódulos serem problemáticos”. Em um mundo melhor, o Git teria checkouts de subárvore. Isso resolveria muitos problemas. Em um mundo ainda melhor, os submódulos do Git funcionariam, mas por enquanto nos contentamos em usar outro gerenciador de pacotes e rezar pela morte. Em uma nota semelhante, rebases versus merges. O Git força você a fazer uma escolha. Use merge e tenha um histórico barulhento, mas representativo. Use rebases e perca parte do trabalho, mas o log é muito mais fácil de navegar. A verdade é que poderíamos ter o melhor dos dois mundos. O Git para Windows faz commits de “merge rebase” que preservam o histórico durante os rebases: ele cria um commit de merge com a versão mais recente e reproduz os commits existentes acima. Também poderíamos ter uma versão do git log que não fizesse os merges parecerem ruins, mas esse é outro problema completamente diferente. A filosofia do Unix é sobre construir conjuntos de ferramentas, não aplicativos. Veja bem, a ideia por trás da filosofia do Unix é simples: sua ferramenta provavelmente está gerando um arquivo de saída. Você pode usar grep, diff, less, cut e várias outras ferramentas para fazer as coisas acontecerem. Isso é bem legal na verdade. O Git é um pouco um exemplo da filosofia do Unix. Não é um único comando grande, mas muitos programas C menores unidos com o bash. Se você quiser uma saída paginada, execute o less, se quiser encontrar coisas, use o grep, e se quiser criar um recurso: basta criá-lo com o bash. Ele evita formatos binários em favor de texto, abomina interfaces de usuário cativas e despeja quase tudo no sistema de arquivos. É uma ótima maneira de construir um conjunto de ferramentas, mas uma maneira terrível de construir ferramentas: as mensagens de erro são estranhas, os problemas são difíceis de se recuperar, e Deus te ajude se você executar o comando errado no lugar errado. Quando se trata de adicionar recursos, você está limitado: não pode adicionar recursos transversais. Não pode ter modos em que alguns comandos sejam válidos e outros não. Uma boa ferramenta deve tornar essas coisas impossíveis. O Git não é uma boa ferramenta e a arquitetura do Git significa que esses tipos de decisões de UX são quase impossíveis de realizar. Em outras palavras, você já cometeu acidentalmente um commit durante um rebase? Ou cometeu acidentalmente um conflito? Azar o seu, amigo. Em outro mundo, seu sistema de controle de versão saberia “estou no modo de rebase” e não deixaria você estragar todo o repositório, mas não estamos no bom universo. Antes de abandonar a filosofia do Unix, há mais dois pontos importantes. Primeiro: os comandos do Git são nomeados de acordo com a implementação, não com o uso, e não há absolutamente nenhuma desculpa para isso. Segundo: arquivos planos são meio chatos se seu estado for corrompido. Fui mimado pelo SQLite. Você pressionou Control-C? Más notícias, amigo, seu repositório está ferrado. O Git, apesar de ser rotulado como um banco de dados, não está realmente interessado em transações, atomicidade ou durabilidade tanto quanto você esperaria. O mais próximo que você chega de um log de gravação antecipada é um reflog para branches. Não estou dizendo que o Git precisa ser tão bom quanto o SQLite, mas seria bom não viver com medo de corromper acidentalmente meu repositório toda vez que cancelo um comando. Pelo menos, se eu fizer o comando errado, tenho a chance de desfazer meu trabalho. Em uma nota semelhante, desfazer e refazer seriam muito úteis. Mesmo que fosse apenas git commit –undo e funcionasse apenas 80% das vezes, seria uma grande melhoria em relação à situação atual, que é ruim, aliás. O Git é feito de pequenas falhas. Há partes em que você não pode fazer check-in de um diretório vazio ou como você pode definir arquivos para serem ignorados, mas não arquivos para serem incluídos. As configurações de ignorar deveriam ter padrões, mas não têm, e grande parte do fluxo de trabalho moderno do Git envolve ativar um monte de configurações e flags que deveriam estar lá desde o início. Eu não queria mencionar a filosofia do Unix novamente, mas quando você constrói seu software como um conjunto de ferramentas para automação, é muito mais difícil fazer alterações quebradas nas coisas. Os usuários geralmente são melhores em lidar com as diferenças do que os scripts bash. Geralmente. De qualquer forma, uma das maiores razões pelas quais não podemos simplesmente consertar o Git é que construímos um pequeno império de bash em cima dele, que desmorona se você olhar para ele de maneira estranha. Temos apenas…