Também disponível em: English · Español · Français · العربية
Gerador de .gitattributes
Gere um arquivo .gitattributes e teste qualquer caminho: qual linha vence, e quais quebras de linha o git vai guardar e entregar a quem clonar o seu repositório.
O que é um arquivo .gitattributes
Um arquivo .gitattributes diz ao git como tratar caminhos específicos. Ele fica no seu repositório, é commitado como qualquer outra coisa, e decide quais arquivos contam como texto, quais são binários, como são comparados e mesclados e — a parte pela qual quase todo mundo chega aqui — o que acontece com as quebras de linha na entrada e na saída.
O formato é um padrão seguido de atributos, uma regra por linha, exatamente o formato de um .gitignore. Essa familiaridade é a maior parte do motivo de dar errado: os padrões são mesmo os do gitignore, mas uma peça da sintaxe significa algo completamente diferente, e o atributo que todo mundo procura faz menos do que o nome sugere.
Esta ferramenta faz as duas metades. Você edita o arquivo, informa um caminho, e ela diz qual linha vence, em que estado cada atributo fica, e o que o git vai realmente guardar e extrair — inclusive para a configuração na máquina de outra pessoa, que você não controla.
Como usar
- Comece pelo arquivo mostrado. É um padrão razoável: normalizar texto, fixar scripts de shell em LF e arquivos .bat em CRLF, marcar os binários de sempre e impedir o git de comparar um arquivo de lock. Edite direto.
- Digite um caminho para testar. Relativo à raiz do repositório. Cada atributo que casa aparece com o padrão que o forneceu, então você vê qual linha realmente venceu, e não qual você pretendia.
- Mude o core.autocrlf dele. Esses três botões representam a configuração na máquina de quem clonar o seu repositório. Observe o painel de quebras de linha enquanto os aperta — se ele se mexer, os seus arquivos dependem de uma configuração que você não enxerga.
O que as quebras de linha fazem de verdade, medido
Esta parte foi medida, não lida. O mesmo arquivo com CRLF foi commitado em vinte e um repositórios descartáveis — todas as combinações de três configurações de core.autocrlf e sete linhas de atributos diferentes — e depois o git foi perguntado sobre o que havia no banco de objetos e, após o arquivo ser apagado e restaurado, sobre o que havia na cópia de trabalho.
Sem um .gitattributes, o que o seu repositório guarda depende de quem commitou. O mesmo arquivo entra como CRLF com core.autocrlf=false e como LF com true ou input. Nada na sua própria cópia diz qual aconteceu, e é por isso que isso aparece como um pull request cheio de arquivos inteiros alterados em vez de como um erro. Acrescente qualquer atributo text e essa variação some: as três configurações produziram bytes idênticos.
A surpresa é o que o text=auto não faz. Ele fixa o repositório e deixa a cópia de trabalho em paz: ao ser extraído de novo, o mesmo arquivo chega como CRLF em duas das três configurações e como LF na terceira. Ou seja, um time que acrescenta uma única linha de text=auto deixou o histórico consistente e não fez as cópias de trabalho concordarem. Só eol=lf ou eol=crlf fixam as duas pontas.
E eol=crlf guarda LF. É uma instrução sobre a extração, não sobre o armazenamento, então se você inspecionar o blob vai encontrar LF e concluir que a linha não fez nada. Fez: só fez na outra ponta.
Os padrões são os do gitignore, com uma exceção que falha em silêncio
O casamento se comporta como esse formato familiar sugere. Um padrão com barra é medido a partir do diretório do próprio .gitattributes; um sem barra casa com um nome em qualquer profundidade abaixo. O asterisco duplo cruza diretórios e — medido, porque é fácil supor o contrário — também casa com nenhum diretório, então sub/**/*.txt cobre sub/a.txt tanto quanto sub/deep/a.txt. Classes de caracteres funcionam.
A precedência é por posição, não por especificidade: vence a última linha que casar, e um padrão ser mais preciso não conta nada. É a mesma regra do EditorConfig, e a mesma que as pessoas entendem ao contrário nos dois. Entre arquivos, um .gitattributes mais profundo na árvore vence um mais raso, seja qual for a ordem em que o git os leia.
A exceção é o ponto de exclamação. Num .gitignore, um ! inicial nega o padrão. Num .gitattributes ele não é suportado de jeito nenhum: uma linha que começa com ! não faz nada, e o valor anterior continua valendo. Não há erro nem aviso. Para tirar um atributo você põe um hífen antes do atributo, e não do padrão, e para devolvê-lo a não especificado põe ali o ponto de exclamação.
Mais uma coisa que vale saber, porque é a linha mais comum de qualquer arquivo real: binary não é um atributo, é uma macro. Ela se expande para desligar text, diff e merge de uma vez, e é por isso que marcar um caminho como binary sobrescreve corretamente um text=auto anterior em vez de conviver com ele.
Limitações honestas
Isto modela as regras, não o seu repositório. Projetos reais podem ter vários .gitattributes em profundidades diferentes, e o git também lê .git/info/attributes e um arquivo global fora do repositório, nenhum dos quais é commitado nem existe para mais ninguém. O que está modelado aqui é o arquivo commitado e as regras dentro dele, que é onde a parte confusa quase sempre mora.
O painel de quebras de linha prevê o que o git faz com um arquivo de texto que hoje tem CRLF, porque é com esse caso que as pessoas chegam. Um arquivo que já é só LF, ou um com quebras misturadas, se comporta de maneiras que o painel não tenta desenhar.
Mudar um .gitattributes não muda arquivos já commitados. O git aplica as regras novas na próxima vez que um arquivo passa por ele, então um repositório que vinha guardando CRLF continua guardando CRLF até algo reescrever esses arquivos. É para isso que existe a opção de renormalizar, e ela produz exatamente o diff enorme que você esperaria — por isso vale fazer de propósito, e não descobrir depois.
Por que é grátis?
Roda no seu navegador. Casar um caminho com um padrão não custa nada na sua própria máquina, então não há servidor a pagar nem conta a criar.
Nada do que você digita é enviado, guardado ou registrado. Nomes de arquivo e a estrutura de diretórios dizem bastante sobre uma base de código privada, e o jeito confiável de manter isso privado é não mandar para lugar nenhum.