Zum Inhalt springen
OneKitly

Eine Tabelle in einen Pull Request einfügen: was kaputtgeht und die zwei Zeichen, die es kaputtmachen

Veröffentlicht am 29.7.2026 · 14 Min. Lesezeit · Entwickler-Tools

Daniel Okonkwo

Daniel OkonkwoFront-end-Entwickler und Tech-Redakteur bei OneKitly

Web-Performance · Dateiformate

Anhand von 4 Quellen geprüft

Profil ansehen
Kurz gesagt

Eine Markdown-Tabellenzelle nimmt alles auf außer zwei Zeichen. Der Pipe schließt die Zelle, also muss er als \| geschrieben werden — der Konverter erledigt das: Füge USB-C | 2 m ein, und er gibt USB-C \| 2 m aus, was GitHub als eine einzige Zelle darstellt. Der Zeilenumbruch schließt die Zeile, und für ihn gibt es überhaupt kein Escape: Eine Zelle mit einem echten Umbruch ist in der GFM-Tabellensyntax unmöglich, deshalb ersetzt das Werkzeug ihn durch das HTML-Tag <br>, das Einzige, was funktioniert. Unter die Kopfzeile gehört die Trennzeile, und sie ist Pflicht — eine Kopfzeile ohne Strichzeile darunter ist keine Tabelle, und GitHub zeigt sie als Absatz mit Pipes darin. Diese Zeile trägt auch die Ausrichtung: --- lässt die Vorgabe des Renderers, :-- ist links, --: ist rechts, :-: ist zentriert, und ein Doppelpunkt anderswo bewirkt nichts. Die Trennzeile muss genau so viele Zellen haben wie die Kopfzeile, sonst wird die Tabelle gar nicht erkannt. Die Leerzeichen, die die Spalten ausrichten, sind reine Kosmetik: | a | b | und |a|b| ergeben byteweise identisches HTML, daher der Schalter zum Auffüllen und daher ist Abschalten gefahrlos. Noch ein Detail zum Escapen, denn hier sieht die richtige Ausgabe falsch aus: Der Backslash wird vor dem Pipe escaped. Eine Zelle, die schon x \| y enthält, kommt als x \\\| y heraus, wobei \\ ein wörtlicher Backslash und \| ein wörtlicher Pipe ist, sodass GitHub die eine Zelle x \| y darstellt. Nur den Pipe zu escapen ergäbe x \\| y — einen wörtlichen Backslash gefolgt von einem lebendigen Zellenbruch — und die Spalte würde sich teilen. Es hängt allein an der Reihenfolge, und deshalb kann eine bestehende Markdown-Tabelle noch einmal durch den CSV-Konverter laufen und unverändert herauskommen.

Eine Markdown-Tabelle verbietet in einer Zelle genau zwei Zeichen: den Pipe und den Zeilenumbruch. Hier steht, was jedes davon anrichtet, wie ein Konverter damit umgeht, warum das Escape in der richtigen Reihenfolge angewandt werden muss, und warum das Auffüllen nie zählt.

Zwei Zeichen, und nur zwei

Fast alles übersteht eine Markdown-Tabellenzelle unversehrt. Akzente, Ideogramme, Emoji, Backticks, Sternchen, Klammern, Währungszeichen, Anführungszeichen — nichts davon bedeutet dem Tabellenparser irgendetwas, der immer nur nach zwei Dingen sucht. Der Pipe beendet eine Zelle. Der Zeilenumbruch beendet eine Reihe. Das ist die ganze Grammatik, und jedes Problem, das du je beim Einfügen einer Tabelle in einen Pull Request haben wirst, ist eines dieser beiden Zeichen an einer Stelle, an der der Parser es nicht erwartet hat.

