{"thread":{"id":"66448","subject":"[PATCH] doc: don't require a SYNOPSIS in section 7","startedAt":"2026-10-02T16:07:10Z","lastAt":"2026-10-04T13:17:31Z","messageCount":11,"participants":["Julia Evans via GitGitGadget","Junio C Hamano","Julia Evans","Tuomas Ahola"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"553979","messageId":"pull.2246.git.1790957227881.gitgitgadget@gmail.com","threadId":"66448","inReplyTo":null,"subject":"[PATCH] doc: don't require a SYNOPSIS in section 7","fromName":"Julia Evans via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-10-02T16:07:07Z","receivedAt":"2026-10-02T16:07:10Z","isPatch":true,"body":"From: Julia Evans <julia@jvns.ca>\n\nRemove the SYNOPSIS section from the section 7 man pages where\nappropriate, to avoid having a section that contains no information.\nIt's not the norm in section 7 to always require a SYNOPSIS.\n\nUpdate the perl script with a special case for section 7.\n\nTested by running `make lint-docs`, and looked at the renaming synopses\nwith this fish script snippet:\n\nfor i in *.7\n   echo $i; grep SYNOPSIS -A 5 (string replace .7 .adoc $i)\nend\n\nSigned-off-by: Julia Evans <julia@jvns.ca>\n---\n    doc: don't require a SYNOPSIS in section 7\n    \n    Seemed like a nice quick improvement, though happy to drop this if it\n    turns into a can of worms\n    \n    I haven't written Perl since probably 2007 so might have made a mistake\n    there but the code does seem to run :). Even managed to write it with no\n    LLMs and just some good ol perlrequick.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-2246%2Fjvns%2Fno-synopsis-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2246/jvns/no-synopsis-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/2246\n\n Documentation/gitcli.adoc                 | 5 -----\n Documentation/gitcore-tutorial.adoc       | 4 ----\n Documentation/gitdatamodel.adoc           | 4 ----\n Documentation/giteveryday.adoc            | 5 -----\n Documentation/gitfaq.adoc                 | 4 ----\n Documentation/gitglossary.adoc            | 4 ----\n Documentation/gitpacking.adoc             | 4 ----\n Documentation/gitrevisions.adoc           | 5 -----\n Documentation/gittutorial-2.adoc          | 5 -----\n Documentation/gittutorial.adoc            | 5 -----\n Documentation/gitworkflows.adoc           | 6 ------\n Documentation/lint-man-section-order.perl | 7 +++++++\n 12 files changed, 7 insertions(+), 51 deletions(-)\n\ndiff --git a/Documentation/gitcli.adoc b/Documentation/gitcli.adoc\nindex 6815d6bfb7..9c4598e29c 100644\n--- a/Documentation/gitcli.adoc\n+++ b/Documentation/gitcli.adoc\n@@ -5,11 +5,6 @@ NAME\n ----\n gitcli - Git command-line interface and conventions\n \n-SYNOPSIS\n---------\n-gitcli\n-\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gitcore-tutorial.adoc b/Documentation/gitcore-tutorial.adoc\nindex 2122aeb976..71fda63a1c 100644\n--- a/Documentation/gitcore-tutorial.adoc\n+++ b/Documentation/gitcore-tutorial.adoc\n@@ -5,10 +5,6 @@ NAME\n ----\n gitcore-tutorial - A Git core tutorial for developers\n \n-SYNOPSIS\n---------\n-git *\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gitdatamodel.adoc b/Documentation/gitdatamodel.adoc\nindex 56b7635c19..8d9be02036 100644\n--- a/Documentation/gitdatamodel.adoc\n+++ b/Documentation/gitdatamodel.adoc\n@@ -5,10 +5,6 @@ NAME\n ----\n gitdatamodel - Git's core data model\n \n-SYNOPSIS\n---------\n-gitdatamodel\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/giteveryday.adoc b/Documentation/giteveryday.adoc\nindex 6cfdd0e07b..0c9db2f150 100644\n--- a/Documentation/giteveryday.adoc\n+++ b/Documentation/giteveryday.adoc\n@@ -5,11 +5,6 @@ NAME\n ----\n giteveryday - A useful minimum set of commands for Everyday Git\n \n-SYNOPSIS\n---------\n-\n-Everyday Git With 20 Commands Or So\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gitfaq.adoc b/Documentation/gitfaq.adoc\nindex f6c9b9d9f7..b26e4e3a09 100644\n--- a/Documentation/gitfaq.adoc\n+++ b/Documentation/gitfaq.adoc\n@@ -5,10 +5,6 @@ NAME\n ----\n gitfaq - Frequently asked questions about using Git\n \n-SYNOPSIS\n---------\n-gitfaq\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gitglossary.adoc b/Documentation/gitglossary.adoc\nindex b046d9cb29..eb1e60832e 100644\n--- a/Documentation/gitglossary.adoc\n+++ b/Documentation/gitglossary.adoc\n@@ -5,10 +5,6 @@ NAME\n ----\n gitglossary - A Git Glossary\n \n-SYNOPSIS\n---------\n-*\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gitpacking.adoc b/Documentation/gitpacking.adoc\nindex e6de6ec824..b0d952c797 100644\n--- a/Documentation/gitpacking.adoc\n+++ b/Documentation/gitpacking.adoc\n@@ -5,10 +5,6 @@ NAME\n ----\n gitpacking - Advanced concepts related to packing in Git\n \n-SYNOPSIS\n---------\n-gitpacking\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gitrevisions.adoc b/Documentation/gitrevisions.adoc\nindex 7146117de5..4412f84d83 100644\n--- a/Documentation/gitrevisions.adoc\n+++ b/Documentation/gitrevisions.adoc\n@@ -5,11 +5,6 @@ NAME\n ----\n gitrevisions - Specifying revisions and ranges for Git\n \n-SYNOPSIS\n---------\n-gitrevisions\n-\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gittutorial-2.adoc b/Documentation/gittutorial-2.adoc\nindex 8bdb7d0bd3..6a4d482ed6 100644\n--- a/Documentation/gittutorial-2.adoc\n+++ b/Documentation/gittutorial-2.adoc\n@@ -5,11 +5,6 @@ NAME\n ----\n gittutorial-2 - A tutorial introduction to Git: part two\n \n-SYNOPSIS\n---------\n-[verse]\n-git *\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gittutorial.adoc b/Documentation/gittutorial.adoc\nindex 519b8d8be2..03120ba191 100644\n--- a/Documentation/gittutorial.adoc\n+++ b/Documentation/gittutorial.adoc\n@@ -5,11 +5,6 @@ NAME\n ----\n gittutorial - A tutorial introduction to Git\n \n-SYNOPSIS\n---------\n-[verse]\n-git *\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gitworkflows.adoc b/Documentation/gitworkflows.adoc\nindex 59305265c5..ad02828bff 100644\n--- a/Documentation/gitworkflows.adoc\n+++ b/Documentation/gitworkflows.adoc\n@@ -5,12 +5,6 @@ NAME\n ----\n gitworkflows - An overview of recommended workflows with Git\n \n-SYNOPSIS\n---------\n-[verse]\n-git *\n-\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/lint-man-section-order.perl b/Documentation/lint-man-section-order.perl\nindex 02408a0062..e032f6ae53 100755\n--- a/Documentation/lint-man-section-order.perl\n+++ b/Documentation/lint-man-section-order.perl\n@@ -53,6 +53,11 @@ sub report {\n \t$exit_code = 1;\n }\n \n+# assume the first line is formatted like 'gitglossary(7)'\n+my $firstline = <>;\n+$firstline =~ m/\\((\\d)\\)/;\n+my $man_section_number = $1;\n+\n my $last_was_section;\n my @actual_order;\n while (my $line = <>) {\n@@ -93,6 +98,8 @@ while (my $line = <>) {\n \n \t\tfor my $section (sort keys %SECTIONS) {\n \t\t\tnext if !$SECTIONS{$section}->{required} or exists $actual_sections{$section};\n+\t\t\t# Synopsis is not required in section 7\n+\t\t\tnext if ($section eq \"SYNOPSIS\" && $man_section_number eq \"7\");\n \t\t\treport(\"has no required '$section' section!\");\n \t\t}\n \n\nbase-commit: a018953688f1b10bddf91bff8747068f5f4746a4\n-- \ngitgitgadget\n"},{"id":"553989","messageId":"xmqqv77kvwgr.fsf@gitster.g","threadId":"66448","inReplyTo":"pull.2246.git.1790957227881.gitgitgadget@gmail.com","subject":"Re: [PATCH] doc: don't require a SYNOPSIS in section 7","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-10-02T17:33:24Z","receivedAt":"2026-10-02T17:33:26Z","isPatch":true,"body":"\"Julia Evans via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> From: Julia Evans <julia@jvns.ca>\n>\n> Remove the SYNOPSIS section from the section 7 man pages where\n> appropriate, to avoid having a section that contains no information.\n> It's not the norm in section 7 to always require a SYNOPSIS.\n\nVery true.\n\n> diff --git a/Documentation/gitcli.adoc b/Documentation/gitcli.adoc\n> index 6815d6bfb7..9c4598e29c 100644\n> --- a/Documentation/gitcli.adoc\n> +++ b/Documentation/gitcli.adoc\n> @@ -5,11 +5,6 @@ NAME\n>  ----\n>  gitcli - Git command-line interface and conventions\n>  \n> -SYNOPSIS\n> ---------\n> -gitcli\n> -\n> -\n>  DESCRIPTION\n>  -----------\n>  \n\nYup.  Thanks for starting this move.  These \"we add meaningless\nfiller only because we need to\" were always eyesore.\n\n> diff --git a/Documentation/lint-man-section-order.perl b/Documentation/lint-man-section-order.perl\n> index 02408a0062..e032f6ae53 100755\n> --- a/Documentation/lint-man-section-order.perl\n> +++ b/Documentation/lint-man-section-order.perl\n> @@ -53,6 +53,11 @@ sub report {\n>  \t$exit_code = 1;\n>  }\n>  \n> +# assume the first line is formatted like 'gitglossary(7)'\n> +my $firstline = <>;\n> +$firstline =~ m/\\((\\d)\\)/;\n> +my $man_section_number = $1;\n\nThis means that the main loop that has already read all the lines of\nthe file no longer sees the first line.  I do not think it would\nimmediately break anything (in other words, the current\nimplementation of the loop only checks the section header and\nnothing else), but it may be an unhealthy thing to assume that this\nwill not change.\n\nIt would be very simple to move it inside the loop.\n\nWould it work better to do it this way, I wonder?  The idea is to\nnotice what manual sections we are in, and tweak the %SECTIONS\ncontents there, to allow us customize behaviour for other sections\nlater, and keep such customizations out of the actual code.\n\n\n Documentation/lint-man-section-order.perl | 15 +++++++++++++++\n 1 file changed, 15 insertions(+)\n\ndiff --git c/Documentation/lint-man-section-order.perl w/Documentation/lint-man-section-order.perl\nindex 02408a0062..ce60c34809 100755\n--- c/Documentation/lint-man-section-order.perl\n+++ w/Documentation/lint-man-section-order.perl\n@@ -55,8 +55,23 @@ sub report {\n \n my $last_was_section;\n my @actual_order;\n+my $section_tweak_done;\n while (my $line = <>) {\n \tchomp $line;\n+\n+\tif (!$section_tweak_done) {\n+\t\t# assume the first line is formatted like 'gitglossary(7)'\n+\t\tmy $firstline = <>;\n+\t\t$firstline =~ m/\\((\\d)\\)/;\n+\t\tmy $man_section_number = $1;\n+\n+\t\tif ($man_section_number == \"7\") {\n+\t\t\t# section 7 usually do not have SYNOPSIS\n+\t\t\t$SECTIONS{SYNOPSIS}{required} = 0;\n+\t\t}\n+\t\t$section_tweak_done = 1;\n+\t}\n+\n \tif ($line =~ $SECTION_RX) {\n \t\tpush @actual_order => $line;\n \t\t$last_was_section = 1;\n"},{"id":"553995","messageId":"xmqq7bk0vv38.fsf@gitster.g","threadId":"66448","inReplyTo":"xmqqv77kvwgr.fsf@gitster.g","subject":"Re: [PATCH] doc: don't require a SYNOPSIS in section 7","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-10-02T18:03:07Z","receivedAt":"2026-10-02T18:03:10Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> diff --git c/Documentation/lint-man-section-order.perl w/Documentation/lint-man-section-order.perl\n> index 02408a0062..ce60c34809 100755\n> --- c/Documentation/lint-man-section-order.perl\n> +++ w/Documentation/lint-man-section-order.perl\n> @@ -55,8 +55,23 @@ sub report {\n>  \n>  my $last_was_section;\n>  my @actual_order;\n> +my $section_tweak_done;\n>  while (my $line = <>) {\n>  \tchomp $line;\n> +\n> +\tif (!$section_tweak_done) {\n> +\t\t# assume the first line is formatted like 'gitglossary(7)'\n> +\t\tmy $firstline = <>;\n\nAh, this was obviously buggy.  Not <>, but we should use $line here.\n\n> +\t\t$firstline =~ m/\\((\\d)\\)/;\n> +\t\tmy $man_section_number = $1;\n> +\n> +\t\tif ($man_section_number == \"7\") {\n> +\t\t\t# section 7 usually do not have SYNOPSIS\n> +\t\t\t$SECTIONS{SYNOPSIS}{required} = 0;\n> +\t\t}\n> +\t\t$section_tweak_done = 1;\n> +\t}\n> +\n>  \tif ($line =~ $SECTION_RX) {\n>  \t\tpush @actual_order => $line;\n>  \t\t$last_was_section = 1;\n"},{"id":"553996","messageId":"bdc1fd67-83dd-4c66-9afe-7f35c572afa3@app.fastmail.com","threadId":"66448","inReplyTo":"xmqq7bk0vv38.fsf@gitster.g","subject":"Re: [PATCH] doc: don't require a SYNOPSIS in section 7","fromName":"Julia Evans","fromEmail":"julia@jvns.ca","sentAt":"2026-10-02T18:10:09Z","receivedAt":"2026-10-02T18:10:30Z","isPatch":true,"body":"On Fri, Oct 2, 2026, at 2:03 PM, Junio C Hamano wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> diff --git c/Documentation/lint-man-section-order.perl w/Documentation/lint-man-section-order.perl\n>> index 02408a0062..ce60c34809 100755\n>> --- c/Documentation/lint-man-section-order.perl\n>> +++ w/Documentation/lint-man-section-order.perl\n>> @@ -55,8 +55,23 @@ sub report {\n>>  \n>>  my $last_was_section;\n>>  my @actual_order;\n>> +my $section_tweak_done;\n>>  while (my $line = <>) {\n>>  \tchomp $line;\n>> +\n>> +\tif (!$section_tweak_done) {\n>> +\t\t# assume the first line is formatted like 'gitglossary(7)'\n>> +\t\tmy $firstline = <>;\n>\n> Ah, this was obviously buggy.  Not <>, but we should use $line here.\n>\n>> +\t\t$firstline =~ m/\\((\\d)\\)/;\n>> +\t\tmy $man_section_number = $1;\n>> +\n>> +\t\tif ($man_section_number == \"7\") {\n>> +\t\t\t# section 7 usually do not have SYNOPSIS\n>> +\t\t\t$SECTIONS{SYNOPSIS}{required} = 0;\n>> +\t\t}\n>> +\t\t$section_tweak_done = 1;\n>> +\t}\n>> +\n>>  \tif ($line =~ $SECTION_RX) {\n>>  \t\tpush @actual_order => $line;\n>>  \t\t$last_was_section = 1;\n\nI'm happy with whichever version of the script you think is easiest to maintain.\nI saw that perl also has Tie::File built in which lets you just treat the file as an\narray instead of worrying about <>. https://metacpan.org/pod/Tie::File\n"},{"id":"553997","messageId":"01891b4b-ce04-41aa-8065-d7b88e466dbc@app.fastmail.com","threadId":"66448","inReplyTo":"pull.2246.git.1790957227881.gitgitgadget@gmail.com","subject":"Re: [PATCH] doc: don't require a SYNOPSIS in section 7","fromName":"Julia Evans","fromEmail":"julia@jvns.ca","sentAt":"2026-10-02T18:20:47Z","receivedAt":"2026-10-02T18:21:08Z","isPatch":true,"body":"> +# assume the first line is formatted like 'gitglossary(7)'\n> +my $firstline = <>;\n> +$firstline =~ m/\\((\\d)\\)/;\n> +my $man_section_number = $1;\n> +\n>  my $last_was_section;\n>  my @actual_order;\n>  while (my $line = <>) {\n> @@ -93,6 +98,8 @@ while (my $line = <>) {\n> \n>  \t\tfor my $section (sort keys %SECTIONS) {\n>  \t\t\tnext if !$SECTIONS{$section}->{required} or exists \n> $actual_sections{$section};\n> +\t\t\t# Synopsis is not required in section 7\n> +\t\t\tnext if ($section eq \"SYNOPSIS\" && $man_section_number eq \"7\");\n>  \t\t\treport(\"has no required '$section' section!\");\n>  \t\t}\n\n\nI just realized that this script is actually supposed to be able to process multiple\nfiles as command line arguments, and that this patch won't work for that.\n\nI don't understand how Perl's `<>`  works when you pass multiple files as\ncommand line arguments and that might be too much of a can of worms for me to\nfigure right now :/\n"},{"id":"554012","messageId":"xmqqo6dbvlaf.fsf@gitster.g","threadId":"66448","inReplyTo":"01891b4b-ce04-41aa-8065-d7b88e466dbc@app.fastmail.com","subject":"Re: [PATCH] doc: don't require a SYNOPSIS in section 7","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-10-02T21:34:48Z","receivedAt":"2026-10-02T21:34:50Z","isPatch":true,"body":"\"Julia Evans\" <julia@jvns.ca> writes:\n\n>> +# assume the first line is formatted like 'gitglossary(7)'\n>> +my $firstline = <>;\n>> +$firstline =~ m/\\((\\d)\\)/;\n>> +my $man_section_number = $1;\n>> +\n>>  my $last_was_section;\n>>  my @actual_order;\n>>  while (my $line = <>) {\n>> @@ -93,6 +98,8 @@ while (my $line = <>) {\n>> \n>>  \t\tfor my $section (sort keys %SECTIONS) {\n>>  \t\t\tnext if !$SECTIONS{$section}->{required} or exists \n>> $actual_sections{$section};\n>> +\t\t\t# Synopsis is not required in section 7\n>> +\t\t\tnext if ($section eq \"SYNOPSIS\" && $man_section_number eq \"7\");\n>>  \t\t\treport(\"has no required '$section' section!\");\n>>  \t\t}\n>\n>\n> I just realized that this script is actually supposed to be able to process multiple\n> files as command line arguments, and that this patch won't work for that.\n\nYeah, your version would then notice only the first line of the\nfirst file, and my update would also do the same.\n\nYou can work from what I gave you and inside the \"eof\" part of the\nloop reset the %SECTIONS back to the original (which means you'd\nneed to keep a separate copy of the original) and also reset the\n\"did I tweak the %SECTIONS thing already?  have I handled the first\nline of the current file?\" variable.\n\n> I don't understand how Perl's `<>`  works when you pass multiple files as\n> command line arguments and that might be too much of a can of worms for me to\n> figure right now :/\n\n\"man perlfunc\" section on \"eof\" has an example to show what to\ndetect and reset when you reached the end of each file within a\n\"while (<>)\" loop.\n\n               # reset line numbering on each input file\n               while (<>) {\n                   next if /^\\s*#/;  # skip comments\n                   print \"$.\\t$_\";\n               } continue {\n                   close ARGV if eof;  # Not eof()!\n               }\n\nThe explicit \"close ARGV if eof;\" is how the example resets the\n$. counter (which by default counts all the lines coming from <>\nacross multiple files).\n\n"},{"id":"554046","messageId":"20261003073303.G-Gck%taahol@utu.fi","threadId":"66448","inReplyTo":"xmqqo6dbvlaf.fsf@gitster.g","subject":"Re: [PATCH] doc: don't require a SYNOPSIS in section 7","fromName":"Tuomas Ahola","fromEmail":"taahol@utu.fi","sentAt":"2026-10-03T07:33:03Z","receivedAt":"2026-10-03T07:33:18Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> wrote:\n\n> \"Julia Evans\" <julia@jvns.ca> writes:\n> \n> >> +# assume the first line is formatted like 'gitglossary(7)'\n> >> +my $firstline = <>;\n> >> +$firstline =~ m/\\((\\d)\\)/;\n> >> +my $man_section_number = $1;\n> >> +\n> >>  my $last_was_section;\n> >>  my @actual_order;\n> >>  while (my $line = <>) {\n> >> @@ -93,6 +98,8 @@ while (my $line = <>) {\n> >> \n> >>  \t\tfor my $section (sort keys %SECTIONS) {\n> >>  \t\t\tnext if !$SECTIONS{$section}->{required} or exists \n> >> $actual_sections{$section};\n> >> +\t\t\t# Synopsis is not required in section 7\n> >> +\t\t\tnext if ($section eq \"SYNOPSIS\" && $man_section_number eq \"7\");\n> >>  \t\t\treport(\"has no required '$section' section!\");\n> >>  \t\t}\n> >\n> >\n> > I just realized that this script is actually supposed to be able to process multiple\n> > files as command line arguments, and that this patch won't work for that.\n> \n> Yeah, your version would then notice only the first line of the\n> first file, and my update would also do the same.\n> \n> You can work from what I gave you and inside the \"eof\" part of the\n> loop reset the %SECTIONS back to the original (which means you'd\n> need to keep a separate copy of the original) and also reset the\n> \"did I tweak the %SECTIONS thing already?  have I handled the first\n> line of the current file?\" variable.\n> \n\nSomething slightly more declarative I managed to hack up:\n\ndiff --git a/Documentation/lint-man-section-order.perl b/Documentation/lint-man-section-order.perl\nindex 02408a0062..160c65e1be 100755\n--- a/Documentation/lint-man-section-order.perl\n+++ b/Documentation/lint-man-section-order.perl\n@@ -13,6 +13,9 @@\n \t\t},\n \t\t'SYNOPSIS' => {\n \t\t\trequired => 1,\n+\t\t\toptional_in_man_sections => {\n+\t\t\t\t'7' => 1,\n+\t\t\t},\n \t\t\torder => $order++,\n \t\t},\n \t\t'DESCRIPTION' => {\n@@ -53,10 +56,18 @@ sub report {\n \t$exit_code = 1;\n }\n \n+my $man_section_number;\n my $last_was_section;\n my @actual_order;\n while (my $line = <>) {\n \tchomp $line;\n+\n+\tif ($. == 1) {\n+\t\t# assume the first line is formatted like 'gitglossary(7)'\n+\t\t$line =~ m/\\((\\d)\\)/;\n+\t\t$man_section_number = $1;\n+\t}\n+\n \tif ($line =~ $SECTION_RX) {\n \t\tpush @actual_order => $line;\n \t\t$last_was_section = 1;\n@@ -92,7 +103,9 @@ sub report {\n \t\t@actual_sections{@actual_order} = ();\n \n \t\tfor my $section (sort keys %SECTIONS) {\n-\t\t\tnext if !$SECTIONS{$section}->{required} or exists $actual_sections{$section};\n+\t\t\tnext if !$SECTIONS{$section}->{required} or\n+\t\t\t\t$SECTIONS{$section}->{optional_in_man_sections}->{$man_section_number} or\n+\t\t\t\texists $actual_sections{$section};\n \t\t\treport(\"has no required '$section' section!\");\n \t\t}\n \n"},{"id":"554055","messageId":"79451beb-15c4-42f3-92fe-1b7fd284b21c@app.fastmail.com","threadId":"66448","inReplyTo":"20261003073303.G-Gck%taahol@utu.fi","subject":"Re: [PATCH] doc: don't require a SYNOPSIS in section 7","fromName":"Julia Evans","fromEmail":"julia@jvns.ca","sentAt":"2026-10-03T11:37:00Z","receivedAt":"2026-10-03T11:39:12Z","isPatch":true,"body":"> Something slightly more declarative I managed to hack up:\n>\n> diff --git a/Documentation/lint-man-section-order.perl \n> b/Documentation/lint-man-section-order.perl\n> index 02408a0062..160c65e1be 100755\n> --- a/Documentation/lint-man-section-order.perl\n> +++ b/Documentation/lint-man-section-order.perl\n> @@ -13,6 +13,9 @@\n>  \t\t},\n>  \t\t'SYNOPSIS' => {\n>  \t\t\trequired => 1,\n> +\t\t\toptional_in_man_sections => {\n> +\t\t\t\t'7' => 1,\n> +\t\t\t},\n>  \t\t\torder => $order++,\n>  \t\t},\n>  \t\t'DESCRIPTION' => {\n> @@ -53,10 +56,18 @@ sub report {\n>  \t$exit_code = 1;\n>  }\n> \n> +my $man_section_number;\n>  my $last_was_section;\n>  my @actual_order;\n>  while (my $line = <>) {\n>  \tchomp $line;\n> +\n> +\tif ($. == 1) {\n> +\t\t# assume the first line is formatted like 'gitglossary(7)'\n> +\t\t$line =~ m/\\((\\d)\\)/;\n> +\t\t$man_section_number = $1;\n> +\t}\n> +\n>  \tif ($line =~ $SECTION_RX) {\n>  \t\tpush @actual_order => $line;\n>  \t\t$last_was_section = 1;\n> @@ -92,7 +103,9 @@ sub report {\n>  \t\t@actual_sections{@actual_order} = ();\n> \n>  \t\tfor my $section (sort keys %SECTIONS) {\n> -\t\t\tnext if !$SECTIONS{$section}->{required} or exists \n> $actual_sections{$section};\n> +\t\t\tnext if !$SECTIONS{$section}->{required} or\n> +\t\t\t\t$SECTIONS{$section}->{optional_in_man_sections}->{$man_section_number} \n> or\n> +\t\t\t\texists $actual_sections{$section};\n>  \t\t\treport(\"has no required '$section' section!\");\n>  \t\t}\n\nThis looks great! Will use for v2 and mark you as a coauthor, thank you :D\n(let me know if there's a better way to do that also, still learning the process)\n\nI wasn't sure what `$.` was before but this makes it clear that it's the current\nline number (and https://perldoc.perl.org/perlvar agrees). Apparently\n`$ARGV` is the name of the current file. (different from @ARGV)\n"},{"id":"554057","messageId":"20261003125511.B8Nsu%taahol@utu.fi","threadId":"66448","inReplyTo":"79451beb-15c4-42f3-92fe-1b7fd284b21c@app.fastmail.com","subject":"Re: [PATCH] doc: don't require a SYNOPSIS in section 7","fromName":"Tuomas Ahola","fromEmail":"taahol@utu.fi","sentAt":"2026-10-03T12:55:11Z","receivedAt":"2026-10-03T12:55:22Z","isPatch":true,"body":"\"Julia Evans\" <julia@jvns.ca> wrote:\n\n> > Something slightly more declarative I managed to hack up:\n> >\n> \n> This looks great! Will use for v2 and mark you as a coauthor, thank you :D\n> (let me know if there's a better way to do that also, still learning the process)\n> \n\nCool!  You can add these before your S-o-b line:\n\n\tCo-authored-by: Tuomas Ahola <taahol@utu.fi>\n\tSigned-off-by: Tuomas Ahola <taahol@utu.fi>\n\nThat seems to be the usual formula for marking coauthors (cf. [1] for a random\nexample).\n\n> I wasn't sure what `$.` was before but this makes it clear that it's the current\n> line number (and https://perldoc.perl.org/perlvar agrees). Apparently\n> `$ARGV` is the name of the current file. (different from @ARGV)\n\nYes, the Perl syntax is... interesting.\n\nLinks:\n  1. https://lore.kernel.org/git/20260711160447.99708-3-marcelomlage@usp.br/\n"},{"id":"554059","messageId":"pull.2246.v2.git.1791033057232.gitgitgadget@gmail.com","threadId":"66448","inReplyTo":"pull.2246.git.1790957227881.gitgitgadget@gmail.com","subject":"[PATCH v2] doc: don't require a SYNOPSIS in section 7","fromName":"Julia Evans via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-10-03T13:10:57Z","receivedAt":"2026-10-03T13:11:00Z","isPatch":true,"body":"From: Julia Evans <julia@jvns.ca>\n\nRemove the SYNOPSIS section from the section 7 man pages where\nappropriate, to avoid having a section that contains no information.\nIt's not the norm in section 7 to always require a SYNOPSIS.\n\nUpdate the perl script with a special case for section 7.\n\nTested by running `make lint-docs`, and looked at the renaming synopses\nwith this fish script snippet:\n\nfor i in *.7\n   echo $i; grep SYNOPSIS -A 5 (string replace .7 .adoc $i)\nend\n\nCo-authored-by: Tuomas Ahola <taahol@utu.fi>\nSigned-off-by: Tuomas Ahola <taahol@utu.fi>\nSigned-off-by: Julia Evans <julia@jvns.ca>\n---\n    doc: don't require a SYNOPSIS in section 7\n    \n    Changes in v2: Tuomas rewrote the Perl script changes to be both more\n    declarative and and more correct. Previously it didn't work if there\n    were multiple files passed on the command line.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-2246%2Fjvns%2Fno-synopsis-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2246/jvns/no-synopsis-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/2246\n\nRange-diff vs v1:\n\n 1:  b6f8878a1f ! 1:  d6004e0c6b doc: don't require a SYNOPSIS in section 7\n     @@ Commit message\n             echo $i; grep SYNOPSIS -A 5 (string replace .7 .adoc $i)\n          end\n      \n     +    Co-authored-by: Tuomas Ahola <taahol@utu.fi>\n     +    Signed-off-by: Tuomas Ahola <taahol@utu.fi>\n          Signed-off-by: Julia Evans <julia@jvns.ca>\n      \n       ## Documentation/gitcli.adoc ##\n     @@ Documentation/gitworkflows.adoc: NAME\n       \n      \n       ## Documentation/lint-man-section-order.perl ##\n     +@@ Documentation/lint-man-section-order.perl: my %SECTIONS;\n     + \t\t},\n     + \t\t'SYNOPSIS' => {\n     + \t\t\trequired => 1,\n     ++\t\t\toptional_in_man_sections => {\n     ++\t\t\t\t'7' => 1,\n     ++\t\t\t},\n     + \t\t\torder => $order++,\n     + \t\t},\n     + \t\t'DESCRIPTION' => {\n      @@ Documentation/lint-man-section-order.perl: sub report {\n       \t$exit_code = 1;\n       }\n       \n     -+# assume the first line is formatted like 'gitglossary(7)'\n     -+my $firstline = <>;\n     -+$firstline =~ m/\\((\\d)\\)/;\n     -+my $man_section_number = $1;\n     -+\n     ++my $man_section_number;\n       my $last_was_section;\n       my @actual_order;\n       while (my $line = <>) {\n     + \tchomp $line;\n     ++\n     ++\tif ($. == 1) {\n     ++\t\t# assume the first line is formatted like 'gitglossary(7)'\n     ++\t\t$line =~ m/\\((\\d)\\)/;\n     ++\t\t$man_section_number = $1;\n     ++\t}\n     ++\n     + \tif ($line =~ $SECTION_RX) {\n     + \t\tpush @actual_order => $line;\n     + \t\t$last_was_section = 1;\n      @@ Documentation/lint-man-section-order.perl: while (my $line = <>) {\n     + \t\t@actual_sections{@actual_order} = ();\n       \n       \t\tfor my $section (sort keys %SECTIONS) {\n     - \t\t\tnext if !$SECTIONS{$section}->{required} or exists $actual_sections{$section};\n     -+\t\t\t# Synopsis is not required in section 7\n     -+\t\t\tnext if ($section eq \"SYNOPSIS\" && $man_section_number eq \"7\");\n     +-\t\t\tnext if !$SECTIONS{$section}->{required} or exists $actual_sections{$section};\n     ++\t\t\tnext if !$SECTIONS{$section}->{required} or\n     ++\t\t\t\t$SECTIONS{$section}->{optional_in_man_sections}->{$man_section_number} or\n     ++\t\t\t\texists $actual_sections{$section};\n       \t\t\treport(\"has no required '$section' section!\");\n       \t\t}\n       \n\n\n Documentation/gitcli.adoc                 |  5 -----\n Documentation/gitcore-tutorial.adoc       |  4 ----\n Documentation/gitdatamodel.adoc           |  4 ----\n Documentation/giteveryday.adoc            |  5 -----\n Documentation/gitfaq.adoc                 |  4 ----\n Documentation/gitglossary.adoc            |  4 ----\n Documentation/gitpacking.adoc             |  4 ----\n Documentation/gitrevisions.adoc           |  5 -----\n Documentation/gittutorial-2.adoc          |  5 -----\n Documentation/gittutorial.adoc            |  5 -----\n Documentation/gitworkflows.adoc           |  6 ------\n Documentation/lint-man-section-order.perl | 15 ++++++++++++++-\n 12 files changed, 14 insertions(+), 52 deletions(-)\n\ndiff --git a/Documentation/gitcli.adoc b/Documentation/gitcli.adoc\nindex 6815d6bfb7..9c4598e29c 100644\n--- a/Documentation/gitcli.adoc\n+++ b/Documentation/gitcli.adoc\n@@ -5,11 +5,6 @@ NAME\n ----\n gitcli - Git command-line interface and conventions\n \n-SYNOPSIS\n---------\n-gitcli\n-\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gitcore-tutorial.adoc b/Documentation/gitcore-tutorial.adoc\nindex 2122aeb976..71fda63a1c 100644\n--- a/Documentation/gitcore-tutorial.adoc\n+++ b/Documentation/gitcore-tutorial.adoc\n@@ -5,10 +5,6 @@ NAME\n ----\n gitcore-tutorial - A Git core tutorial for developers\n \n-SYNOPSIS\n---------\n-git *\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gitdatamodel.adoc b/Documentation/gitdatamodel.adoc\nindex 56b7635c19..8d9be02036 100644\n--- a/Documentation/gitdatamodel.adoc\n+++ b/Documentation/gitdatamodel.adoc\n@@ -5,10 +5,6 @@ NAME\n ----\n gitdatamodel - Git's core data model\n \n-SYNOPSIS\n---------\n-gitdatamodel\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/giteveryday.adoc b/Documentation/giteveryday.adoc\nindex 6cfdd0e07b..0c9db2f150 100644\n--- a/Documentation/giteveryday.adoc\n+++ b/Documentation/giteveryday.adoc\n@@ -5,11 +5,6 @@ NAME\n ----\n giteveryday - A useful minimum set of commands for Everyday Git\n \n-SYNOPSIS\n---------\n-\n-Everyday Git With 20 Commands Or So\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gitfaq.adoc b/Documentation/gitfaq.adoc\nindex f6c9b9d9f7..b26e4e3a09 100644\n--- a/Documentation/gitfaq.adoc\n+++ b/Documentation/gitfaq.adoc\n@@ -5,10 +5,6 @@ NAME\n ----\n gitfaq - Frequently asked questions about using Git\n \n-SYNOPSIS\n---------\n-gitfaq\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gitglossary.adoc b/Documentation/gitglossary.adoc\nindex b046d9cb29..eb1e60832e 100644\n--- a/Documentation/gitglossary.adoc\n+++ b/Documentation/gitglossary.adoc\n@@ -5,10 +5,6 @@ NAME\n ----\n gitglossary - A Git Glossary\n \n-SYNOPSIS\n---------\n-*\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gitpacking.adoc b/Documentation/gitpacking.adoc\nindex e6de6ec824..b0d952c797 100644\n--- a/Documentation/gitpacking.adoc\n+++ b/Documentation/gitpacking.adoc\n@@ -5,10 +5,6 @@ NAME\n ----\n gitpacking - Advanced concepts related to packing in Git\n \n-SYNOPSIS\n---------\n-gitpacking\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gitrevisions.adoc b/Documentation/gitrevisions.adoc\nindex 7146117de5..4412f84d83 100644\n--- a/Documentation/gitrevisions.adoc\n+++ b/Documentation/gitrevisions.adoc\n@@ -5,11 +5,6 @@ NAME\n ----\n gitrevisions - Specifying revisions and ranges for Git\n \n-SYNOPSIS\n---------\n-gitrevisions\n-\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gittutorial-2.adoc b/Documentation/gittutorial-2.adoc\nindex 8bdb7d0bd3..6a4d482ed6 100644\n--- a/Documentation/gittutorial-2.adoc\n+++ b/Documentation/gittutorial-2.adoc\n@@ -5,11 +5,6 @@ NAME\n ----\n gittutorial-2 - A tutorial introduction to Git: part two\n \n-SYNOPSIS\n---------\n-[verse]\n-git *\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gittutorial.adoc b/Documentation/gittutorial.adoc\nindex 519b8d8be2..03120ba191 100644\n--- a/Documentation/gittutorial.adoc\n+++ b/Documentation/gittutorial.adoc\n@@ -5,11 +5,6 @@ NAME\n ----\n gittutorial - A tutorial introduction to Git\n \n-SYNOPSIS\n---------\n-[verse]\n-git *\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/gitworkflows.adoc b/Documentation/gitworkflows.adoc\nindex 59305265c5..ad02828bff 100644\n--- a/Documentation/gitworkflows.adoc\n+++ b/Documentation/gitworkflows.adoc\n@@ -5,12 +5,6 @@ NAME\n ----\n gitworkflows - An overview of recommended workflows with Git\n \n-SYNOPSIS\n---------\n-[verse]\n-git *\n-\n-\n DESCRIPTION\n -----------\n \ndiff --git a/Documentation/lint-man-section-order.perl b/Documentation/lint-man-section-order.perl\nindex 02408a0062..160c65e1be 100755\n--- a/Documentation/lint-man-section-order.perl\n+++ b/Documentation/lint-man-section-order.perl\n@@ -13,6 +13,9 @@ my %SECTIONS;\n \t\t},\n \t\t'SYNOPSIS' => {\n \t\t\trequired => 1,\n+\t\t\toptional_in_man_sections => {\n+\t\t\t\t'7' => 1,\n+\t\t\t},\n \t\t\torder => $order++,\n \t\t},\n \t\t'DESCRIPTION' => {\n@@ -53,10 +56,18 @@ sub report {\n \t$exit_code = 1;\n }\n \n+my $man_section_number;\n my $last_was_section;\n my @actual_order;\n while (my $line = <>) {\n \tchomp $line;\n+\n+\tif ($. == 1) {\n+\t\t# assume the first line is formatted like 'gitglossary(7)'\n+\t\t$line =~ m/\\((\\d)\\)/;\n+\t\t$man_section_number = $1;\n+\t}\n+\n \tif ($line =~ $SECTION_RX) {\n \t\tpush @actual_order => $line;\n \t\t$last_was_section = 1;\n@@ -92,7 +103,9 @@ while (my $line = <>) {\n \t\t@actual_sections{@actual_order} = ();\n \n \t\tfor my $section (sort keys %SECTIONS) {\n-\t\t\tnext if !$SECTIONS{$section}->{required} or exists $actual_sections{$section};\n+\t\t\tnext if !$SECTIONS{$section}->{required} or\n+\t\t\t\t$SECTIONS{$section}->{optional_in_man_sections}->{$man_section_number} or\n+\t\t\t\texists $actual_sections{$section};\n \t\t\treport(\"has no required '$section' section!\");\n \t\t}\n \n\nbase-commit: a018953688f1b10bddf91bff8747068f5f4746a4\n-- \ngitgitgadget\n"},{"id":"554111","messageId":"xmqqece5vc48.fsf@gitster.g","threadId":"66448","inReplyTo":"pull.2246.v2.git.1791033057232.gitgitgadget@gmail.com","subject":"Re: [PATCH v2] doc: don't require a SYNOPSIS in section 7","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-10-04T13:17:27Z","receivedAt":"2026-10-04T13:17:31Z","isPatch":true,"body":"\"Julia Evans via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n>     Changes in v2: Tuomas rewrote the Perl script changes to be both more\n>     declarative and and more correct. Previously it didn't work if there\n>     were multiple files passed on the command line.\n\n> diff --git a/Documentation/lint-man-section-order.perl b/Documentation/lint-man-section-order.perl\n> index 02408a0062..160c65e1be 100755\n> --- a/Documentation/lint-man-section-order.perl\n> +++ b/Documentation/lint-man-section-order.perl\n> @@ -13,6 +13,9 @@ my %SECTIONS;\n>  \t\t},\n>  \t\t'SYNOPSIS' => {\n>  \t\t\trequired => 1,\n> +\t\t\toptional_in_man_sections => {\n> +\t\t\t\t'7' => 1,\n> +\t\t\t},\n>  \t\t\torder => $order++,\n>  \t\t},\n>  \t\t'DESCRIPTION' => {\n> @@ -53,10 +56,18 @@ sub report {\n>  \t$exit_code = 1;\n>  }\n>  \n> +my $man_section_number;\n>  my $last_was_section;\n>  my @actual_order;\n>  while (my $line = <>) {\n>  \tchomp $line;\n> +\n> +\tif ($. == 1) {\n\nOK, this, together with the explicit \"close ARGV\" later in\npostcontext upon seeing eof, lets us do a \"special\" thing on the\nfirst line.\n\n\nI think for the purpose of \"doc lint\", this implementation is good\nenough, especially with documented \"assumption\".\n\nIf we wanted to shoot for a bit more robustness, on the other hand,\nwe would want to handle when $1 is left undef ...\n\n> +\t\t# assume the first line is formatted like 'gitglossary(7)'\n> +\t\t$line =~ m/\\((\\d)\\)/;\n> +\t\t$man_section_number = $1;\n\n... here.  Perhaps like\n\n\t$man_section_number = ($line =~ /\\((\\d)\\)/) ? $1 : \"0\";\n\nIf we left $man_section_number undef, ...\n\n>  \tif ($line =~ $SECTION_RX) {\n>  \t\tpush @actual_order => $line;\n>  \t\t$last_was_section = 1;\n> @@ -92,7 +103,9 @@ while (my $line = <>) {\n>  \t\t@actual_sections{@actual_order} = ();\n>  \n>  \t\tfor my $section (sort keys %SECTIONS) {\n> -\t\t\tnext if !$SECTIONS{$section}->{required} or exists $actual_sections{$section};\n> +\t\t\tnext if !$SECTIONS{$section}->{required} or\n> +\t\t\t\t$SECTIONS{$section}->{optional_in_man_sections}->{$man_section_number} or\n\n... this will access\n\n\t$SECTIONS{$section}->{optional_in_man_sections}->{undef}\n\nand may trigger a warning on use of uninitialized value.  \n\nAlso, this would autovivify $SECTIONS{*}{optional_in_man_sections}\nfor sections that don't have optional_in_man_sections hash (like\nNAME and DESCRIPTION), which may be harmless but needless.\n"}]}