fast-import: support 'encoding' commit header

Since git supports commit messages with an encoding other than UTF-8, allow fast-import to import such commits. This may be useful for folks who do not want to reencode commit messages from an external system, and may also be useful to achieve reversible history rewrites (e.g. sha1sum <-> sha256sum transitions or subtree work) with git repositories that have used specialized encodings in their commit history. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed May 13, 2019 at 21:30 UTC 3edfcc65fdfc708c1c8f1d314885eecf9beb9b67
3 files changed +36 -2
Documentation/git-fast-import.txt
+7
@@ -388,6 +388,7 @@ change to the project.
388 original-oid?
389 ('author' (SP <name>)? SP LT <email> GT SP <when> LF)?
390 'committer' (SP <name>)? SP LT <email> GT SP <when> LF
391 + ('encoding' SP <encoding>)?
392 data
393 ('from' SP <commit-ish> LF)?
394 ('merge' SP <commit-ish> LF)?
@@ -455,6 +456,12 @@ that was selected by the --date-format=<fmt> command-line option.
456 See ``Date Formats'' above for the set of supported formats, and
457 their syntax.
458
459 +`encoding`
460 +^^^^^^^^^^
461 +The optional `encoding` command indicates the encoding of the commit
462 +message. Most commits are UTF-8 and the encoding is omitted, but this
463 +allows importing commit messages into git without first reencoding them.
464 +
465 `from`
466 ^^^^^^
467 The `from` command is used to specify the commit to initialize
fast-import.c
+9 -2
@@ -2585,6 +2585,7 @@ static void parse_new_commit(const char *arg)
2585 struct branch *b;
2586 char *author = NULL;
2587 char *committer = NULL;
2588 + const char *encoding = NULL;
2589 struct hash_list *merge_list = NULL;
2590 unsigned int merge_count;
2591 unsigned char prev_fanout, new_fanout;
@@ -2607,6 +2608,8 @@ static void parse_new_commit(const char *arg)
2608 }
2609 if (!committer)
2610 die("Expected committer but didn't get one");
2611 + if (skip_prefix(command_buf.buf, "encoding ", &encoding))
2612 + read_next_command();
2613 parse_data(&msg, 0, NULL);
2614 read_next_command();
2615 parse_from(b);
@@ -2670,9 +2673,13 @@ static void parse_new_commit(const char *arg)
2673 }
2674 strbuf_addf(&new_data,
2675 "author %s\n"
2673 - "committer %s\n"
2674 - "\n",
2676 + "committer %s\n",
2677 author ? author : committer, committer);
2678 + if (encoding)
2679 + strbuf_addf(&new_data,
2680 + "encoding %s\n",
2681 + encoding);
2682 + strbuf_addch(&new_data, '\n');
2683 strbuf_addbuf(&new_data, &msg);
2684 free(author);
2685 free(committer);
t/t9300-fast-import.sh
+20
@@ -3299,4 +3299,24 @@ test_expect_success !MINGW 'W: get-mark & empty orphan commit with erroneous thi
3299 sed -e s/LFs/LLL/ W-input | tr L "\n" | test_must_fail git fast-import
3300 '
3301
3302 +###
3303 +### series X (other new features)
3304 +###
3305 +
3306 +test_expect_success 'X: handling encoding' '
3307 + test_tick &&
3308 + cat >input <<-INPUT_END &&
3309 + commit refs/heads/encoding
3310 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3311 + encoding iso-8859-7
3312 + data <<COMMIT
3313 + INPUT_END
3314 +
3315 + printf "Pi: \360\nCOMMIT\n" >>input &&
3316 +
3317 + git fast-import <input &&
3318 + git cat-file -p encoding | grep $(printf "\360") &&
3319 + git log -1 --format=%B encoding | grep $(printf "\317\200")
3320 +'
3321 +
3322 test_done