Der Pipe hat ein Escape. Schreibe \|, und der Parser liest einen echten senkrechten Strich statt einer Spaltengrenze. Der Konverter setzt es für dich: Seine eigenen Beispieldaten enthalten die Zelle USB-C | 2 m, und der Durchlauf ergibt die Zeile | Câble | USB-C \| 2 m | 9.90 |, also eine Reihe mit drei Zellen und nicht mit vier. Gib ihm eine Zelle, die nur aus einem Pipe besteht, und du bekommst \| allein, weiterhin eine Zelle. Dieser Teil sitzt, und genau ihn verfehlen handgeschriebene Tabellen am häufigsten: Ein Shell-Befehl in einer Doku-Tabelle — ps | grep node — gewinnt stillschweigend eine Spalte und schiebt jeden Wert eine Stelle nach rechts, ein Fehler, über den ein Reviewer hinwegliest, weil die Tabelle immer noch wie eine Tabelle aussieht.

Der Zeilenumbruch hat kein Escape, und das ist der Teil, den man verinnerlichen sollte: Eine Zelle mit einem Umbruch ist in der GFM-Tabellensyntax nicht bloß unhandlich, sie ist unmöglich. Die Reihe endet am Umbruch, Punkt. Es gibt genau zwei ehrliche Auswege. Ersetze den Bruch durch das HTML-Tag <br>, das GitHub in einer Zelle erlaubt und das der Konverter setzt — ein CSV-Feld in Anführungszeichen mit dem Inhalt Zeile eins\nZeile zwei kommt als Zeile eins<br>Zeile zwei in einer einzigen Zelle heraus. Oder akzeptiere, dass der Inhalt in keine Tabelle gehört, und setze ihn in eine Liste oder einen Absatz darunter. Alles andere ist Wunschdenken: Es gibt keinen Backslash-Trick, keinen verdoppelten Pipe, kein Fortsetzungszeichen.

Die Trennzeile ist keine Verzierung

GitHub Flavored Markdown nennt die Strichreihe unter der Kopfzeile die Trennzeile, und die Spezifikation ist darin eindeutig: Sie besteht aus Zellen, deren einziger Inhalt Bindestriche sind, mit einem optionalen Doppelpunkt am Anfang, am Ende oder an beiden Stellen. Ohne sie gibt es keine Tabelle. Eine Kopfzeile und drei Datenzeilen ohne Striche dazwischen erscheinen als vier Textabsätze mit Pipes darin — deshalb hat eine Tabelle, die im Editor gut aussah und im Pull Request zerfiel, fast immer genau diese eine Zeile beim Kopieren verloren.

Vier Formen der Trennzelle bedeuten vier verschiedene Dinge, und der Konverter bietet alle vier als Ausrichtungseinstellung an. Ein nacktes --- überlässt die Ausrichtung dem Renderer, was in der Praxis in jeder gebräuchlichen Engine links heißt. Ein führender Doppelpunkt, :---, erzwingt links. Ein abschließender Doppelpunkt, ---:, erzwingt rechts und ist der, den du auf jeder Zahlenspalte willst. Ein Doppelpunkt an beiden Enden, :---:, zentriert. Ein Doppelpunkt mitten in den Strichen ist keine Ausrichtung und nicht gültig — die Zelle muss Doppelpunkt, Striche, Doppelpunkt sein, in dieser Reihenfolge, und sonst nichts. Stelle das Werkzeug auf rechts, und eine zweispaltige Tabelle kommt mit | -----: | ---: | darunter heraus, und jede Zahl der Spalte richtet sich in der Ausgabe an ihrer letzten Ziffer aus.

Eine Regel fängt die meisten stillen Fehlschläge ab: Die Trennzeile muss genau so viele Zellen haben wie die Kopfzeile, sonst wird die Tabelle gar nicht erkannt. Die Spezifikation sagt es unumwunden, und der Fehlermodus ist der schlimmste — du bekommst keine kaputte Tabelle, du bekommst keine Tabelle. Eine Kopfzeile mit vier Spalten über einer Trennzeile mit drei erscheint als wörtlicher Text, Pipes inklusive. Genau das passiert, wenn jemand von Hand eine Spalte ergänzt und die Striche vergisst. Der Konverter kann diesen Fehler nicht machen, weil er beide Zeilen aus derselben Spaltenzahl baut — ein ordentliches Argument dafür, die Tabelle zu erzeugen statt eine zu bearbeiten.

