Pegar una tabla en un pull request: qué se rompe y los dos caracteres que lo rompen
Publicado el 29/7/2026 · 15 min de lectura · Herramientas para desarrolladores
Daniel Okonkwo — Desarrollador front-end y redactor de Tecnología en OneKitly
Rendimiento web · Formatos de archivo
Verificado con 4 fuentes
Una celda de tabla Markdown admite todo menos dos caracteres. La barra vertical cierra la celda, así que hay que escribirla \| — el conversor lo hace por ti: pega USB-C | 2 m y devuelve USB-C \| 2 m, que GitHub muestra como una sola celda. El salto de línea cierra la fila, y para él no existe ningún escape: una celda con un retorno de carro real es imposible en la sintaxis de tablas de GFM, así que la herramienta lo sustituye por la etiqueta HTML <br>, lo único que funciona. Bajo la cabecera va la fila separadora, y es obligatoria: una línea de cabecera sin una hilera de guiones debajo no es una tabla, y GitHub la pinta como un párrafo con barras. Esa fila lleva además la alineación: --- deja el valor por defecto del motor, :-- alinea a la izquierda, --: a la derecha, :-: centra, y un dos puntos en cualquier otro sitio no hace nada. La fila separadora debe tener exactamente tantas celdas como la cabecera, o la tabla no se reconoce en absoluto. Los espacios que cuadran las columnas son puramente cosméticos: | a | b | y |a|b| producen un HTML idéntico byte a byte, de ahí el interruptor «Rellenar columnas» y que se pueda quitar sin riesgo. Un detalle sobre el escape, porque aquí la salida correcta parece equivocada: la contrabarra se escapa antes que la barra. Una celda que ya contiene x \| y sale como x \\\| y, donde \\ es una contrabarra literal y \| una barra literal, así que GitHub muestra la única celda x \| y. Escapar solo la barra daría x \\| y —una contrabarra literal seguida de un corte de celda real— y la columna se partiría. Todo está en el orden, y por eso una tabla Markdown existente puede volver a pasar por el conversor CSV y salir intacta.
Una tabla Markdown prohíbe exactamente dos caracteres dentro de una celda: la barra vertical y el salto de línea. Aquí está qué hace cada uno, cómo los trata un conversor, por qué el escape debe aplicarse en el orden correcto, y por qué el relleno nunca importa.
Dos caracteres, y solo dos
Casi todo atraviesa una celda de tabla Markdown sin daño. Acentos, ideogramas, emoji, acentos graves, asteriscos, corchetes, símbolos de moneda, comillas: nada de eso significa nada para el analizador de tablas, que solo busca dos cosas. La barra vertical termina una celda. El salto de línea termina una fila. Esa es toda la gramática, y cualquier problema que tengas pegando una tabla en un pull request será uno de esos dos caracteres apareciendo donde el analizador no lo esperaba.
La barra vertical tiene escape. Escribe \| y el analizador lee una barra literal en lugar de un límite de columna. El conversor lo aplica por ti: sus propios datos de ejemplo contienen la celda USB-C | 2 m, y pasar el ejemplo da la fila | Câble | USB-C \| 2 m | 9.90 |, que es una fila de tres celdas y no de cuatro. Dale una celda que sea solo una barra y obtienes \| a solas, todavía una celda. Esta parte es sólida, y es la que más fallan las tablas escritas a mano: un comando de shell en una tabla de documentación —ps | grep node— gana una columna en silencio y empuja cada valor un puesto a la derecha, un defecto que un revisor pasa por alto porque la tabla sigue pareciendo una tabla.
El salto de línea no tiene escape, y esta es la parte que conviene interiorizar: una celda con un retorno de carro no es solo incómoda en la sintaxis de tablas de GFM, es imposible. La fila termina en el salto, punto. Hay exactamente dos salidas honestas. Sustituir la ruptura por la etiqueta HTML <br>, que GitHub permite dentro de una celda y que el conversor aplica: un campo CSV entrecomillado que diga «línea uno\nlínea dos» sale como línea uno<br>línea dos en una sola celda. O aceptar que ese contenido no pinta nada en una tabla y ponerlo en una lista o un párrafo debajo. Todo lo demás es ilusión: no hay truco de contrabarra, ni barra doblada, ni marcador de continuación.
La fila separadora no es un adorno
GitHub Flavored Markdown llama a la hilera de guiones bajo la cabecera la fila delimitadora, y la especificación no deja lugar a dudas: está hecha de celdas cuyo único contenido son guiones, con un dos puntos opcional al principio, al final, o en ambos. Sin ella no hay tabla. Una línea de cabecera y tres líneas de datos sin guiones entre medias se muestran como cuatro párrafos de texto con barras dentro, y por eso una tabla que se veía bien en un editor y se rompió en el pull request casi siempre perdió esa línea en un copiar y pegar.
Cuatro formas de celda separadora significan cuatro cosas distintas, y el conversor ofrece las cuatro como ajuste de alineación. Un --- pelado deja la alineación al motor, lo que en la práctica quiere decir a la izquierda en todos los motores que alguien usa. Un dos puntos al principio, :---, fuerza izquierda. Un dos puntos al final, ---:, fuerza derecha, y es el que quieres en cualquier columna de números. Dos puntos en ambos extremos, :---:, centra. Un dos puntos en medio de los guiones no es alineación y no es válido: la celda tiene que ser dos puntos, guiones, dos puntos, en ese orden, y nada más. Pon la herramienta en derecha y una tabla de dos columnas sale con | -----: | ---: | debajo, y cada número de la columna cuadra por su última cifra en el resultado.
Una regla atrapa la mayoría de los fallos silenciosos: la fila separadora debe tener exactamente tantas celdas como la cabecera, o la tabla no se reconoce en absoluto. La especificación lo dice sin rodeos, y el modo de fallo es el peor posible: no obtienes una tabla rota, no obtienes tabla. Una cabecera de cuatro columnas sobre una separadora de tres se muestra como texto literal, barras incluidas. Es exactamente lo que pasa cuando alguien añade una columna a mano y se olvida de los guiones. El conversor no puede cometer ese error porque construye ambas filas a partir del mismo recuento de columnas, lo que es un argumento decente a favor de generar la tabla en vez de editarla.
El relleno es para ti, no para GitHub
El conversor tiene un interruptor «Rellenar columnas», activado por defecto, y no cambia nada de la tabla renderizada. Activado, una tabla de dos columnas sale como | Item | Qty |, | ------ | --- |, | Widget | 3 |, con las celdas cuadradas. Desactivado obtienes | Item | Qty |, | --- | --- |, | Widget | 3 |, desigual. GitHub produce un HTML idéntico con ambas. Los espacios existen para que un humano leyendo el diff vea las columnas, y por ninguna otra razón. Quita el relleno cuando la tabla es ancha y lo que se va a leer es el diff; déjalo cuando el fichero se edita a mano.
Hay una trampa que conviene conocer si tus datos no son latinos. El relleno se calcula contando caracteres, y un carácter no es una columna. Dale al conversor una celda con dos emoji: cuenta dos, rellena a dos, y la fuente deja de cuadrar en un editor donde cada emoji ocupa dos columnas de ancho fijo. Lo mismo pasa con texto chino, japonés y coreano, y en sentido contrario con una é escrita como e más acento combinante, que son dos caracteres en una sola columna. Nada de esto afecta a la tabla renderizada, así que es un problema de legibilidad y no de corrección, pero si produces una tabla ancha de topónimos japoneses no esperes una fuente peinada.
Escapar el escape, y adivinar el delimitador
Un conversor que cambia cada barra por \| y se detiene ahí se equivoca en exactamente una entrada, y es la que aparece en cuanto vuelves a importar una tabla que escribiste tú: una celda que ya contiene \|. Escapa solo la barra y x \| y se convierte en x \\| y, donde la contrabarra duplicada es una contrabarra literal y la barra que va detrás vuelve a estar viva: la columna se parte y nada avisa. El orden tiene que ser el contrario. Este conversor escapa primero la contrabarra y después la barra, así que x \| y sale como x \\\| y, que parece una contrabarra de más y no lo es: GFM lee \\ como una contrabarra literal y \| como una barra literal, y muestra la única celda x \| y.
La consecuencia es que la ida y vuelta es segura. Convierte unos datos en una tabla Markdown, saca la tabla, guárdala como CSV, vuelve a meterla: las columnas que llevaban barras regresan tal y como salieron, y todo lo demás con ellas. Vale más de lo que parece, porque exportar una tabla renderizada a una hoja de cálculo y volver a importarla es algo corriente en cuanto una columna cambia de nombre. La herramienta hermana de este sitio, el generador de tablas Markdown, cierra el mismo círculo por el otro extremo: su analizador lee \| como una barra literal cuando el delimitador es la barra y le quita el escape a la entrada, así que una tabla pegada allí también vuelve idéntica.
El delimitador se adivina en vez de declararse, y la adivinanza se hace sobre varios registros, no solo sobre la cabecera. La herramienta cuenta comas, puntos y coma, tabulaciones y barras fuera de comillas en hasta cinco registros, y un delimitador que da el mismo recuento en cada registro leído gana a uno que simplemente es más numeroso en el primero. Eso es lo que resuelve una cabecera como A|B|C,D: por sí sola parece tres columnas separadas por barras, pero pon debajo filas con comas y gana la coma, porque es su recuento el que se repite. Una exportación francesa cuya cabecera es Nom;Prénom se detecta como punto y coma en cualquier caso. Lo único que el primer registro sigue decidiendo solo es qué delimitadores son candidatos: una cabecera que no contiene ninguno de los cuatro no deja nada que dirimir, y la adivinanza recae en la coma. Si tu primera línea es rara, fija el delimitador a mano.
Un flujo que sobrevive a la revisión
Exporta los datos como CSV en vez de copiar celdas de una hoja de cálculo, porque las reglas de comillas de un fichero CSV son lo único que le dice al conversor dónde acaba un campo con una coma o un salto de línea. Pégalo, comprueba el separador que detectó, elige la alineación —derecha para números, por defecto para lo demás— y lee las dos primeras líneas de salida antes de copiar. Esas dos líneas son la cabecera y la fila separadora, y si tienen distinto número de barras nada se renderizará después.
Luego busca las tres celdas que dan guerra. Todo lo que lleve una barra: comprueba que salió como \| y no como un límite de columna vivo, y ten presente que una celda que ya llevaba una contrabarra la ve duplicada: \\\| es la salida correcta, no un escape de más. Todo lo que era multilínea: comprueba que se volvió <br> y decide si eso es de verdad lo que quieres en una tabla. Todo lo que esté vacío: una celda vacía es perfectamente legal y se muestra vacía, así que una fila de blancos en medio de tu tabla es dato, no daño. Si la tabla va a un repositorio y no a un comentario, súbela una vez con el relleno activado para que el primer revisor lea el diff, y no la reformatees nunca más: un cambio de solo espacios en una tabla son treinta líneas de ruido en un pull request que no dicen nada.
| Contenido de la celda | Lo que emite la herramienta | Resultado |
|---|---|---|
| USB-C | 2 m | USB-C \| 2 m | Correcto: una celda con una barra visible |
| Un campo entrecomillado con un retorno de carro real | línea uno<br>línea dos | Correcto: lo único que permiten las tablas GFM; un salto real es imposible |
| x \| y (ya escapado) | x \\\| y | Correcto: la contrabarra se escapa primero, GitHub muestra la única celda x \| y |
| Un campo vacío | Nada entre las barras | Correcto: una celda vacía es legal y se muestra vacía |
| Una fila con menos campos que la cabecera | Rellenada con celdas vacías hasta la fila más ancha | Correcto: una tabla irregular no se renderizaría, así que la herramienta la cuadra |
| Dos emoji | Rellenada como si midiera dos columnas | Solo cosmético: ocupan cuatro; la tabla renderizada no se ve afectada |
Preguntas frecuentes
- ¿Puedo poner un salto de línea dentro de una celda de tabla Markdown?
- Uno real, no. El salto de línea es lo que termina una fila, así que la sintaxis de tablas no tiene forma de expresar una celda que lo contenga: no existe una secuencia de escape como \| para la barra. El apaño que GitHub acepta es la etiqueta HTML <br>, que es lo que sustituye este conversor: un campo CSV entrecomillado con una ruptura pasa a ser una celda que dice línea uno<br>línea dos. Dos límites honestos. Los motores que filtran HTML mostrarán la etiqueta como texto literal, y una celda con tres o cuatro <br> suele indicar que el contenido quiere ser una lista bajo la tabla y no una celda dentro.
- Mi tabla se muestra como texto plano con barras. ¿Qué he roto?
- Casi siempre la fila separadora. O falta del todo, o tiene un número de celdas distinto del de la cabecera: la especificación exige que la cabecera coincida con la fila delimitadora en número de celdas, y si no coincide la tabla no se reconoce y cae a párrafo. Cuenta las barras de la línea uno y la línea dos de tu tabla; deben ser iguales. La otra causa frecuente es una línea en blanco entre la cabecera y la separadora, que cierra el bloque antes de empezar. Una tercera, más rara: las celdas separadoras solo pueden contener guiones y dos puntos opcionales en los bordes, así que un espacio-guion-espacio perdido o una raya pegada por la autocorrección de un editor invalida la fila.
- ¿Importan los espacios que cuadran las columnas?
- No. | a | b | y |a|b| producen el mismo HTML en GitHub, y el interruptor «Rellenar columnas» existe solo para que la fuente se lea bien en un editor. El relleno sí tiene un coste real en un repositorio: como el ancho de cada columna es el de su valor más largo, editar una celda puede cambiar el relleno de toda la columna, y un cambio de una palabra se convierte en un diff que toca todas las filas. Si la tabla vive en un fichero versionado y se edita a menudo, generarla sin relleno da diffs más limpios. Si se escribe una vez y la leen humanos en el fichero crudo, deja el relleno.
- ¿Puedo usar negrita, enlaces o código dentro de una celda?
- Sí: el formato en línea funciona con normalidad dentro de las celdas, así que **negrita**, un [enlace](https://example.com) y un `fragmento de código` se renderizan. Las construcciones de bloque no: ni títulos, ni listas, ni bloques de código delimitados, ni tablas anidadas, porque todos necesitan saltos de línea que la fila no puede contener. La trampa es un fragmento de código con una barra, como `ps | grep node`. Los acentos graves no protegen una barra del analizador de tablas: la celda se parte primero y el código se interpreta después, así que igualmente hay que escribir `ps \| grep node`. Es uno de los pocos casos en que hay que escapar a mano, porque el conversor solo escapa las barras que ve en los datos de origen.
- ¿Por qué mi CSV francés salió en una sola columna?
- Porque la línea de cabecera no le dio nada que contar al detector, y es la cabecera la que decide qué delimitadores entran siquiera en liza. La herramienta cuenta comas, puntos y coma, tabulaciones y barras fuera de comillas en los primeros registros, y un recuento que se repite gana a otro que solo es el mayor en la línea uno; pero un delimitador que no aparece en el primer registro ni siquiera es candidato. Una hoja de cálculo francesa o alemana exporta con puntos y coma, ya que la coma es el separador decimal, y una cabecera Nom;Prénom se detecta bien. Una cabecera de una sola palabra sin separador, no: no hay nada que contar, la adivinanza recae en la coma y el archivo entero llega como una columna. Pon la opción Delimitador en Punto y coma a mano. El mismo remedio sirve para una exportación tabulada pegada desde un terminal, donde las tabulaciones pueden haberse convertido en espacios por el camino y ya no queda de verdad ningún delimitador que encontrar.
Artículos que podrían interesarte
Todas las guías →Herramientas relacionadas
Esto describe cómo se comportan un formato de archivo y un motor de renderizado, comprobado contra la especificación citada y contra el código de la herramienta tal y como está hoy. Los motores discrepan: GitHub, GitLab, un generador de sitios estáticos y la vista previa de tu editor son cuatro implementaciones distintas, y lo que funciona en una puede no funcionar en otra. Nada de esto garantiza nada sobre tu cadena de publicación: prueba el resultado donde vaya a publicarse de verdad, y trata cualquier herramienta, esta incluida, como algo que se comprueba y no como algo en lo que se confía.
Fuentes
- 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
¿Has detectado un error en este artículo?