Colar uma tabela num pull request: o que parte, e os dois carateres que partem tudo
Publicado a 29/07/2026 · 15 min de leitura · Ferramentas para programadores
Daniel Okonkwo — Programador front-end e redator de Tecnologia na OneKitly
Desempenho web · Formatos de ficheiro
Verificado a partir de 4 fontes
Uma célula de tabela Markdown aceita tudo menos dois carateres. A barra vertical fecha a célula, por isso tem de se escrever \| — o conversor faz isso por si: cole USB-C | 2 m e devolve USB-C \| 2 m, que o GitHub mostra como uma só célula. A quebra de linha fecha a linha, e para ela não existe escape nenhum: uma célula com um retorno real é impossível na sintaxe de tabelas do GFM, por isso a ferramenta troca-a pela etiqueta HTML <br>, a única coisa que funciona. Debaixo do cabeçalho vem a linha separadora, e é obrigatória — uma linha de cabeçalho sem uma fila de travessões por baixo não é uma tabela, e o GitHub pinta-a como um parágrafo com barras. Essa fila leva também o alinhamento: --- deixa o valor por omissão do motor, :-- alinha à esquerda, --: à direita, :-: centra, e dois pontos em qualquer outro sítio não faz nada. A linha separadora tem de ter exatamente tantas células como o cabeçalho, ou a tabela não é reconhecida de todo. Os espaços que alinham as colunas são puramente cosméticos: | a | b | e |a|b| produzem HTML idêntico byte a byte, daí o interruptor «Alinhar colunas» e o facto de se poder desligar sem risco. Um pormenor sobre o escape, porque aqui a saída correta parece errada: a contrabarra leva escape antes da barra. Uma célula que já contém x \| y sai como x \\\| y, onde \\ é uma contrabarra literal e \| uma barra literal, por isso o GitHub mostra a única célula x \| y. Fazer o escape só da barra daria x \\| y — uma contrabarra literal seguida de um corte de célula real — e a coluna partia-se. Está tudo na ordem, e é por isso que uma tabela Markdown existente pode voltar a passar pelo conversor CSV e sair intacta.
Uma tabela Markdown proíbe exatamente dois carateres dentro de uma célula: a barra vertical e a quebra de linha. Aqui está o que cada um faz, como um conversor os trata, porque é que o escape tem de ser aplicado na ordem certa, e porque é que o alinhamento da fonte nunca conta.
Dois carateres, e apenas dois
Quase tudo atravessa uma célula de tabela Markdown sem dano. Acentos, ideogramas, emoji, acentos graves, asteriscos, parênteses retos, símbolos monetários, aspas: nada disso significa seja o que for para o analisador de tabelas, que só procura duas coisas. A barra vertical termina uma célula. A quebra de linha termina uma fila. É toda a gramática, e qualquer chatice que tenha ao colar uma tabela num pull request será um destes dois carateres a chegar onde o analisador não o esperava.
A barra vertical tem escape. Escreva \| e o analisador lê uma barra literal em vez de uma fronteira de coluna. O conversor aplica-o por si: os seus próprios dados de exemplo contêm a célula USB-C | 2 m, e passar o exemplo dá a linha | Câble | USB-C \| 2 m | 9.90 |, que é uma fila de três células e não de quatro. Dê-lhe uma célula que seja só uma barra e obtém \| sozinho, ainda uma célula. Esta parte é sólida, e é a que as tabelas escritas à mão mais falham: um comando de shell numa tabela de documentação — ps | grep node — ganha uma coluna em silêncio e empurra cada valor um lugar para a direita, um defeito que um revisor passa ao lado porque a tabela continua a parecer uma tabela.
A quebra de linha não tem escape, e esta é a parte que convém interiorizar: uma célula com um retorno de carro não é apenas incómoda na sintaxe de tabelas do GFM, é impossível. A fila acaba na quebra, ponto final. Há exatamente duas saídas honestas. Trocar a quebra pela etiqueta HTML <br>, que o GitHub permite dentro de uma célula e que o conversor aplica — um campo CSV entre aspas a dizer «linha um\nlinha dois» sai como linha um<br>linha dois numa só célula. Ou aceitar que aquele conteúdo não tem nada que fazer numa tabela e pô-lo numa lista ou num parágrafo por baixo. Tudo o resto é ilusão: não há truque de contrabarra, nem barra duplicada, nem marcador de continuação.
A linha separadora não é um adorno
O GitHub Flavored Markdown chama à fila de travessões sob o cabeçalho a linha delimitadora, e a especificação não deixa dúvidas: é feita de células cujo único conteúdo são travessões, com dois pontos opcionais no início, no fim, ou em ambos. Sem ela não há tabela. Uma linha de cabeçalho e três linhas de dados sem travessões pelo meio aparecem como quatro parágrafos de texto com barras dentro — e é por isso que uma tabela que parecia bem num editor e partiu no pull request quase sempre perdeu essa linha num copiar e colar.
Quatro formas de célula separadora significam quatro coisas diferentes, e o conversor oferece as quatro como definição de alinhamento. Um --- despido deixa o alinhamento ao motor, o que na prática quer dizer à esquerda em todos os motores que alguém usa. Dois pontos no início, :---, força à esquerda. Dois pontos no fim, ---:, força à direita, e é o que quer em qualquer coluna de números. Dois pontos em ambas as pontas, :---:, centra. Dois pontos no meio dos travessões não é alinhamento e não é válido — a célula tem de ser dois pontos, travessões, dois pontos, por essa ordem, e mais nada. Ponha a ferramenta em direita e uma tabela de duas colunas sai com | -----: | ---: | por baixo, e cada número da coluna alinha pelo último algarismo no resultado.
Uma regra apanha a maioria das falhas silenciosas: a linha separadora tem de ter exatamente tantas células como o cabeçalho, ou a tabela não é reconhecida de todo. A especificação di-lo sem rodeios, e o modo de falha é o pior possível — não obtém uma tabela partida, não obtém tabela nenhuma. Um cabeçalho de quatro colunas sobre uma separadora de três aparece como texto literal, barras incluídas. É exatamente o que acontece quando alguém acrescenta uma coluna à mão e se esquece dos travessões. O conversor não pode cometer esse erro porque constrói as duas filas a partir da mesma contagem de colunas, o que é um argumento decente a favor de gerar a tabela em vez de a editar.
O alinhamento é para si, não para o GitHub
O conversor tem um interruptor «Alinhar colunas», ligado por omissão, e não muda nada na tabela renderizada. Ligado, uma tabela de duas colunas sai como | Item | Qty |, | ------ | --- |, | Widget | 3 |, com as células quadradas. Desligado obtém | Item | Qty |, | --- | --- |, | Widget | 3 |, irregular. O GitHub produz HTML idêntico a partir de ambas. Os espaços existem para que um humano a ler o diff veja as colunas, e por mais nenhuma razão. Desligue o alinhamento quando a tabela é larga e o que se vai ler é o diff; deixe-o quando o ficheiro é editado à mão.
Há uma armadilha que convém conhecer se os seus dados não forem latinos. O alinhamento é calculado a contar carateres, e um carácter não é uma coluna. Dê ao conversor uma célula com dois emoji: conta dois, alinha por dois, e a fonte deixa de bater certo num editor onde cada emoji ocupa duas colunas de largura fixa. O mesmo acontece com texto chinês, japonês e coreano, e no sentido inverso com um é escrito como e mais acento combinante, que são dois carateres numa só coluna. Nada disto afeta a tabela renderizada, logo é um problema de legibilidade e não de correção — mas se produzir uma tabela larga de topónimos japoneses, não espere uma fonte penteada.
Fazer o escape do escape, e adivinhar o delimitador
Um conversor que troca cada barra por \| e para por aí engana-se em exatamente uma entrada, e é a que aparece assim que se reimporta uma tabela escrita pela própria pessoa: uma célula que já contém \|. Faça o escape só da barra e x \| y passa a x \\| y, onde a contrabarra duplicada é uma contrabarra literal e a barra atrás dela volta a estar viva — a coluna parte-se e nada avisa. A ordem tem de ser a inversa. Este conversor faz o escape primeiro da contrabarra e só depois da barra, por isso x \| y sai como x \\\| y, que parece uma contrabarra a mais e não é: o GFM lê \\ como uma contrabarra literal e \| como uma barra literal, e mostra a única célula x \| y.
A consequência é que a ida e volta é segura. Converta uns dados numa tabela Markdown, tire a tabela, guarde-a como CSV, volte a metê-la: as colunas que levavam barras regressam tal como saíram, e tudo o resto com elas. Vale mais do que parece, porque exportar uma tabela renderizada para uma folha de cálculo e voltar a importá-la é coisa banal assim que uma coluna muda de nome. A ferramenta irmã deste site, o gerador de tabelas Markdown, fecha o mesmo círculo pela outra ponta: o seu analisador lê \| como uma barra literal quando o delimitador é a barra e retira-lhe o escape à entrada, por isso uma tabela colada ali também volta idêntica.
O delimitador é adivinhado em vez de declarado, e o palpite faz-se sobre vários registos, não só sobre o cabeçalho. A ferramenta conta vírgulas, pontos e vírgulas, tabulações e barras fora de aspas em até cinco registos, e um delimitador que dá a mesma contagem em cada registo lido ganha a um que apenas é mais numeroso no primeiro. É isso que resolve um cabeçalho como A|B|C,D: sozinho parece três colunas separadas por barras, mas ponha por baixo filas com vírgulas e a vírgula ganha, porque é a contagem dela que se repete. Uma exportação francesa cujo cabeçalho é Nom;Prénom é detetada como ponto e vírgula de qualquer modo. A única coisa que o primeiro registo continua a decidir sozinho é quais os delimitadores candidatos: um cabeçalho que não contém nenhum dos quatro não deixa nada a desempatar, e o palpite recai na vírgula. Se a sua primeira linha for invulgar, defina o delimitador à mão.
Um fluxo que sobrevive à revisão
Exporte os dados como CSV em vez de copiar células de uma folha de cálculo, porque as regras de aspas de um ficheiro CSV são a única coisa que diz ao conversor onde acaba um campo com uma vírgula ou uma quebra de linha. Cole, confirme o separador detetado, escolha o alinhamento — à direita para números, por omissão para o resto — e leia as duas primeiras linhas de saída antes de copiar. Essas duas linhas são o cabeçalho e a linha separadora, e se tiverem um número diferente de barras nada se vai renderizar a jusante.
Depois procure as três células que dão problemas. Tudo o que leve uma barra: confirme que saiu como \| e não como um limite de coluna vivo, e tenha presente que uma célula que já levava uma contrabarra vê-a duplicada: \\\| é a saída correta, não um escape a mais. Tudo o que era multilinha: confirme que passou a <br> e decida se é mesmo isso que quer numa tabela. Tudo o que esteja vazio: uma célula vazia é perfeitamente legal e aparece vazia, por isso uma fila de brancos no meio da sua tabela é dado, não estrago. Se a tabela vai para um repositório e não para um comentário, faça o commit uma vez com o alinhamento ligado para o primeiro revisor ler o diff, e nunca mais a reformate — uma alteração só de espaços numa tabela são trinta linhas de ruído num pull request que não dizem nada.
| Conteúdo da célula | O que a ferramenta produz | Resultado |
|---|---|---|
| USB-C | 2 m | USB-C \| 2 m | Correto — uma célula com uma barra visível |
| Um campo entre aspas com um retorno de carro real | linha um<br>linha dois | Correto — a única coisa que as tabelas GFM permitem; uma quebra real é impossível |
| x \| y (já com escape) | x \\\| y | Correto — a contrabarra é escapada primeiro, o GitHub mostra a única célula x \| y |
| Um campo vazio | Nada entre as barras | Correto — uma célula vazia é legal e aparece vazia |
| Uma fila com menos campos do que o cabeçalho | Preenchida com células vazias até à fila mais larga | Correto — uma tabela irregular não renderizaria, por isso a ferramenta quadra-a |
| Dois emoji | Alinhada como se medisse duas colunas | Só cosmético — ocupam quatro; a tabela renderizada não é afetada |
Perguntas frequentes
- Posso pôr uma quebra de linha dentro de uma célula de tabela Markdown?
- Uma verdadeira, não. A quebra de linha é o que termina uma fila, por isso a sintaxe de tabelas não tem forma de exprimir uma célula que a contenha — não existe uma sequência de escape como \| para a barra. O contorno que o GitHub aceita é a etiqueta HTML <br>, que é o que este conversor substitui: um campo CSV entre aspas com uma quebra passa a ser uma célula a dizer linha um<br>linha dois. Dois limites honestos. Os motores que filtram HTML vão mostrar a etiqueta como texto literal, e uma célula com três ou quatro <br> costuma indicar que o conteúdo quer ser uma lista sob a tabela e não uma célula dentro dela.
- A minha tabela aparece como texto simples com barras. O que parti?
- Quase sempre a linha separadora. Ou falta por completo, ou tem um número de células diferente do cabeçalho — a especificação exige que o cabeçalho coincida com a linha delimitadora no número de células, e se não coincidir a tabela não é reconhecida e cai para parágrafo. Conte as barras na linha um e na linha dois da sua tabela; devem ser iguais. A outra causa frequente é uma linha em branco entre o cabeçalho e a separadora, que fecha o bloco antes de começar. Uma terceira, mais rara: as células separadoras só podem conter travessões e dois pontos opcionais nas pontas, por isso um espaço-travessão-espaço perdido ou um travessão longo colado pela correção automática de um editor invalida a fila.
- Os espaços que alinham as colunas contam?
- Não. | a | b | e |a|b| produzem o mesmo HTML no GitHub, e o interruptor «Alinhar colunas» existe apenas para que a fonte se leia bem num editor. O alinhamento tem, isso sim, um custo real num repositório: como a largura de cada coluna é a do seu valor mais longo, editar uma célula pode mudar o alinhamento da coluna inteira, e uma alteração de uma palavra transforma-se num diff que toca todas as filas. Se a tabela vive num ficheiro versionado e muda muitas vezes, gerá-la sem alinhamento dá diffs mais limpos. Se é escrita uma vez e lida por humanos no ficheiro cru, mantenha o alinhamento.
- Posso usar negrito, ligações ou código dentro de uma célula?
- Sim — a formatação em linha funciona normalmente dentro das células, por isso **negrito**, uma [ligação](https://example.com) e um `trecho de código` renderizam todos. As construções de bloco não: nem títulos, nem listas, nem blocos de código delimitados, nem tabelas aninhadas, porque todos precisam de quebras de linha que a fila não pode conter. A armadilha é um trecho de código com uma barra, como `ps | grep node`. Os acentos graves não protegem uma barra do analisador de tabelas — a célula é partida primeiro e o código interpretado depois — por isso tem mesmo de escrever `ps \| grep node`. É um dos poucos casos em que o escape tem de ser feito à mão, porque o conversor só escapa as barras que vê nos dados de origem.
- Porque é que o meu CSV francês saiu numa só coluna?
- Porque a linha de cabeçalho não deu nada a contar ao detetor, e é o cabeçalho que decide quais os delimitadores sequer em prova. A ferramenta conta vírgulas, pontos e vírgulas, tabulações e barras fora de aspas nos primeiros registos, e uma contagem que se repete ganha a outra que apenas é a maior na linha um; mas um delimitador que não aparece no primeiro registo nem candidato é. Uma folha de cálculo francesa ou alemã exporta com pontos e vírgulas, já que a vírgula é o separador decimal, e um cabeçalho Nom;Prénom é detetado bem. Um cabeçalho de uma só palavra sem separador, não: não há nada a contar, o palpite recai na vírgula e o ficheiro inteiro chega como uma coluna. Ponha a opção Delimitador em Ponto e vírgula à mão. O mesmo remédio serve para uma exportação por tabulações colada de um terminal, onde as tabulações podem ter virado espaços pelo caminho e já não resta mesmo delimitador nenhum para encontrar.
Artigos que podem interessar-lhe
Todos os guias →Ferramentas relacionadas
Isto descreve como se comportam um formato de ficheiro e um motor de renderização, verificado face à especificação citada e ao código da ferramenta tal como está hoje. Os motores divergem: GitHub, GitLab, um gerador de sites estáticos e a pré-visualização do seu editor são quatro implementações diferentes, e o que funciona numa pode não funcionar noutra. Nada aqui é uma garantia sobre a sua cadeia de publicação — teste o resultado onde ele vai mesmo ser publicado, e trate qualquer ferramenta, esta incluída, como algo a verificar e não a acreditar.
Fontes
- GitHub — GitHub Flavored Markdown Spec, version 0.29-gfm (2019-04-06), section 4.10 Tables (extension): the delimiter row consists of cells whose only content are hyphens with optional leading or trailing colons; the header row must match the delimiter row in the number of cells or the table is not recognised; a table with no body rows generates no tbody
- GitHub Docs — Organizing information with tables: the pipe must be escaped as \| inside a cell, cells can carry inline formatting and links, and the vertical bars of a row need not line up
- RFC Editor — RFC 4180, Common Format and MIME Type for Comma-Separated Values (CSV) Files, October 2005 — section 2 rules 5 to 7: a field containing the delimiter, a line break or a double quote must be enclosed in double quotes, and an embedded double quote is written twice
- CommonMark — CommonMark Spec version 0.31.2 (2024-01-28): the core specification defines leaf and container blocks and contains no table construct — pipe tables are an extension, which is why a table that renders on GitHub may not render in a strict CommonMark processor
Detetaste um erro neste artigo?