Das Auffüllen ist für dich, nicht für GitHub

Der Konverter hat einen Schalter zum Auffüllen der Spalten, standardmäßig an, und er ändert nichts an der gerenderten Tabelle. Eingeschaltet kommt eine zweispaltige Tabelle als | Item | Qty |, | ------ | --- |, | Widget | 3 | heraus, mit bündigen Zellen. Ausgeschaltet bekommst du | Item | Qty |, | --- | --- |, | Widget | 3 |, ausgefranst. GitHub erzeugt aus beidem identisches HTML. Die Leerzeichen sind dafür da, dass ein Mensch beim Lesen des Diffs die Spalten sieht, und aus keinem anderen Grund. Schalte das Auffüllen ab, wenn die Tabelle breit ist und ohnehin der Diff gelesen wird; lass es an, wenn die Datei von Hand bearbeitet wird.

Es gibt einen Haken, den man kennen sollte, wenn die Daten nicht lateinisch sind. Das Auffüllen zählt Zeichen, und ein Zeichen ist keine Spalte. Gib dem Konverter eine Zelle mit zwei Emoji: Er zählt zwei, füllt auf zwei auf, und die Quelle steht in einem Editor nicht mehr bündig, in dem jedes Emoji zwei Monospace-Spalten belegt. Dasselbe gilt für chinesischen, japanischen und koreanischen Text, und in die andere Richtung für ein é aus e plus kombinierendem Akzent, also zwei Zeichen in einer Spalte. Nichts davon betrifft die gerenderte Tabelle, es ist also ein Lesbarkeits- und kein Richtigkeitsproblem — aber wer eine breite Tabelle japanischer Ortsnamen erzeugt, sollte keine saubere Quelle erwarten.

Das Escape escapen, und das Trennzeichen erraten

Ein Konverter, der jeden Pipe durch \| ersetzt und dort aufhört, liegt bei genau einer Eingabe falsch, und die trifft man, sobald man eine selbst geschriebene Tabelle wieder einliest: eine Zelle, die schon \| enthält. Escapt man nur den Pipe, wird aus x \| y ein x \\| y, wobei der verdoppelte Backslash ein wörtlicher Backslash ist und der Pipe dahinter wieder lebt — die Spalte teilt sich, und nichts warnt. Die Reihenfolge muss umgekehrt sein. Dieser Konverter escapt erst den Backslash und dann den Pipe, also kommt x \| y als x \\\| y heraus, was nach einem Backslash zu viel aussieht und keiner ist: GFM liest \\ als wörtlichen Backslash und \| als wörtlichen Pipe und stellt die eine Zelle x \| y dar.

Die Folge ist, dass das Hin und Zurück sicher ist. Wandle Daten in eine Markdown-Tabelle, kopiere die Tabelle heraus, speichere sie als CSV, gib sie wieder hinein — die Spalten mit Pipes kommen so zurück, wie sie hinausgingen, und alles andere ebenso. Das ist mehr wert, als es klingt, denn eine gerenderte Tabelle in eine Tabellenkalkulation zu exportieren und wieder einzulesen ist ganz normal, sobald eine Spalte umbenannt wird. Das Schwesterwerkzeug auf dieser Seite, der Markdown-Tabellengenerator, schließt dieselbe Schleife vom anderen Ende: Sein Parser liest \| als wörtlichen Pipe, wenn das Trennzeichen ein Pipe ist, und macht das Escape beim Einlesen rückgängig, sodass eine dort eingefügte Tabelle ebenfalls identisch zurückkommt.

