Merge branch 'kh/trailers-no-urls'

The trailer parsing machinery has been updated to avoid mistaking
lines that begin with a URL (e.g., 'https://...') as trailer lines.
This prevents intended textual URLs from being mangled or mistakenly
treated as metadata keys.

* kh/trailers-no-urls:
  trailers: stop recognizing URLs as trailers
This commit is contained in:
Junio C Hamano committed 2026-08-31 08:24:59 -07:00
commit 1e4d33de9b
4 files changed
+86 -4

No files matched your search

+10 -3
View File
@@ -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
-------
+19
View File
@@ -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 <somebody@somewhere>
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 <somebody@somewhere>
EOF
test_cmp expect actual
'
test_done
+52
View File
@@ -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);
}
+5 -1
View File
@@ -635,8 +635,12 @@ 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 (!whitespace_found && starts_with(c, "://"))
return -1;
return c - line;
}
if (!whitespace_found && (isalnum(*c) || *c == '-'))
continue;
if (c != line && (*c == ' ' || *c == '\t')) {