Skip to content

Commit 5404183

Browse files
committed
Merge branch 'en/fast-import-looser-date'
Some repositories in the wild have commits that record nonsense committer timezone (e.g. rails.git); "git fast-import" learned an option to pass these nonsense timestamps intact to allow recreating existing repositories as-is. * en/fast-import-looser-date: fast-import: add new --date-format=raw-permissive format
2 parents a0ba2bb + d42a2fb commit 5404183

File tree

3 files changed

+57
-5
lines changed

3 files changed

+57
-5
lines changed

Documentation/git-fast-import.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,14 @@ by users who are located in the same location and time zone. In this
293293
case a reasonable offset from UTC could be assumed.
294294
+
295295
Unlike the `rfc2822` format, this format is very strict. Any
296-
variation in formatting will cause fast-import to reject the value.
296+
variation in formatting will cause fast-import to reject the value,
297+
and some sanity checks on the numeric values may also be performed.
298+
299+
`raw-permissive`::
300+
This is the same as `raw` except that no sanity checks on
301+
the numeric epoch and local offset are performed. This can
302+
be useful when trying to filter or import an existing history
303+
with e.g. bogus timezone values.
297304

298305
`rfc2822`::
299306
This is the standard email format as described by RFC 2822.

fast-import.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ struct hash_list {
139139

140140
typedef enum {
141141
WHENSPEC_RAW = 1,
142+
WHENSPEC_RAW_PERMISSIVE,
142143
WHENSPEC_RFC2822,
143144
WHENSPEC_NOW
144145
} whenspec_type;
@@ -1911,7 +1912,7 @@ static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res)
19111912
return 1;
19121913
}
19131914

1914-
static int validate_raw_date(const char *src, struct strbuf *result)
1915+
static int validate_raw_date(const char *src, struct strbuf *result, int strict)
19151916
{
19161917
const char *orig_src = src;
19171918
char *endp;
@@ -1920,7 +1921,11 @@ static int validate_raw_date(const char *src, struct strbuf *result)
19201921
errno = 0;
19211922

19221923
num = strtoul(src, &endp, 10);
1923-
/* NEEDSWORK: perhaps check for reasonable values? */
1924+
/*
1925+
* NEEDSWORK: perhaps check for reasonable values? For example, we
1926+
* could error on values representing times more than a
1927+
* day in the future.
1928+
*/
19241929
if (errno || endp == src || *endp != ' ')
19251930
return -1;
19261931

@@ -1929,7 +1934,13 @@ static int validate_raw_date(const char *src, struct strbuf *result)
19291934
return -1;
19301935

19311936
num = strtoul(src + 1, &endp, 10);
1932-
if (errno || endp == src + 1 || *endp || 1400 < num)
1937+
/*
1938+
* NEEDSWORK: check for brokenness other than num > 1400, such as
1939+
* (num % 100) >= 60, or ((num % 100) % 15) != 0 ?
1940+
*/
1941+
if (errno || endp == src + 1 || *endp || /* did not parse */
1942+
(strict && (1400 < num)) /* parsed a broken timezone */
1943+
)
19331944
return -1;
19341945

19351946
strbuf_addstr(result, orig_src);
@@ -1963,7 +1974,11 @@ static char *parse_ident(const char *buf)
19631974

19641975
switch (whenspec) {
19651976
case WHENSPEC_RAW:
1966-
if (validate_raw_date(ltgt, &ident) < 0)
1977+
if (validate_raw_date(ltgt, &ident, 1) < 0)
1978+
die("Invalid raw date \"%s\" in ident: %s", ltgt, buf);
1979+
break;
1980+
case WHENSPEC_RAW_PERMISSIVE:
1981+
if (validate_raw_date(ltgt, &ident, 0) < 0)
19671982
die("Invalid raw date \"%s\" in ident: %s", ltgt, buf);
19681983
break;
19691984
case WHENSPEC_RFC2822:
@@ -3258,6 +3273,8 @@ static void option_date_format(const char *fmt)
32583273
{
32593274
if (!strcmp(fmt, "raw"))
32603275
whenspec = WHENSPEC_RAW;
3276+
else if (!strcmp(fmt, "raw-permissive"))
3277+
whenspec = WHENSPEC_RAW_PERMISSIVE;
32613278
else if (!strcmp(fmt, "rfc2822"))
32623279
whenspec = WHENSPEC_RFC2822;
32633280
else if (!strcmp(fmt, "now"))

t/t9300-fast-import.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,34 @@ test_expect_success 'B: accept empty committer' '
410410
test -z "$out"
411411
'
412412

413+
test_expect_success 'B: reject invalid timezone' '
414+
cat >input <<-INPUT_END &&
415+
commit refs/heads/invalid-timezone
416+
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1234567890 +051800
417+
data <<COMMIT
418+
empty commit
419+
COMMIT
420+
INPUT_END
421+
422+
test_when_finished "git update-ref -d refs/heads/invalid-timezone" &&
423+
test_must_fail git fast-import <input
424+
'
425+
426+
test_expect_success 'B: accept invalid timezone with raw-permissive' '
427+
cat >input <<-INPUT_END &&
428+
commit refs/heads/invalid-timezone
429+
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1234567890 +051800
430+
data <<COMMIT
431+
empty commit
432+
COMMIT
433+
INPUT_END
434+
435+
git init invalid-timezone &&
436+
git -C invalid-timezone fast-import --date-format=raw-permissive <input &&
437+
git -C invalid-timezone cat-file -p invalid-timezone >out &&
438+
grep "1234567890 [+]051800" out
439+
'
440+
413441
test_expect_success 'B: accept and fixup committer with no name' '
414442
cat >input <<-INPUT_END &&
415443
commit refs/heads/empty-committer-2

0 commit comments

Comments
 (0)