Das Trennzeichen wird geraten statt angegeben, und geraten wird über mehrere Datensätze hinweg, nicht nur über die Kopfzeile. Das Werkzeug zählt Kommas, Semikolons, Tabs und Pipes außerhalb von Anführungszeichen über höchstens fünf Datensätze, und ein Trennzeichen, das in jedem gelesenen Datensatz dieselbe Anzahl ergibt, schlägt eines, das im ersten bloß häufiger vorkommt. Damit ist eine Kopfzeile wie A|B|C,D entschieden: für sich allein sieht sie nach drei durch Pipes getrennten Spalten aus, aber stell Zeilen mit Kommas darunter, und das Komma gewinnt, weil seine Anzahl sich wiederholt. Ein französischer Export mit der Kopfzeile Nom;Prénom wird so oder so als Semikolon erkannt. Das Einzige, was der erste Datensatz noch allein entscheidet, ist, welche Trennzeichen überhaupt in Frage kommen — eine Kopfzeile ohne eines der vier lässt nichts zu entscheiden, und die Vermutung fällt auf das Komma zurück. Ist deine erste Zeile ungewöhnlich, stell das Trennzeichen von Hand ein.

Ein Ablauf, der das Review übersteht

Exportiere die Daten als CSV, statt Zellen aus einer Tabellenkalkulation zu kopieren, denn die Anführungsregeln einer CSV-Datei sind das Einzige, was dem Konverter sagt, wo ein Feld mit Komma oder Zeilenumbruch endet. Einfügen, das erkannte Trennzeichen prüfen, die Ausrichtung wählen — rechts für Zahlen, Vorgabe für alles andere — und vor dem Kopieren die ersten beiden Ausgabezeilen lesen. Diese zwei Zeilen sind Kopf- und Trennzeile, und wenn sie unterschiedlich viele Pipes haben, rendert weiter unten gar nichts.

Dann suche die drei Zellen, die Ärger machen. Alles mit einem Pipe: prüfen, dass \| herauskam und keine lebendige Spaltengrenze, und daran denken, dass eine Zelle, die schon einen Backslash hatte, ihn verdoppelt bekommt — \\\| ist die richtige Ausgabe und kein überzähliges Escape. Alles, was mehrzeilig war: prüfen, dass es zu <br> wurde, und entscheiden, ob das in einer Tabelle wirklich gewollt ist. Alles Leere: Eine leere Zelle ist völlig zulässig und erscheint leer, eine Reihe aus Leerzellen mitten in der Tabelle ist also Datum und kein Schaden. Geht die Tabelle in ein Repository statt in einen Kommentar, committe sie einmal mit eingeschaltetem Auffüllen, damit der erste Reviewer den Diff lesen kann, und formatiere sie danach nie wieder um — eine reine Leerzeichenänderung an einer Tabelle sind dreißig Zeilen Rauschen in einem Pull Request, die nichts aussagen.

Was der Konverter mit jeder heiklen Zelle macht und was GitHub darstellt
ZelleninhaltWas das Werkzeug ausgibtErgebnis
USB-C | 2 mUSB-C \| 2 mRichtig — eine Zelle mit sichtbarem Pipe
Ein Feld in Anführungszeichen mit echtem UmbruchZeile eins<br>Zeile zweiRichtig — das Einzige, was GFM-Tabellen erlauben; ein echter Umbruch ist unmöglich
x \| y (bereits escaped)x \\\| yRichtig — der Backslash wird zuerst escaped, GitHub stellt die eine Zelle x \| y dar
Ein leeres FeldNichts zwischen den PipesRichtig — eine leere Zelle ist zulässig und erscheint leer
Eine Reihe mit weniger Feldern als die KopfzeileMit leeren Zellen bis zur breitesten Reihe aufgefülltRichtig — eine ausgefranste Tabelle würde gar nicht rendern, also richtet das Werkzeug sie aus
Zwei EmojiAufgefüllt, als wären es zwei Spalten breitNur kosmetisch — sie belegen vier; die gerenderte Tabelle bleibt unberührt
CSV zu Markdown-TabelleWandle CSV in eine Markdown-Tabelle, Anführungszeichen inklusive: Ein Feld darf das Trennzeichen, einen Zeilenumbruch oder einen Pipe enthalten, ohne die Tabelle zu zerlegen. Komma, Semikolon (französisches Excel), Tab oder Pipe — erkannt oder erzwungen.Tool ausprobieren

