Shawn O. Pearce  committed 2c570cd

Make trailing LF following fast-import `data` commands optional

A few fast-import frontend developers have found it odd that we
require the LF following a `data` command, especially in the exact
byte count format. Technically we don't need this LF to parse
the stream properly, but having it here does make the stream more
readable to humans. We can easily make the LF optional by peeking
at the next byte available from the stream and pushing it back into
the buffer if its not LF.

Signed-off-by: Shawn O. Pearce <>

  • Participants
  • Parent commits 401d53f
  • Branches master

Comments (0)

Files changed (3)

File Documentation/git-fast-import.txt

 	'data' SP <count> LF
-	<raw> LF
+	<raw> LF?
 where `<count>` is the exact number of bytes appearing within
 `<raw>`.  The value of `<count>` is expressed as an ASCII decimal
 integer.  The `LF` on either side of `<raw>` is not
 included in `<count>` and will not be included in the imported data.
+The `LF` after `<raw>` is optional (it used to be required) but
+recommended.  Always including it makes debugging a fast-import
+stream easier as the next command always starts in column 0
+of the next line, even if `<raw>` did not end with an `LF`.
 Delimited format::
 	A delimiter string is used to mark the end of the data.
 	'data' SP '<<' <delim> LF
 	<raw> LF
 	<delim> LF
+	LF?
 where `<delim>` is the chosen delimiter string.  The string `<delim>`
 immediately trailing `<raw>` is part of `<raw>`.  This is one of
 the limitations of the delimited format, it is impossible to supply
 a data chunk which does not have an LF as its last byte.
+The `LF` after `<delim> LF` is optional (it used to be required).

File fast-import.c

   mark ::= 'mark' sp idnum lf;
   data ::= (delimited_data | exact_data)
-    lf;
+    lf?;
     # note: delim may be any string but must not contain lf.
     # data_line may contain any data but must not be exactly
 	} while (!command_buf.eof && command_buf.buf[0] == '#');
+static void skip_optional_lf()
+	int term_char = fgetc(stdin);
+	if (term_char != '\n' && term_char != EOF)
+		ungetc(term_char, stdin);
 static void cmd_mark(void)
 	if (!prefixcmp(command_buf.buf, "mark :")) {
-	if (fgetc(stdin) != '\n')
-		die("An lf did not trail the binary data as expected.");
+	skip_optional_lf();
 	*size = length;
 	return buffer;

File t/

 	'git-fast-import <input &&
 	 test `git-rev-parse N3` = `git-rev-parse O1`'
+cat >input <<INPUT_END
+commit refs/heads/O2
+data <<COMMIT
+dirty directory copy
+from refs/heads/branch^0
+M 644 inline file2/file5
+data <<EOF
+C file2 file3
+D file2/file5
+test_expect_success \
+	'O: blank lines not necessary after data commands' \
+	'git-fast-import <input &&
+	 test `git-rev-parse N3` = `git-rev-parse O2`'