diff --git a/Documentation/git-interpret-trailers.adoc b/Documentation/git-interpret-trailers.adoc index b4988d39ea..903d598dcb 100644 --- a/Documentation/git-interpret-trailers.adoc +++ b/Documentation/git-interpret-trailers.adoc @@ -123,9 +123,16 @@ OTHER RULES What was covered in the previous section are the rules that are relevant for regular use. The following points are included for completeness. -This command ignores comment lines (see `core.commentString` in -linkgit:git-config[1]). This is for use with the `prepare-commit-msg` -and `commit-msg` hooks. +-- +* This command ignores comment lines (see `core.commentString` in + linkgit:git-config[1]). This is for use with the `prepare-commit-msg` + and `commit-msg` hooks. + +* Candidate trailer lines that have `:` as the separator, that have no + whitespace before the value part, and that start with `//` are not + recognized as trailers. This is to avoid accidentally interpreting + URLs as trailers (e.g. lines that start with `https://`). +-- OPTIONS ------- diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh index 818a8dafbd..e3555b6d51 100755 --- a/t/t7513-interpret-trailers.sh +++ b/t/t7513-interpret-trailers.sh @@ -1989,4 +1989,23 @@ test_expect_success 'handling of --- lines in conjunction with cut-lines' ' test_cmp expected actual ' +test_expect_success 'URLs and lines that are not quite URLs' ' + cat >expect <<-\EOF && + https: //www.a-trailer.org + https: //www.another-trailer.org + Signed-off-by: somebody + EOF + git interpret-trailers --only-trailers >actual <<-\EOF && + subject + + body + + https://www.not-a-trailer.org + https ://www.a-trailer.org + https: //www.another-trailer.org + Signed-off-by: somebody + EOF + test_cmp expect actual +' + test_done diff --git a/t/unit-tests/u-trailer.c b/t/unit-tests/u-trailer.c index 3d60ea1603..7404b165fa 100644 --- a/t/unit-tests/u-trailer.c +++ b/t/unit-tests/u-trailer.c @@ -318,3 +318,55 @@ void test_trailer__one_non_trailer_no_git_trailers(void) 0, expected_contents); } + +void test_trailer__URL(void) +{ + struct contents expected_contents[] = { 0 }; + + t_trailer_iterator("Subject: foo bar\n" + "\n" + /* + * We do not want to match URLs as trailers. + */ + "https://www.example.org\n", + 0, + expected_contents); +} + +void test_trailer__not_a_URL_space_after_separator(void) +{ + struct contents expected_contents[] = { + { .raw = "https: //www.example.org\n", + .key = "https", + .val = "//www.example.org" }, + { 0 }, + }; + + t_trailer_iterator("Subject: foo bar\n" + "\n" + /* + * This has a space after ':' so it's not a URL. + */ + "https: //www.example.org\n", + 1, + expected_contents); +} + +void test_trailer__not_a_URL_space_before_separator(void) +{ + struct contents expected_contents[] = { + { .raw = "https ://www.example.org\n", + .key = "https", + .val = "//www.example.org" }, + { 0 }, + }; + + t_trailer_iterator("Subject: foo bar\n" + "\n" + /* + * This has a space before ':' so it's not a URL. + */ + "https ://www.example.org\n", + 1, + expected_contents); +} diff --git a/trailer.c b/trailer.c index 6d8ec7fa8d..971ae45959 100644 --- a/trailer.c +++ b/trailer.c @@ -635,8 +635,13 @@ static ssize_t find_separator(const char *line, const char *separators) int whitespace_found = 0; const char *c; for (c = line; *c; c++) { - if (strchr(separators, *c)) + if (strchr(separators, *c)) { + /* avoid accidental URL matches (://) */ + if (*c == ':' && c[1] == '/' && c[2] == '/' && + !whitespace_found) + return -1; return c - line; + } if (!whitespace_found && (isalnum(*c) || *c == '-')) continue; if (c != line && (*c == ' ' || *c == '\t')) {