Häufige Fragen

Kann ich einen Zeilenumbruch in eine Markdown-Tabellenzelle setzen?
Einen echten nicht. Der Zeilenumbruch beendet die Reihe, also kann die Tabellensyntax eine Zelle mit einem Umbruch gar nicht ausdrücken — es gibt dafür keine Escape-Sequenz, wie \| sie für den Pipe hat. Der von GitHub akzeptierte Behelf ist das HTML-Tag <br>, und genau das setzt dieser Konverter ein: Ein CSV-Feld in Anführungszeichen mit Umbruch wird zu einer Zelle mit Zeile eins<br>Zeile zwei. Zwei ehrliche Grenzen. Renderer, die HTML entfernen, zeigen das Tag als wörtlichen Text, und eine Zelle mit drei oder vier <br> darin ist meist ein Zeichen dafür, dass der Inhalt eine Liste unter der Tabelle sein will und keine Zelle darin.
Meine Tabelle erscheint als reiner Text mit Pipes. Was habe ich kaputtgemacht?
Fast immer die Trennzeile. Entweder fehlt sie ganz, oder sie hat eine andere Zellenzahl als die Kopfzeile — die Spezifikation verlangt, dass Kopf- und Trennzeile in der Zellenzahl übereinstimmen, sonst wird die Tabelle nicht erkannt und fällt auf einen Absatz zurück. Zähle die Pipes in Zeile eins und Zeile zwei deiner Tabelle; sie müssen gleich sein. Die andere häufige Ursache ist eine Leerzeile zwischen Kopf- und Trennzeile, die den Block beendet, bevor er beginnt. Eine dritte, seltenere: Die Trennzellen dürfen nur Bindestriche und optionale Randdoppelpunkte enthalten, ein verirrtes Leerzeichen-Strich-Leerzeichen oder ein von der Autokorrektur eingefügter Geviertstrich macht die Zeile also ungültig.
Zählen die Leerzeichen, die die Spalten ausrichten?
Nein. | a | b | und |a|b| erzeugen auf GitHub dasselbe HTML, und der Schalter zum Auffüllen ist nur da, damit die Quelle im Editor lesbar bleibt. Das Auffüllen hat allerdings einen echten Preis im Repository: Da die Breite jeder Spalte die ihres längsten Werts ist, kann das Ändern einer Zelle das Auffüllen der ganzen Spalte verschieben, und eine Ein-Wort-Änderung wird zu einem Diff, der jede Reihe berührt. Lebt die Tabelle in einer versionierten Datei und ändert sich oft, ergibt eine ungepolsterte Ausgabe sauberere Diffs. Wird sie einmal geschrieben und von Menschen in der Rohdatei gelesen, behalte das Auffüllen.
Kann ich Fettschrift, Links oder Code in einer Zelle verwenden?
Ja — Inline-Formatierung funktioniert in Zellen ganz normal, also erscheinen **fett**, ein [Link](https://example.com) und eine `Code-Spanne`. Blockkonstrukte nicht: keine Überschriften, keine Listen, keine eingezäunten Codeblöcke, keine verschachtelten Tabellen, denn sie alle brauchen Zeilenumbrüche, die die Reihe nicht enthalten kann. Die Falle ist eine Code-Spanne mit einem Pipe, etwa `ps | grep node`. Backticks schützen einen Pipe nicht vor dem Tabellenparser — die Zelle wird zuerst geteilt, die Code-Spanne erst danach gelesen — du musst also trotzdem `ps \| grep node` schreiben. Das ist einer der wenigen Fälle, in denen von Hand escaped werden muss, denn der Konverter escaped nur Pipes, die er in den Quelldaten sieht.
Warum kam meine französische CSV als eine einzige Spalte heraus?
Weil die Kopfzeile dem Erkenner nichts zum Zählen gegeben hat — und die Kopfzeile entscheidet, welche Trennzeichen überhaupt im Rennen sind. Das Werkzeug zählt Kommas, Semikolons, Tabs und Pipes außerhalb von Anführungszeichen über die ersten Datensätze, und eine Anzahl, die sich wiederholt, schlägt eine, die in Zeile eins bloß am größten ist; ein Trennzeichen, das im ersten Datensatz nicht vorkommt, ist aber gar kein Kandidat. Eine französische oder deutsche Tabellenkalkulation exportiert mit Semikolons, weil das Komma das Dezimaltrennzeichen ist, und eine Kopfzeile Nom;Prénom wird richtig erkannt. Eine Kopfzeile aus einem einzigen Wort ohne Trennzeichen nicht: Da ist nichts zu zählen, die Vermutung fällt auf das Komma zurück, und die ganze Datei kommt als eine Spalte an. Stell die Option Trennzeichen von Hand auf Semikolon. Dasselbe gilt für einen tabulatorgetrennten Export aus einem Terminal, bei dem die Tabs unterwegs zu Leerzeichen geworden sein können und wirklich kein Trennzeichen mehr zu finden ist.

Artikel, die dich interessieren könnten

Alle Ratgeber
AnleitungEine Markdown-Tabelle von Grund auf bauen, ohne Striche zu zählenDas Kleinste, das noch eine Tabelle ist, sind zwei Zeilen: eine Kopfzeile und eine Trennzeile. Hier steht, warum die zweite in GitHub Flavored Markdown Pflicht ist, wo Pipe-Tabellen überhaupt nicht existieren, und was ein Generator kann, was Tippen von Hand nicht kann.RatgeberEine Tabelle transponieren, deren Zeilen Spalten hätten sein sollenWas aus der Kopfzeile wird, was aus ungleich langen Zeilen wird, was aus Typen wird — und die eine Sache, mit der Transponieren regelmäßig verwechselt wird und die es nicht kann.ErklärungCSV zu JSON: die fünf Fälle, an denen jeder Konverter scheitertTrennzeichen in Anführungszeichen, eingebettete Zeilenumbrüche, mehrdeutige Typen, doppelte Spaltennamen und Kodierung. Jeder Fall lief durch den Konverter, und die exakte Ausgabe steht hier — auch die beiden, die er nicht rettet.AnleitungMarkdown: EinsteigerleitfadenFormatiere reinen Text mit ein paar Symbolen: # für Überschriften, ** für Fett, - für Listen. Hier steht, was Markdown ist, die Kernsyntax, warum es überall ist und die Fallstricke.ErklärungSemikolon, Tab, Pipe: ein Trennzeichen wählen, das die Reise überstehtWarum die Sprache des Lesers das Trennzeichen bestimmt, was der Konverter beim Wechsel mit der Zitierung macht, was die erste Zeile sep= wirklich ist, und die Zahl zitierter Zellen bei demselben Export in fünf Schreibweisen.ErklärungWarum dein CSV in Excel Umlaute und Datumsangaben zerlegtHinter demselben Satz verbergen sich drei völlig verschiedene Fehler. Einer ist die Kodierung, einer das Trennzeichen, einer Excel, das beim Öffnen Datentypen errät — und jeder hat eine andere Lösung. So unterscheidest du sie in fünf Sekunden.

Ähnliche Tools

Das hier beschreibt das Verhalten eines Dateiformats und eines Renderers, geprüft an der genannten Spezifikation und am Code des Werkzeugs, wie er heute aussieht. Renderer sind sich uneinig: GitHub, GitLab, ein Static-Site-Generator und die Vorschau deines Editors sind vier verschiedene Implementierungen, und was in der einen läuft, kann in der anderen scheitern. Nichts davon ist eine Zusage über deine Veröffentlichungskette — teste das Ergebnis dort, wo es wirklich erscheinen wird, und behandle jedes Werkzeug, dieses eingeschlossen, als etwas zum Nachprüfen und nicht zum Glauben.

Quellen

Hast du einen Fehler in diesem Artikel entdeckt?

Eine Tabelle in einen Pull Request einfügen: was kaputtgeht und die zwei Zeichen, die es kaputtmachen — OneKitly