teach branch-specific options for format-patch
cover teach branch-specific options for format-patch
Currently, format-patch only accepts branch.<name>.description as a branch-specific configuration variable. However, there are many other options which would be useful to have on a branch-by-branch basis, namely cover letter subject and To: and Cc: headers.
Teach format-patch to recognise these branch-specific configuration options.
Note that this patchset[1] was created using these new configuration options:
[branch "submitted/fix-revisions-txt"]
coverSubject = "cleanup revisions.txt" cc = "Andreas Heiduk <[email protected]>" cc = "Duy Nguyen <[email protected]>" cc = "Junio C Hamano <[email protected]>"
So this is a live example of this patchset working in practice.
[1]: https://public-inbox.org/git/[email protected]/
Denton Liu (7):
t4014: clean up style
Doc: add more detail for git-format-patch branch.c: extract read_branch_config function
format-patch: make cover letter subject configurable
format-patch: move extra_headers logic later
string-list: create string_list_append_all
format-patch: read branch-specific To: and Cc: headers
Documentation/config/branch.txt | 10 + Documentation/git-format-patch.txt | 33 +- branch.c | 14 +- branch.h | 5 + builtin/log.c | 147 ++++-- string-list.c | 9 + string-list.h | 7 + t/t4014-format-patch.sh | 708 +++++++++++++++++------------ t/t9902-completion.sh | 5 +- 9 files changed, 590 insertions(+), 348 deletions(-)
Signature · 1 line
2.21.0.1049.geb646f7864
PATCH 1/7 t4014: clean up style
In Git's tests, there is typically no space between the redirection operator and the filename. Remove these spaces.
Since output is silenced when running without -v and debugging output is useful with -v, remove redirections to /dev/null.
Change here-docs from <<\EOF to <<-\EOF so that they can be indented along with the rest of the test case.
Finally, refactor to remove Git commands upstream of pipe. This way, if an invocation of a Git command fails, the return code won't be lost. Keep upstream non-Git commands since we have to assume a base level of sanity.
--- t/t4014-format-patch.sh | 614 +++++++++++++++++++++------------------- 1 file changed, 319 insertions(+), 295 deletions(-)
t/t4014-format-patch.sh +319 -295
@@ -34,7 +34,8 @@ test_expect_success setup ' git commit -m "Side changes #3 with \\n backslash-n in it." && git checkout master && - git diff-tree -p C2 | git apply --index && + git diff-tree -p C2 >patch && + git apply --index <patch && test_tick && git commit -m "Master accepts moral equivalent of #2"
@@ -77,7 +78,7 @@ test_expect_success "format-patch doesn't consider merge commits" ' git checkout -b merger master && test_tick && git merge --no-ff slave && - cnt=$(git format-patch -3 --stdout | grep "^From " | wc -l) && + cnt=$(git format-patch -3 --stdout >patch && grep "^From " patch | wc -l) && test $cnt = 3 '
@@ -85,21 +86,22 @@ test_expect_success "format-patch result applies" ' git checkout -b rebuild-0 master && git am -3 patch0 && - cnt=$(git rev-list master.. | wc -l) && - test $cnt = 2 + git rev-list master.. >list && + test_line_count = 2 list ' test_expect_success "format-patch --ignore-if-in-upstream result applies" ' git checkout -b rebuild-1 master && git am -3 patch1 && - cnt=$(git rev-list master.. | wc -l) && - test $cnt = 2 + git rev-list master.. >list && + test_line_count = 2 list ' test_expect_success 'commit did not screw up the log message' ' - git cat-file commit side | grep "^Side .* with .* backslash-n" + git cat-file commit side >actual && + grep "^Side .* with .* backslash-n" actual '
@@ -112,7 +114,8 @@ test_expect_success 'format-patch did not screw up the log message' ' test_expect_success 'replay did not screw up the log message' ' - git cat-file commit rebuild-1 | grep "^Side .* with .* backslash-n" + git cat-file commit rebuild-1 >actual && + grep "^Side .* with .* backslash-n" actual '
@@ -122,8 +125,8 @@ test_expect_success 'extra headers' ' " && git config --add format.headers "Cc: S E Cipient <[email protected]> " && - git format-patch --stdout master..side > patch2 && - sed -e "/^\$/q" patch2 > hdrs2 && + git format-patch --stdout master..side >patch2 && + sed -e "/^\$/q" patch2 >hdrs2 && grep "^To: R E Cipient <[email protected]>\$" hdrs2 && grep "^Cc: S E Cipient <[email protected]>\$" hdrs2
@@ -134,7 +137,7 @@ test_expect_success 'extra headers without newlines' ' git config --replace-all format.headers "To: R E Cipient <[email protected]>" && git config --add format.headers "Cc: S E Cipient <[email protected]>" && git format-patch --stdout master..side >patch3 && - sed -e "/^\$/q" patch3 > hdrs3 && + sed -e "/^\$/q" patch3 >hdrs3 && grep "^To: R E Cipient <[email protected]>\$" hdrs3 && grep "^Cc: S E Cipient <[email protected]>\$" hdrs3
@@ -144,8 +147,8 @@ test_expect_success 'extra headers with multiple To:s' ' git config --replace-all format.headers "To: R E Cipient <[email protected]>" && git config --add format.headers "To: S E Cipient <[email protected]>" && - git format-patch --stdout master..side > patch4 && - sed -e "/^\$/q" patch4 > hdrs4 && + git format-patch --stdout master..side >patch4 && + sed -e "/^\$/q" patch4 >hdrs4 && grep "^To: R E Cipient <[email protected]>,\$" hdrs4 && grep "^ *S E Cipient <[email protected]>\$" hdrs4 '
@@ -153,72 +156,82 @@ test_expect_success 'extra headers with multiple To:s' ' test_expect_success 'additional command line cc (ascii)' ' git config --replace-all format.headers "Cc: R E Cipient <[email protected]>" && - git format-patch --cc="S E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch5 && - grep "^Cc: R E Cipient <[email protected]>,\$" patch5 && - grep "^ *S E Cipient <[email protected]>\$" patch5 + git format-patch --cc="S E Cipient <[email protected]>" --stdout master..side >patch5 && + sed -e "/^\$/q" patch5 >hdrs5 && + grep "^Cc: R E Cipient <[email protected]>,\$" hdrs5 && + grep "^ *S E Cipient <[email protected]>\$" hdrs5 ' test_expect_failure 'additional command line cc (rfc822)' ' git config --replace-all format.headers "Cc: R E Cipient <[email protected]>" && - git format-patch --cc="S. E. Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch5 && - grep "^Cc: R E Cipient <[email protected]>,\$" patch5 && - grep "^ *\"S. E. Cipient\" <[email protected]>\$" patch5 + git format-patch --cc="S. E. Cipient <[email protected]>" --stdout master..side >patch5 && + sed -e "/^\$/q" patch5 >hdrs5 && + grep "^Cc: R E Cipient <[email protected]>,\$" hdrs5 && + grep "^ *\"S. E. Cipient\" <[email protected]>\$" hdrs5 ' test_expect_success 'command line headers' ' git config --unset-all format.headers && - git format-patch --add-header="Cc: R E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch6 && - grep "^Cc: R E Cipient <[email protected]>\$" patch6 + git format-patch --add-header="Cc: R E Cipient <[email protected]>" --stdout master..side >patch6 && + sed -e "/^\$/q" patch6 >hdrs6 && + grep "^Cc: R E Cipient <[email protected]>\$" hdrs6 ' test_expect_success 'configuration headers and command line headers' ' git config --replace-all format.headers "Cc: R E Cipient <[email protected]>" && - git format-patch --add-header="Cc: S E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch7 && - grep "^Cc: R E Cipient <[email protected]>,\$" patch7 && - grep "^ *S E Cipient <[email protected]>\$" patch7 + git format-patch --add-header="Cc: S E Cipient <[email protected]>" --stdout master..side >patch7 && + sed -e "/^\$/q" patch7 >hdrs7 && + grep "^Cc: R E Cipient <[email protected]>,\$" hdrs7 && + grep "^ *S E Cipient <[email protected]>\$" hdrs7 ' test_expect_success 'command line To: header (ascii)' ' git config --unset-all format.headers && - git format-patch --to="R E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch8 && - grep "^To: R E Cipient <[email protected]>\$" patch8 + git format-patch --to="R E Cipient <[email protected]>" --stdout master..side >patch8 && + sed -e "/^\$/q" patch8 >hdrs8 && + grep "^To: R E Cipient <[email protected]>\$" hdrs8 ' test_expect_failure 'command line To: header (rfc822)' ' - git format-patch --to="R. E. Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch8 && - grep "^To: \"R. E. Cipient\" <[email protected]>\$" patch8 + git format-patch --to="R. E. Cipient <[email protected]>" --stdout master..side >patch8 && + sed -e "/^\$/q" patch8 >hdrs8 && + grep "^To: \"R. E. Cipient\" <[email protected]>\$" hdrs8 ' test_expect_failure 'command line To: header (rfc2047)' ' - git format-patch --to="R Ä Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch8 && - grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" patch8 + git format-patch --to="R Ä Cipient <[email protected]>" --stdout master..side >patch8 && + sed -e "/^\$/q" patch8 >hdrs8 && + grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" hdrs8 ' test_expect_success 'configuration To: header (ascii)' ' git config format.to "R E Cipient <[email protected]>" && - git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && - grep "^To: R E Cipient <[email protected]>\$" patch9 + git format-patch --stdout master..side >patch9 && + sed -e "/^\$/q" patch9 >hdrs9 && + grep "^To: R E Cipient <[email protected]>\$" hdrs9 ' test_expect_failure 'configuration To: header (rfc822)' ' git config format.to "R. E. Cipient <[email protected]>" && - git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && - grep "^To: \"R. E. Cipient\" <[email protected]>\$" patch9 + git format-patch --stdout master..side >patch9 && + sed -e "/^\$/q" patch9 >hdrs9 && + grep "^To: \"R. E. Cipient\" <[email protected]>\$" hdrs9 ' test_expect_failure 'configuration To: header (rfc2047)' ' git config format.to "R Ä Cipient <[email protected]>" && - git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && - grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" patch9 + git format-patch --stdout master..side >patch9 && + sed -e "/^\$/q" patch9 >hdrs9 && + grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" hdrs9 ' # check_patch <patch>: Verify that <patch> looks like a half-sane
@@ -231,52 +244,52 @@ check_patch () { test_expect_success 'format.from=false' ' - git -c format.from=false format-patch --stdout master..side | - sed -e "/^\$/q" >patch && + git -c format.from=false format-patch --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && check_patch patch && - ! grep "^From: C O Mitter <[email protected]>\$" patch + ! grep "^From: C O Mitter <[email protected]>\$" hdrs ' test_expect_success 'format.from=true' ' - git -c format.from=true format-patch --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - grep "^From: C O Mitter <[email protected]>\$" patch + git -c format.from=true format-patch --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + grep "^From: C O Mitter <[email protected]>\$" hdrs ' test_expect_success 'format.from with address' ' - git -c format.from="F R Om <[email protected]>" format-patch --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - grep "^From: F R Om <[email protected]>\$" patch + git -c format.from="F R Om <[email protected]>" format-patch --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + grep "^From: F R Om <[email protected]>\$" hdrs ' test_expect_success '--no-from overrides format.from' ' - git -c format.from="F R Om <[email protected]>" format-patch --no-from --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - ! grep "^From: F R Om <[email protected]>\$" patch + git -c format.from="F R Om <[email protected]>" format-patch --no-from --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + ! grep "^From: F R Om <[email protected]>\$" hdrs ' test_expect_success '--from overrides format.from' ' - git -c format.from="F R Om <[email protected]>" format-patch --from --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - ! grep "^From: F R Om <[email protected]>\$" patch + git -c format.from="F R Om <[email protected]>" format-patch --from --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + ! grep "^From: F R Om <[email protected]>\$" hdrs ' test_expect_success '--no-to overrides config.to' ' git config --replace-all format.to \ "R E Cipient <[email protected]>" && - git format-patch --no-to --stdout master..side | - sed -e "/^\$/q" >patch10 && - check_patch patch10 && - ! grep "^To: R E Cipient <[email protected]>\$" patch10 + git format-patch --no-to --stdout master..side >patch10 && + sed -e "/^\$/q" patch10 >hdrs10 && + check_patch hdrs10 && + ! grep "^To: R E Cipient <[email protected]>\$" hdrs10 ' test_expect_success '--no-to and --to replaces config.to' '
@@ -284,31 +297,31 @@ test_expect_success '--no-to and --to replaces config.to' ' git config --replace-all format.to \ "Someone <[email protected]>" && git format-patch --no-to --to="Someone Else <[email protected]>" \ - --stdout master..side | - sed -e "/^\$/q" >patch11 && - check_patch patch11 && - ! grep "^To: Someone <[email protected]>\$" patch11 && - grep "^To: Someone Else <[email protected]>\$" patch11 + --stdout master..side >patch11 && + sed -e "/^\$/q" patch11 >hdrs11 && + check_patch hdrs11 && + ! grep "^To: Someone <[email protected]>\$" hdrs11 && + grep "^To: Someone Else <[email protected]>\$" hdrs11 ' test_expect_success '--no-cc overrides config.cc' ' git config --replace-all format.cc \ "C E Cipient <[email protected]>" && - git format-patch --no-cc --stdout master..side | - sed -e "/^\$/q" >patch12 && - check_patch patch12 && - ! grep "^Cc: C E Cipient <[email protected]>\$" patch12 + git format-patch --no-cc --stdout master..side >patch12 && + sed -e "/^\$/q" patch12 >hdrs12 && + check_patch hdrs12 && + ! grep "^Cc: C E Cipient <[email protected]>\$" hdrs12 ' test_expect_success '--no-add-header overrides config.headers' ' git config --replace-all format.headers \ "Header1: B E Cipient <[email protected]>" && - git format-patch --no-add-header --stdout master..side | - sed -e "/^\$/q" >patch13 && - check_patch patch13 && - ! grep "^Header1: B E Cipient <[email protected]>\$" patch13 + git format-patch --no-add-header --stdout master..side >patch13 && + sed -e "/^\$/q" patch13 >hdrs13 && + check_patch hdrs13 && + ! grep "^Header1: B E Cipient <[email protected]>\$" hdrs13 ' test_expect_success 'multiple files' '
@@ -338,7 +351,7 @@ test_expect_success 'reroll count (-v)' ' check_threading () { expect="$1" && shift && - (git format-patch --stdout "$@"; echo $? > status.out) | + (git format-patch --stdout "$@"; echo $? >status.out) | # Prints everything between the Message-ID and In-Reply-To, # and replaces all Message-ID-lookalikes by a sequence number perl -ne '
@@ -353,12 +366,12 @@ check_threading () { print; } print "---\n" if /^From /i; - ' > actual && + ' >actual && test 0 = "$(cat status.out)" && test_cmp "$expect" actual } -cat >> expect.no-threading <<EOF +cat >>expect.no-threading <<EOF --- --- ---
@@ -369,7 +382,7 @@ test_expect_success 'no threading' ' check_threading expect.no-threading master ' -cat > expect.thread <<EOF +cat >expect.thread <<EOF --- Message-Id: <0> ---
@@ -386,7 +399,7 @@ test_expect_success 'thread' ' check_threading expect.thread --thread master ' -cat > expect.in-reply-to <<EOF +cat >expect.in-reply-to <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -406,7 +419,7 @@ test_expect_success 'thread in-reply-to' ' --thread master ' -cat > expect.cover-letter <<EOF +cat >expect.cover-letter <<EOF --- Message-Id: <0> ---
@@ -427,7 +440,7 @@ test_expect_success 'thread cover-letter' ' check_threading expect.cover-letter --cover-letter --thread master ' -cat > expect.cl-irt <<EOF +cat >expect.cl-irt <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -459,7 +472,7 @@ test_expect_success 'thread explicit shallow' ' --in-reply-to="<test.message>" --thread=shallow master ' -cat > expect.deep <<EOF +cat >expect.deep <<EOF --- Message-Id: <0> ---
@@ -477,7 +490,7 @@ test_expect_success 'thread deep' ' check_threading expect.deep --thread=deep master ' -cat > expect.deep-irt <<EOF +cat >expect.deep-irt <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -500,7 +513,7 @@ test_expect_success 'thread deep in-reply-to' ' --in-reply-to="<test.message>" master ' -cat > expect.deep-cl <<EOF +cat >expect.deep-cl <<EOF --- Message-Id: <0> ---
@@ -524,7 +537,7 @@ test_expect_success 'thread deep cover-letter' ' check_threading expect.deep-cl --cover-letter --thread=deep master ' -cat > expect.deep-cl-irt <<EOF +cat >expect.deep-cl-irt <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -600,7 +613,7 @@ test_expect_success 'cover-letter inherits diff options' ' ' -cat > expect << EOF +cat >expect <<EOF This is an excessively long subject line for a message due to the habit some projects have of not having a short, one-line subject at the start of the commit message, but rather sticking a whole
@@ -613,12 +626,12 @@ EOF test_expect_success 'shortlog of cover-letter wraps overly-long onelines' ' git format-patch --cover-letter -2 && - sed -e "1,/A U Thor/d" -e "/^\$/q" < 0000-cover-letter.patch > output && + sed -e "1,/A U Thor/d" -e "/^\$/q" <0000-cover-letter.patch >output && test_cmp expect output ' -cat > expect << EOF +cat >expect <<EOF index $before..$after 100644 --- a/file +++ b/file
@@ -640,7 +653,7 @@ test_expect_success 'format-patch respects -U' ' ' -cat > expect << EOF +cat >expect <<EOF diff --git a/file b/file index $before..$after 100644
@@ -656,7 +669,7 @@ EOF test_expect_success 'format-patch -p suppresses stat' ' git format-patch -p -2 && - sed -e "1,/^\$/d" -e "/^+5/q" < 0001-This-is-an-excessively-long-subject-line-for-a-messa.patch > output && + sed -e "1,/^\$/d" -e "/^+5/q" <0001-This-is-an-excessively-long-subject-line-for-a-messa.patch >output && test_cmp expect output '
@@ -711,7 +724,7 @@ test_expect_success 'format-patch from a subdirectory (3)' ' ' test_expect_success 'format-patch --in-reply-to' ' - git format-patch -1 --stdout --in-reply-to "[email protected]" > patch8 && + git format-patch -1 --stdout --in-reply-to "[email protected]" >patch8 && grep "^In-Reply-To: <[email protected]>" patch8 && grep "^References: <[email protected]>" patch8 '
@@ -732,20 +745,20 @@ test_expect_success 'format-patch --notes --signoff' ' sed "1,/^---$/d" out | grep "test message" ' -echo "fatal: --name-only does not make sense" > expect.name-only -echo "fatal: --name-status does not make sense" > expect.name-status -echo "fatal: --check does not make sense" > expect.check +echo "fatal: --name-only does not make sense" >expect.name-only +echo "fatal: --name-status does not make sense" >expect.name-status +echo "fatal: --check does not make sense" >expect.check test_expect_success 'options no longer allowed for format-patch' ' - test_must_fail git format-patch --name-only 2> output && + test_must_fail git format-patch --name-only 2>output && test_i18ncmp expect.name-only output && - test_must_fail git format-patch --name-status 2> output && + test_must_fail git format-patch --name-status 2>output && test_i18ncmp expect.name-status output && - test_must_fail git format-patch --check 2> output && + test_must_fail git format-patch --check 2>output && test_i18ncmp expect.check output' test_expect_success 'format-patch --numstat should produce a patch' ' - git format-patch --numstat --stdout master..side > output && + git format-patch --numstat --stdout master..side >output && test 5 = $(grep "^diff --git a/" output | wc -l)' test_expect_success 'format-patch -- <path>' '
@@ -757,20 +770,22 @@ test_expect_success 'format-patch --ignore-if-in-upstream HEAD' ' git format-patch --ignore-if-in-upstream HEAD ' -git_version="$(git --version | sed "s/.* //")" +git_version="$(git --version >version && sed "s/.* //" version)" signature() { printf "%s\n%s\n\n" "-- " "${1:-$git_version}" } test_expect_success 'format-patch default signature' ' - git format-patch --stdout -1 | tail -n 3 >output && + git format-patch --stdout -1 >patch && + tail -n 3 patch >output && signature >expect && test_cmp expect output ' test_expect_success 'format-patch --signature' ' - git format-patch --stdout --signature="my sig" -1 | tail -n 3 >output && + git format-patch --stdout --signature="my sig" -1 >patch && + tail -n 3 patch >output && signature "my sig" >expect && test_cmp expect output '
@@ -1161,282 +1176,282 @@ append_signoff() test_expect_success 'signoff: commit with no body' ' append_signoff </dev/null >actual && - cat <<\EOF | sed "s/EOL$//" >expected && -4:Subject: [PATCH] EOL -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat <<-\EOF | sed "s/EOL$//" >expected && + 4:Subject: [PATCH] EOL + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: commit with only subject' ' echo subject | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: commit with only subject that does not end with NL' ' printf subject | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: no existing signoffs' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + body + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: no existing signoffs and no trailing NL' ' printf "subject\n\nbody" | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: some random signoff' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: my@house -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: my@house -12:Signed-off-by: C O Mitter <[email protected]> -EOF + Signed-off-by: my@house + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: my@house + 12:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: misc conforming footer elements' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: my@house -(cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709) -Tested-by: Some One <[email protected]> -Bug: 1234 -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: my@house -15:Signed-off-by: C O Mitter <[email protected]> -EOF + Signed-off-by: my@house + (cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709) + Tested-by: Some One <[email protected]> + Bug: 1234 + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: my@house + 15:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: some random signoff-alike' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body -Fooled-by-me: my@house -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -11: -12:Signed-off-by: C O Mitter <[email protected]> -EOF + body + Fooled-by-me: my@house + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 11: + 12:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: not really a signoff' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -I want to mention about Signed-off-by: here. -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:I want to mention about Signed-off-by: here. -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + I want to mention about Signed-off-by: here. + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:I want to mention about Signed-off-by: here. + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: not really a signoff (2)' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -My unfortunate -Signed-off-by: example happens to be wrapped here. -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10:Signed-off-by: example happens to be wrapped here. -11:Signed-off-by: C O Mitter <[email protected]> -EOF + My unfortunate + Signed-off-by: example happens to be wrapped here. + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10:Signed-off-by: example happens to be wrapped here. + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: valid S-o-b paragraph in the middle' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -Signed-off-by: my@house -Signed-off-by: your@house + Signed-off-by: my@house + Signed-off-by: your@house -A lot of houses. -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: my@house -10:Signed-off-by: your@house -11: -13: -14:Signed-off-by: C O Mitter <[email protected]> -EOF + A lot of houses. + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: my@house + 10:Signed-off-by: your@house + 11: + 13: + 14:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: the same signoff at the end' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: C O Mitter <[email protected]> -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + Signed-off-by: C O Mitter <[email protected]> + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: the same signoff at the end, no trailing NL' ' printf "subject\n\nSigned-off-by: C O Mitter <[email protected]>" | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: the same signoff NOT at the end' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: C O Mitter <[email protected]> -Signed-off-by: my@house -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -12:Signed-off-by: my@house -EOF + Signed-off-by: C O Mitter <[email protected]> + Signed-off-by: my@house + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + 12:Signed-off-by: my@house + EOF test_cmp expected actual ' test_expect_success 'signoff: tolerate garbage in conforming footer' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Tested-by: my@house -Some Trash -Signed-off-by: C O Mitter <[email protected]> -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -13:Signed-off-by: C O Mitter <[email protected]> -EOF + Tested-by: my@house + Some Trash + Signed-off-by: C O Mitter <[email protected]> + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 13:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: respect trailer config' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -Myfooter: x -Some Trash -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -11: -12:Signed-off-by: C O Mitter <[email protected]> -EOF + Myfooter: x + Some Trash + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 11: + 12:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual && test_config trailer.Myfooter.ifexists add && - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -Myfooter: x -Some Trash -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + Myfooter: x + Some Trash + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: footer begins with non-signoff without @ sign' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Reviewed-id: Noone -Tested-by: my@house -Change-id: Ideadbeef -Signed-off-by: C O Mitter <[email protected]> -Bug: 1234 -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -14:Signed-off-by: C O Mitter <[email protected]> -EOF + Reviewed-id: Noone + Tested-by: my@house + Change-id: Ideadbeef + Signed-off-by: C O Mitter <[email protected]> + Bug: 1234 + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 14:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual '
@@ -1452,42 +1467,42 @@ test_expect_success 'cover letter using branch description (1)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter master >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (2)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter rebuild-1~2..rebuild-1 >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (3)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter ^master rebuild-1 >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (4)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter master.. >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (5)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter -2 HEAD >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (6)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter -2 >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter with nothing' '
@@ -1541,7 +1556,8 @@ test_expect_success 'format-patch format.outputDirectory option' ' test_config format.outputDirectory patches && rm -fr patches && git format-patch master..side && - test $(git rev-list master..side | wc -l) -eq $(ls patches | wc -l) + git rev-list master..side >list && + test_line_count = $(ls patches | wc -l) list ' test_expect_success 'format-patch -o overrides format.outputDirectory' '
@@ -1554,13 +1570,21 @@ test_expect_success 'format-patch -o overrides format.outputDirectory' ' test_expect_success 'format-patch --base' ' git checkout side && - git format-patch --stdout --base=HEAD~3 -1 | tail -n 7 >actual1 && - git format-patch --stdout --base=HEAD~3 HEAD~.. | tail -n 7 >actual2 && + git format-patch --stdout --base=HEAD~3 -1 >patch && + tail -n 7 patch >actual1 && + git format-patch --stdout --base=HEAD~3 HEAD~.. >patch && + tail -n 7 patch >actual2 && echo >expected && echo "base-commit: $(git rev-parse HEAD~3)" >>expected && - echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --stable | awk "{print \$1}")" >>expected && - echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --stable | awk "{print \$1}")" >>expected && - signature >> expected && + git show --patch HEAD~2 >patch && + git patch-id --stable <patch >patch.id.raw && + awk "{print \$1}" <patch.id.raw >patch.id && + echo "prerequisite-patch-id: $(cat patch.id)" >>expected && + git show --patch HEAD~1 >patch && + git patch-id --stable <patch >patch.id.raw && + awk "{print \$1}" <patch.id.raw >patch.id && + echo "prerequisite-patch-id: $(cat patch.id)" >>expected && + signature >>expected && test_cmp expected actual1 && test_cmp expected actual2 '
Signature · 1 line
2.21.0.1049.geb646f7864
PATCH 2/7 Doc: add more detail for git-format-patch
In reply to Denton LiuIn git-format-patch.txt, we were missing some key user information. First of all, using the --to and --cc options don't override format.to and format.cc variables, respectively. They add on to each other. Document this.
In addition, document the special value of --base=auto.
Finally, while we're at it, surround option arguments with <>.
--- Documentation/git-format-patch.txt | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
Documentation/git-format-patch.txt +11 -6
@@ -17,9 +17,9 @@ SYNOPSIS [--signature-file=<file>] [-n | --numbered | -N | --no-numbered] [--start-number <n>] [--numbered-files] - [--in-reply-to=Message-Id] [--suffix=.<sfx>] + [--in-reply-to=<Message-Id>] [--suffix=.<sfx>] [--ignore-if-in-upstream] - [--rfc] [--subject-prefix=Subject-Prefix] + [--rfc] [--subject-prefix=<Subject-Prefix>] [(--reroll-count|-v) <n>] [--to=<email>] [--cc=<email>] [--[no-]cover-letter] [--quiet] [--notes[=<ref>]]
@@ -158,7 +158,7 @@ Beware that the default for 'git send-email' is to thread emails itself. If you want `git format-patch` to take care of threading, you will want to ensure that threading is disabled for `git send-email`. ---in-reply-to=Message-Id:: +--in-reply-to=<Message-Id>:: Make the first mail (or all the mails with `--no-thread`) appear as a reply to the given Message-Id, which avoids breaking threads to provide a new patch series.
@@ -192,13 +192,17 @@ will want to ensure that threading is disabled for `git send-email`. --to=<email>:: Add a `To:` header to the email headers. This is in addition - to any configured headers, and may be used multiple times. + to any configured headers, and may be used multiple times. The + emails given will be used along with any emails given by + `format.to` configurations. The negated form `--no-to` discards all `To:` headers added so far (from config or command line). --cc=<email>:: Add a `Cc:` header to the email headers. This is in addition - to any configured headers, and may be used multiple times. + to any configured headers, and may be used multiple times. The + emails given will be used along with any emails given by + `format.cc` configurations. The negated form `--no-cc` discards all `Cc:` headers added so far (from config or command line).
@@ -309,7 +313,8 @@ you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`. --base=<commit>:: Record the base tree information to identify the state the patch series applies to. See the BASE TREE INFORMATION section - below for details. + below for details. If <commit> is equal to "auto", a base commit + is automatically chosen. --root:: Treat the revision argument as a <revision range>, even if it
Signature · 1 line
2.21.0.1049.geb646f7864
PATCH 3/7 branch.c: extract read_branch_config function
In reply to Denton LiuIn the future, we'll need to use read_branch_config as a generic base for other branch-config reading functions. Extract it from read_branch_desc so that it can be reused later.
--- branch.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
branch.c +7 -2
@@ -162,11 +162,11 @@ static void setup_tracking(const char *new_ref, const char *orig_ref,free (tracking.src); } -int read_branch_desc (struct strbuf *buf,const char *branch_name) +static int read_branch_config (struct strbuf *buf,const char *branch_name,const char *key) {char *v =NULL ;struct strbuf name =STRBUF_INIT ; -strbuf_addf (&name,"branch.%s.description" , branch_name); +strbuf_addf (&name,"branch.%s.%s" , branch_name, key);if (git_config_get_string (name.buf, &v)) {strbuf_release (&name);return -1 ;
@@ -177,6 +177,11 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)return 0 ; } +int read_branch_desc (struct strbuf *buf,const char *branch_name) +{ +return read_branch_config (buf, branch_name,"description" ); +} +/* * Check if 'name' can be a valid name for a branch; die otherwise. * Return 1 if the named branch already exists; return 0 otherwise.
Signature · 1 line
2.21.0.1049.geb646f7864
PATCH 4/7 format-patch: make cover letter subject configurable
In reply to Denton LiuWe used to populate the subject of the cover letter generated by git-format-patch with "*** SUBJECT HERE ***". However, if a user submits multiple patchsets, they may want to keep a consistent subject between rerolls.
If git-format-patch is run on a branch that has branch.<name>.coverSubject defined, make the cover letter's subject be that value instead of the generic "*** SUBJECT HERE ***".
In addition, add the --cover-subject option to override this setting.
--- Documentation/config/branch.txt | 4 ++++ Documentation/git-format-patch.txt | 12 ++++++++++++ branch.c | 5 +++++ branch.h | 5 +++++ builtin/log.c | 26 +++++++++++++++++++------- t/t4014-format-patch.sh | 20 ++++++++++++++++++++ t/t9902-completion.sh | 5 ++++- 7 files changed, 69 insertions(+), 8 deletions(-)
Documentation/config/branch.txt +4 -0
@@ -100,3 +100,7 @@ branch.<name>.description:: `git branch --edit-description`. Branch description is automatically added in the format-patch cover letter or request-pull summary. + +branch.<name>.coverSubject:: + When format-patch generates a cover letter, use the specified + subject for the cover letter instead of the generic template.
Documentation/git-format-patch.txt +12 -0
@@ -19,6 +19,7 @@ SYNOPSIS [--start-number <n>] [--numbered-files] [--in-reply-to=<Message-Id>] [--suffix=.<sfx>] [--ignore-if-in-upstream] + [--cover-subject=<subject>] [--rfc] [--subject-prefix=<Subject-Prefix>] [(--reroll-count|-v) <n>] [--to=<email>] [--cc=<email>]
@@ -170,6 +171,10 @@ will want to ensure that threading is disabled for `git send-email`. patches being generated, and any patch that matches is ignored. +--cover-subject=<subject>:: + Instead of using the default "*** SUBJECT HERE ***" subject for + the cover letter, use the given <subject>. + --subject-prefix=<Subject-Prefix>:: Instead of the standard '[PATCH]' prefix in the subject line, instead use '[<Subject-Prefix>]'. This
@@ -346,6 +351,13 @@ attachments, and sign off patches with configuration variables. coverletter = auto ------------ +In addition, for a specific branch, you can specify a custom cover +letter subject. + +------------ +[branch "branch-name"] + coverSubject = "subject for branch-name only" +------------ DISCUSSION ----------
branch.c +5 -0
@@ -182,6 +182,11 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)return read_branch_config (buf, branch_name,"description" ); } +int read_branch_subject (struct strbuf *buf,const char *branch_name) +{ +return read_branch_config (buf, branch_name,"coversubject" ); +} +/* * Check if 'name' can be a valid name for a branch; die otherwise. * Return 1 if the named branch already exists; return 0 otherwise.
branch.h +5 -0
@@ -79,6 +79,11 @@ extern int install_branch_config(int flag, const char *local, const char *origin*/ extern int read_branch_desc (struct strbuf *,const char *branch_name); +/* +* Read branch subject +*/ +extern int read_branch_subject (struct strbuf *,const char *branch_name); +/* * Check if a branch is checked out in the main worktree or any linked * worktree and die (with a message describing its checkout location) if
builtin/log.c +19 -7
@@ -1034,13 +1034,14 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,struct commit *origin, int nr, struct commit **list, const char *branch_name, + const char *subject, int quiet) { const char *committer; -const char *body ="*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n" ; -const char *msg; +const char *body ="*** BLURB HERE ***" ;struct shortlog log;struct strbuf sb =STRBUF_INIT ; +struct strbuf subject_sb =STRBUF_INIT ;int i;const char *encoding ="UTF-8" ;int need_8bit_cte =0 ;
@@ -1068,17 +1069,24 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,if (!branch_name) branch_name =find_branch_name (rev); - msg = body; +if (!subject) { +if (branch_name && *branch_name && !read_branch_subject (&subject_sb, branch_name)) + subject = subject_sb.buf; +else + subject ="*** SUBJECT HERE ***" ; + } + pp.fmt =CMIT_FMT_EMAIL ; pp.date_mode.type =DATE_RFC2822 ; pp.rev = rev; pp.print_email_subject =1 ;pp_user_info (&pp,NULL , &sb, committer, encoding); -pp_title_line (&pp, &msg, &sb, encoding, need_8bit_cte); -pp_remainder (&pp, &msg, &sb,0 ); +pp_title_line (&pp, &subject, &sb, encoding, need_8bit_cte); +pp_remainder (&pp, &body, &sb,0 );add_branch_description (&sb, branch_name);fprintf (rev->diffopt.file,"%s\n" , sb.buf); +strbuf_release (&subject_sb);strbuf_release (&sb);shortlog_init (&log);
@@ -1512,6 +1520,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)int no_binary_diff =0 ;int zero_commit =0 ;struct commit *origin =NULL ; +const char *cover_subject =NULL ;const char *in_reply_to =NULL ;struct patch_ids ids;struct strbuf buf =STRBUF_INIT ;
@@ -1554,6 +1563,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) {OPTION_CALLBACK ,0 ,"rfc" , &rev,NULL ,N_ ("Use [RFC PATCH] instead of [PATCH]" ), PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback }, +OPT_STRING (0 ,"cover-subject" , &cover_subject,N_ ("subject" ), +N_ ("the subject for the cover letter" )), { OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"),N_ ("Use [<prefix>] instead of [PATCH]" ), PARSE_OPT_NONEG, subject_prefix_callback },
@@ -1617,8 +1628,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) extra_to.strdup_strings =1 ; extra_cc.strdup_strings =1 ;init_log_defaults (); -git_config (git_format_config,NULL );repo_init_revisions (the_repository, &rev, prefix); + +git_config (git_format_config,NULL ); rev.commit_format =CMIT_FMT_EMAIL ; rev.expand_tabs_in_log_default =0 ; rev.verbose_header =1 ;
@@ -1893,7 +1905,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)if (thread)gen_message_id (&rev,"cover" );make_cover_letter (&rev, use_stdout, - origin, nr, list, branch_name, quiet); + origin, nr, list, branch_name, cover_subject, quiet);print_bases (&bases, rev.diffopt.file);print_signature (rev.diffopt.file); total++;
t/t4014-format-patch.sh +20 -0
@@ -1463,6 +1463,26 @@ test_expect_success 'format patch ignores color.ui' ' test_cmp expect actual ' +test_expect_success 'cover letter with config subject' ' + test_config branch.rebuild-1.coverSubject "config subject" && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter master >actual && + grep "Subject: \[PATCH 0/2\] config subject" actual +' + +test_expect_success 'cover letter with command-line subject' ' + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --cover-subject "command-line subject" master >actual && + grep "Subject: \[PATCH 0/2\] command-line subject" actual +' + +test_expect_success 'cover letter with command-line subject overrides config' ' + test_config branch.rebuild-1.coverSubject "config subject" && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --cover-subject "command-line subject" master >actual && + grep "Subject: \[PATCH 0/2\] command-line subject" actual +' + test_expect_success 'cover letter using branch description (1)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello &&
t/t9902-completion.sh +4 -1
@@ -1542,7 +1542,10 @@ test_expect_success 'complete tree filename with metacharacters' ' ' test_expect_success PERL 'send-email' ' - test_completion "git send-email --cov" "--cover-letter " && + test_completion "git send-email --cov" <<-\EOF && + --cover-letter Z + --cover-subject=Z + EOF test_completion "git send-email ma" "master " '
Signature · 1 line
2.21.0.1049.geb646f7864
PATCH 5/7 format-patch: move extra_headers logic later
In reply to Denton LiuIn a future patch, we need to perform the addition of To: and Cc:
to extra_headers after the branch_name logic. Simply transpose this logic later in the function so that this happens. (This patch is best viewed with git diff --color-moved.)
Note that this logic only depends on the git_config and repo_init_revisions and is depended on by the patch creation logic which is directly below it so this move is effectively a no-op as no dependencies being reordered.
--- builtin/log.c | 58 +++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 29 deletions(-)
builtin/log.c +29 -29
@@ -1665,35 +1665,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) rev.subject_prefix =strbuf_detach (&sprefix,NULL ); } -for (i =0 ; i < extra_hdr.nr; i++) { -strbuf_addstr (&buf, extra_hdr.items[i].string); -strbuf_addch (&buf,'\n' ); - } - -if (extra_to.nr) -strbuf_addstr (&buf,"To: " ); -for (i =0 ; i < extra_to.nr; i++) { -if (i) -strbuf_addstr (&buf," " ); -strbuf_addstr (&buf, extra_to.items[i].string); -if (i +1 < extra_to.nr) -strbuf_addch (&buf,',' ); -strbuf_addch (&buf,'\n' ); - } - -if (extra_cc.nr) -strbuf_addstr (&buf,"Cc: " ); -for (i =0 ; i < extra_cc.nr; i++) { -if (i) -strbuf_addstr (&buf," " ); -strbuf_addstr (&buf, extra_cc.items[i].string); -if (i +1 < extra_cc.nr) -strbuf_addch (&buf,',' ); -strbuf_addch (&buf,'\n' ); - } - - rev.extra_headers =strbuf_detach (&buf,NULL ); -if (from) {if (split_ident_line (&rev.from_ident, from,strlen (from)))die (_ ("invalid ident line: %s" ), from);
@@ -1796,6 +1767,35 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } } +for (i =0 ; i < extra_hdr.nr; i++) { +strbuf_addstr (&buf, extra_hdr.items[i].string); +strbuf_addch (&buf,'\n' ); + } + +if (extra_to.nr) +strbuf_addstr (&buf,"To: " ); +for (i =0 ; i < extra_to.nr; i++) { +if (i) +strbuf_addstr (&buf," " ); +strbuf_addstr (&buf, extra_to.items[i].string); +if (i +1 < extra_to.nr) +strbuf_addch (&buf,',' ); +strbuf_addch (&buf,'\n' ); + } + +if (extra_cc.nr) +strbuf_addstr (&buf,"Cc: " ); +for (i =0 ; i < extra_cc.nr; i++) { +if (i) +strbuf_addstr (&buf," " ); +strbuf_addstr (&buf, extra_cc.items[i].string); +if (i +1 < extra_cc.nr) +strbuf_addch (&buf,',' ); +strbuf_addch (&buf,'\n' ); + } + + rev.extra_headers =strbuf_detach (&buf,NULL ); +/* * We cannot move this anywhere earlier because we do want to * know if --root was given explicitly from the command line.
Signature · 1 line
2.21.0.1049.geb646f7864
PATCH 6/7 string-list: create string_list_append_all
In reply to Denton LiuIn a future patch, we'll need to take one string_list and append it to the end of another. Create the string_list_append_all function which does this.
--- string-list.c | 9 +++++++++ string-list.h | 7 +++++++ 2 files changed, 16 insertions(+)
string-list.c +9 -0
@@ -215,6 +215,15 @@ struct string_list_item *string_list_append(struct string_list *list, list->strdup_strings ? xstrdup(string) : (char *)string); } +void string_list_append_all (struct string_list *list, +const struct string_list *append_list) +{ +struct string_list_item *item; +ALLOC_GROW (list->items, list->nr + append_list->nr, list->alloc); +for_each_string_list_item (item, append_list) +string_list_append (list, item->string); +} +/* * Encapsulate the compare function pointer because ISO C99 forbids * casting from void * to a function pointer and vice versa.
string-list.h +7 -0
@@ -208,6 +208,13 @@ struct string_list_item *string_list_append(struct string_list *list, const char*/ struct string_list_item *string_list_append_nodup (struct string_list *list,char *string); +/** +* Add all strings in append_list to list. If list->strdup_string is +* set, then each string is copied; otherwise the new string_list_entry +* refers to the entry in the append_list. +*/ +void string_list_append_all (struct string_list *list,const struct string_list *append_list); +/** * Sort the list's entries by string value in `strcmp()` order. */
Signature · 1 line
2.21.0.1049.geb646f7864
PATCH 7/7 format-patch: read branch-specific To: and Cc: headers
In reply to Denton LiuIf a user wishes to keep track of whom to Cc: on individual patchsets, they must manually keep track of each recipient and fill it in with the --cc option on git-format-patch each time. However, on the Git mailing list, Cc:'s are typically never dropped. As a result, it would be nice to have a method to keep track of recipients on a per-branch basis.
Currently, git-format-patch gets its To: headers from the --to options and the format.to config variable. The Cc: header is derived similarly.
In addition to the above, read To: and Cc: headers from branch.<name>.to and branch.<name>.cc so that users can have branch-specific configuration options.
--- Documentation/config/branch.txt | 6 ++ Documentation/git-format-patch.txt | 10 +-- builtin/log.c | 63 +++++++++++++++-- t/t4014-format-patch.sh | 108 +++++++++++++++++++++++------ 4 files changed, 159 insertions(+), 28 deletions(-)
Documentation/config/branch.txt +6 -0
@@ -104,3 +104,9 @@ branch.<name>.description:: branch.<name>.coverSubject:: When format-patch generates a cover letter, use the specified subject for the cover letter instead of the generic template. + +branch.<name>.to:: +branch.<name>.cc:: + Additional recipients to include in a patch to be submitted + by mail. See the --to and --cc options in + linkgit:git-format-patch[1].
Documentation/git-format-patch.txt +6 -4
@@ -199,7 +199,7 @@ will want to ensure that threading is disabled for `git send-email`. Add a `To:` header to the email headers. This is in addition to any configured headers, and may be used multiple times. The emails given will be used along with any emails given by - `format.to` configurations. + `format.to` and `branch.<name>.to` configurations. The negated form `--no-to` discards all `To:` headers added so far (from config or command line).
@@ -207,7 +207,7 @@ will want to ensure that threading is disabled for `git send-email`. Add a `Cc:` header to the email headers. This is in addition to any configured headers, and may be used multiple times. The emails given will be used along with any emails given by - `format.cc` configurations. + `format.cc` and `branch.<name>.cc` configurations. The negated form `--no-cc` discards all `Cc:` headers added so far (from config or command line).
@@ -335,7 +335,7 @@ CONFIGURATION ------------- You can specify extra mail header lines to be added to each message, defaults for the subject prefix and file suffix, number patches when -outputting more than one patch, add "To" or "Cc:" headers, configure +outputting more than one patch, add "To:" or "Cc:" headers, configure attachments, and sign off patches with configuration variables. ------------
@@ -352,11 +352,13 @@ attachments, and sign off patches with configuration variables. ------------ In addition, for a specific branch, you can specify a custom cover -letter subject. +letter subject, and add additional "To:" or "Cc:" headers. ------------ [branch "branch-name"] coverSubject = "subject for branch-name only" + to = <email> + cc = <email> ------------ DISCUSSION
builtin/log.c +59 -4
95 lines not on this page · raw message
t/t4014-format-patch.sh +88 -20
157 lines not on this page · raw message
Signature · 1 line
2.21.0.1049.geb646f7864
Quoted 8 lines · Denton Liu
Currently, format-patch only accepts branch.<name>.description as a branch-specific configuration variable. However, there are many other options which would be useful to have on a branch-by-branch basis, namely cover letter subject and To: and Cc: headers.
Teach format-patch to recognise these branch-specific configuration options.
Quoted 8 lines
Note that this patchset[1] was created using these new configuration options:
[branch "submitted/fix-revisions-txt"]
coverSubject = "cleanup revisions.txt" cc = "Andreas Heiduk <[email protected]>" cc = "Duy Nguyen <[email protected]>" cc = "Junio C Hamano <[email protected]>"
Do we have format.<something> configuration for these things?
What I am trying to get at is if these are better structured similar to http options where http.<something> supplies the overall default for <something>, while http.<destination>.<something> gives a more destination site specific override of that default. I.e. format.cc is used as fallback, while format.<branch>.cc is used to override.
In any case, it smells to me that branch.<branch>.cc does not hint strongly enough that they are meant to affect format-patch.
Hi Junio,
Quoted 13 lines · Junio C Hamano
Quoted 11 lines · Denton Liu
Currently, format-patch only accepts branch.<name>.description as a branch-specific configuration variable. However, there are many other options which would be useful to have on a branch-by-branch basis, namely cover letter subject and To: and Cc: headers.
Teach format-patch to recognise these branch-specific configuration options.
Note that this patchset[1] was created using these new configuration options:
Quoted 7 lines
Quoted 5 lines
[branch "submitted/fix-revisions-txt"]
coverSubject = "cleanup revisions.txt" cc = "Andreas Heiduk <[email protected]>" cc = "Duy Nguyen <[email protected]>" cc = "Junio C Hamano <[email protected]>"Do we have format.<something> configuration for these things?
Currently, we have format.{to,cc} but not format.coverSubject. The reason why is that for the cover-subject, I didn't think that it would make a lot of sense to have a general configuration for this since it varies between branches, just like how branch.<name>.description does not have a matching format.description.
Quoted 6 lines
What I am trying to get at is if these are better structured similar to http options where http.<something> supplies the overall default for <something>, while http.<destination>.<something> gives a more destination site specific override of that default. I.e. format.cc is used as fallback, while format.<branch>.cc is used to override.
The reason why I chose to use branch.<name>.* is because format-patch currently reads from branch.<name>.description and I wanted to build on top of that. In addition, I didn't want to scatter branch-specific configs in two different place (i.e. have a branch.<branchName>.description alongside a format.<branchName>.coverSubject).
Quoted 5 lines
In any case, it smells to me that branch.<branch>.cc does not hint strongly enough that they are meant to affect format-patch.
Would you suggest moving to a format.<branchname>.* approach or would it make sense to rename the configs to something like branch.<name>.{emailCoverSubject,emailTo,emailCc}?
Thanks,
Denton
Quoted 5 lines · Denton Liu
The reason why I chose to use branch.<name>.* is because format-patch currently reads from branch.<name>.description and I wanted to build on top of that. In addition, I didn't want to scatter branch-specific configs in two different place (i.e. have a branch.<branchName>.description alongside a format.<branchName>.coverSubject).
The "branch.<name>.description" variable lives at a lot higher level of abstraction than "use this for the default value of option X of the command Y". It gives a place for the user to state what the branch is about. It makes 100% sense not to have it under format.* hierarchy, because it is designed to be agnostic to what individual command uses it for. It is there to talk about what the branch is for, and what the variable says about the branch to its users, i.e. various tools, does not change depending on who is listening to it.
The format-patch command may use it as a hint for writing the cover letter message. Repository browsers may use it while listing the branches when more descriptive text than the branch name is desired. Request-pull tool may use it when preparing the branch summary.
The point is that "description" is about "what that *branch* is", not "what that branch means for the format-patch user".
You cannot compare that with something like "when format-patch prepares an e-mail, add CC: header to this address", which is very specific to the single command, i.e. "how command X uses it". I think that is the gist of the new variables you are adding.
Quoted 6 lines
Quoted 2 lines
In any case, it smells to me that branch.<branch>.cc does not hint strongly enough that they are meant to affect format-patch.
Would you suggest moving to a format.<branchname>.* approach or would it make sense to rename the configs to something like branch.<name>.{emailCoverSubject,emailTo,emailCc}?
So if I have to pick between the two, I would probably vote for the former from the philosophical ground, but operationally, I suspect that the latter would be much simpler to use. You could even have "git branch -d <name>" to get rid of them at the same time.
But as I may have hinted in the message you are responding to, I am not quite convinced we want these configuration variables in the first place. Why should both description and coverSubject need to exist? Perhaps we should add a heuristic like "If the branch description looks like a single line, optionally followed by 'a blank line and more paragraphs', use the first line as the subject of the cover letter (and the remainder as the body of the cover letter) or something?
Quoted 1 line · Junio C Hamano
Denton Liu <[email protected]> writes:
[snip]
Quoted 10 lines
Quoted 4 lines
Would you suggest moving to a format.<branchname>.* approach or would it make sense to rename the configs to something like branch.<name>.{emailCoverSubject,emailTo,emailCc}?
So if I have to pick between the two, I would probably vote for the former from the philosophical ground, but operationally, I suspect that the latter would be much simpler to use. You could even have "git branch -d <name>" to get rid of them at the same time.
Quoted 9 lines
But as I may have hinted in the message you are responding to, I am not quite convinced we want these configuration variables in the first place. Why should both description and coverSubject need to exist? Perhaps we should add a heuristic like "If the branch description looks like a single line, optionally followed by 'a blank line and more paragraphs', use the first line as the subject of the cover letter (and the remainder as the body of the cover letter) or something?
I considered doing something like that but I opted not to because it wouldn't be a backwards compatible change and I didn't want to surprise any future users with a change like this.
For branch.<branchname>.{to,cc}, I wanted these config options because the current method for format-patch to handle Cc-lists is just manually keeping track of the people who have responded and entering them into the --cc option of format-patch.
Quoted 25 lines · Denton Liu
Quoted 1 line · Junio C Hamano
Denton Liu <[email protected]> writes:
[snip]
Quoted 10 lines
Quoted 4 lines
Would you suggest moving to a format.<branchname>.* approach or would it make sense to rename the configs to something like branch.<name>.{emailCoverSubject,emailTo,emailCc}?
So if I have to pick between the two, I would probably vote for the former from the philosophical ground, but operationally, I suspect that the latter would be much simpler to use. You could even have "git branch -d <name>" to get rid of them at the same time.
Quoted 9 lines
But as I may have hinted in the message you are responding to, I am not quite convinced we want these configuration variables in the first place. Why should both description and coverSubject need to exist? Perhaps we should add a heuristic like "If the branch description looks like a single line, optionally followed by 'a blank line and more paragraphs', use the first line as the subject of the cover letter (and the remainder as the body of the cover letter) or something?
Quoted 8 lines
I considered doing something like that but I opted not to because it wouldn't be a backwards compatible change and I didn't want to surprise any future users with a change like this.
For branch.<branchname>.{to,cc}, I wanted these config options because the current method for format-patch to handle Cc-lists is just manually keeping track of the people who have responded and entering them into the --cc option of format-patch.
This may just be more insanity to implement right now, but perhaps in addition to "gitdir:" etc. in the IncludeIf config syntax we'd want to aim for "HEADref" (or some saner name). I.e. allowing to include/enable arbitrary config based on the ref name.
Chicken & egg problems though...
Quoted 6 lines · Ævar Arnfjörð Bjarmason
This may just be more insanity to implement right now, but perhaps in addition to "gitdir:" etc. in the IncludeIf config syntax we'd want to aim for "HEADref" (or some saner name). I.e. allowing to
include/enablearbitrary config based on the ref name.Chicken & egg problems though...
The saner name might be
[IncludeIf "onBranch:my-topic"] path = ...
Would we discard the section when "branch -d my-topic" is done, or would we keep it for the next creation of the branch with the same name?
v2 cover teach branch-specific options for format-patch
In reply to Denton LiuHi all,
I thought a lot about building the branch-specific include option but I opted against this because format.<name>.coverSubject is a branch-exclusive config option, whereas it doesn't make sense to have a format.coverSubject option.
Thus, if we pursue this, we *need* to have a format.<name>.* section so let's not deal with the complexity of buliding a generic include system for now.
Also, I might consider adding a format.<name>.outputDirectory option in the future but let's see what kind of comments this patchset gets.
Changes since v1:
* Used format.<branch-name>.* variables instead of branch.<branch-name>.*
Denton Liu (6):
t4014: clean up style
Doc: add more detail for git-format-patch
format-patch: make cover letter subject configurable
format-patch: move extra_headers logic later
string-list: create string_list_append_all
format-patch: read branch-specific To: and Cc: headers
Documentation/config/format.txt | 12 +- Documentation/git-format-patch.txt | 33 +- builtin/branch.c | 16 +- builtin/log.c | 162 +++++-- string-list.c | 9 + string-list.h | 7 + t/t3200-branch.sh | 8 +- t/t4014-format-patch.sh | 708 +++++++++++++++++------------ t/t9902-completion.sh | 5 +- 9 files changed, 608 insertions(+), 352 deletions(-)
Interdiff against v1:
Documentation/config/branch.txt +0 -10
@@ -100,13 +100,3 @@ branch.<name>.description:: `git branch --edit-description`. Branch description is automatically added in the format-patch cover letter or request-pull summary. - -branch.<name>.coverSubject:: - When format-patch generates a cover letter, use the specified - subject for the cover letter instead of the generic template. - -branch.<name>.to:: -branch.<name>.cc:: - Additional recipients to include in a patch to be submitted - by mail. See the --to and --cc options in - linkgit:git-format-patch[1].
Documentation/config/format.txt +10 -2
@@ -28,14 +28,22 @@ format.headers:: format.to:: format.cc:: +format.<branch-name>.to:: +format.<branch-name>.cc:: Additional recipients to include in a patch to be submitted - by mail. See the --to and --cc options in - linkgit:git-format-patch[1]. + by mail. For the <branch-name> options, the recipients are only + included if patches are generated for the given <branch-name>. + See the --to and --cc options in linkgit:git-format-patch[1]. format.subjectPrefix:: The default for format-patch is to output files with the '[PATCH]' subject prefix. Use this variable to change that prefix. +format.<branch-name>.coverSubject:: + When format-patch generates a cover letter for the given + <branch-name>, use the specified subject for the cover letter + instead of the generic template. + format.signature:: The default for format-patch is to output a signature containing the Git version number. Use this variable to change that default.
Documentation/git-format-patch.txt +3 -3
@@ -199,7 +199,7 @@ will want to ensure that threading is disabled for `git send-email`. Add a `To:` header to the email headers. This is in addition to any configured headers, and may be used multiple times. The emails given will be used along with any emails given by - `format.to` and `branch.<name>.to` configurations. + `format.to` and `format.<branch-name>.to` configurations. The negated form `--no-to` discards all `To:` headers added so far (from config or command line).
@@ -207,7 +207,7 @@ will want to ensure that threading is disabled for `git send-email`. Add a `Cc:` header to the email headers. This is in addition to any configured headers, and may be used multiple times. The emails given will be used along with any emails given by - `format.cc` and `branch.<name>.cc` configurations. + `format.cc` and `format.<branch-name>.cc` configurations. The negated form `--no-cc` discards all `Cc:` headers added so far (from config or command line).
@@ -355,7 +355,7 @@ In addition, for a specific branch, you can specify a custom cover letter subject, and add additional "To:" or "Cc:" headers. ------------ -[branch "branch-name"] +[format "branch-name"] coverSubject = "subject for branch-name only" to = <email> cc = <email>
branch.c +2 -12
@@ -163,11 +163,11 @@ static void setup_tracking(const char *new_ref, const char *orig_ref,free (tracking.src); } -static int read_branch_config (struct strbuf *buf,const char *branch_name,const char *key) +int read_branch_desc (struct strbuf *buf,const char *branch_name) {char *v =NULL ;struct strbuf name =STRBUF_INIT ; -strbuf_addf (&name,"branch.%s.%s" , branch_name, key); +strbuf_addf (&name,"branch.%s.description" , branch_name);if (git_config_get_string (name.buf, &v)) {strbuf_release (&name);return -1 ;
@@ -178,16 +178,6 @@ static int read_branch_config(struct strbuf *buf, const char *branch_name, constreturn 0 ; } -int read_branch_desc (struct strbuf *buf,const char *branch_name) -{ -return read_branch_config (buf, branch_name,"description" ); -} - -int read_branch_subject (struct strbuf *buf,const char *branch_name) -{ -return read_branch_config (buf, branch_name,"coversubject" ); -} -/* * Check if 'name' can be a valid name for a branch; die otherwise. * Return 1 if the named branch already exists; return 0 otherwise.
branch.h +0 -5
@@ -79,11 +79,6 @@ int install_branch_config(int flag, const char *local, const char *origin, const*/ int read_branch_desc (struct strbuf *,const char *branch_name); -/* -* Read branch subject -*/ -extern int read_branch_subject (struct strbuf *,const char *branch_name); -/* * Check if a branch is checked out in the main worktree or any linked * worktree and die (with a message describing its checkout location) if
builtin/branch.c +13 -3
@@ -178,12 +178,22 @@ static int check_branch_commit(const char *branchname, const char *refname,return 0 ; } +static const char *branch_specific_config[] = { +"branch" , +"format" , +NULL +}; +static void delete_branch_config (const char *branchname) {struct strbuf buf =STRBUF_INIT ; -strbuf_addf (&buf,"branch.%s" , branchname); -if (git_config_rename_section (buf.buf,NULL ) <0 ) -warning (_ ("Update of config-file failed" )); +int i; +for (i =0 ; branch_specific_config[i]; i++) { +strbuf_addf (&buf,"%s.%s" , branch_specific_config[i], branchname); +if (git_config_rename_section (buf.buf,NULL ) <0 ) +warning (_ ("Update of config-file failed" )); +strbuf_reset (&buf); + }strbuf_release (&buf); }
builtin/log.c +17 -2
@@ -1032,6 +1032,21 @@ static void show_diffstat(struct rev_info *rev,fprintf (rev->diffopt.file,"\n" ); } +static int read_branch_subject (struct strbuf *buf,const char *branch_name) +{ +char *v =NULL ; +struct strbuf name =STRBUF_INIT ; +strbuf_addf (&name,"format.%s.coverSubject" , branch_name); +if (git_config_get_string (name.buf, &v)) { +strbuf_release (&name); +return -1 ; + } +strbuf_addstr (buf, v); +free (v); +strbuf_release (&name); +return 0 ; +} +static void add_branch_headers (struct rev_info *rev,const char *branch_name) {struct strbuf buf =STRBUF_INIT ;
@@ -1064,7 +1079,7 @@ static void add_branch_headers(struct rev_info *rev, const char *branch_name)*/ if (!to_cleared) { -strbuf_addf (&buf,"branch.%s.to" , branch_name); +strbuf_addf (&buf,"format.%s.to" , branch_name); values =git_config_get_value_multi (buf.buf);if (values)string_list_append_all (&extra_to, values);
@@ -1072,7 +1087,7 @@ static void add_branch_headers(struct rev_info *rev, const char *branch_name)if (!cc_cleared) {strbuf_reset (&buf); -strbuf_addf (&buf,"branch.%s.cc" , branch_name); +strbuf_addf (&buf,"format.%s.cc" , branch_name); values =git_config_get_value_multi (buf.buf);if (values)string_list_append_all (&extra_cc, values);
t/t3200-branch.sh +7 -1
@@ -782,9 +782,15 @@ test_expect_success 'test tracking setup via --track but deeper' ' ' test_expect_success 'test deleting branch deletes branch config' ' + git config format.my7.coverSubject "cover subject" && + git config format.my7.to "To Me <[email protected]>" && + git config format.my7.cc "Cc Me <[email protected]>" && git branch -d my7 && test -z "$(git config branch.my7.remote)" && - test -z "$(git config branch.my7.merge)" + test -z "$(git config branch.my7.merge)" && + test -z "$(git config format.my7.coverSubject)" + test -z "$(git config format.my7.to)" && + test -z "$(git config format.my7.cc)" ' test_expect_success 'test deleting branch without config' '
t/t4014-format-patch.sh +12 -12
@@ -237,7 +237,7 @@ test_expect_failure 'configuration To: header (rfc2047)' ' test_expect_success 'branch-specific configuration To: header (ascii)' ' test_unconfig format.to && - git config branch.side.to "R E Cipient <[email protected]>" && + git config format.side.to "R E Cipient <[email protected]>" && git format-patch --stdout master..side >patch10 && sed -e "/^\$/q" patch10 >hdrs10 && grep "^To: R E Cipient <[email protected]>\$" hdrs10
@@ -245,7 +245,7 @@ test_expect_success 'branch-specific configuration To: header (ascii)' ' test_expect_failure 'branch-specific configuration To: header (rfc822)' ' - git config branch.side.to "R. E. Cipient <[email protected]>" && + git config format.side.to "R. E. Cipient <[email protected]>" && git format-patch --stdout master..side >patch10 && sed -e "/^\$/q" patch10 >hdrs10 && grep "^To: \"R. E. Cipient\" <[email protected]>\$" hdrs10
@@ -253,7 +253,7 @@ test_expect_failure 'branch-specific configuration To: header (rfc822)' ' test_expect_failure 'branch-specific configuration To: header (rfc2047)' ' - git config branch.side.to "R Ä Cipient <[email protected]>" && + git config format.side.to "R Ä Cipient <[email protected]>" && git format-patch --stdout master..side >patch10 && sed -e "/^\$/q" patch10 >hdrs10 && grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" hdrs10
@@ -265,10 +265,10 @@ test_expect_success 'all recipients included from all sources' ' git config --add format.to "Format To2 <[email protected]>" && git config format.cc "Format Cc1 <[email protected]>" && git config --add format.cc "Format Cc2 <[email protected]>" && - git config branch.side.to "Branch To1 <[email protected]>" && - git config --add branch.side.to "Branch To2 <[email protected]>" && - git config branch.side.cc "Branch Cc1 <[email protected]>" && - git config --add branch.side.cc "Branch Cc2 <[email protected]>" && + git config format.side.to "Branch To1 <[email protected]>" && + git config --add format.side.to "Branch To2 <[email protected]>" && + git config format.side.cc "Branch Cc1 <[email protected]>" && + git config --add format.side.cc "Branch Cc2 <[email protected]>" && cat <<-\EOF >expect && To: Format To1 <[email protected]>, Format To2 <[email protected]>,
@@ -345,7 +345,7 @@ test_expect_success '--no-to overrides config.to' ' git config --replace-all format.to \ "R E Cipient <[email protected]>" && - git config --replace-all branch.side.to \ + git config --replace-all format.side.to \ "B R Anch <[email protected]>" && git format-patch --no-to --stdout master..side >patch11 && sed -e "/^\$/q" patch11 >hdrs11 &&
@@ -358,7 +358,7 @@ test_expect_success '--no-to and --to replaces config.to' ' git config --replace-all format.to \ "Someone <[email protected]>" && - git config --replace-all branch.side.to \ + git config --replace-all format.side.to \ "B R Anch2 <[email protected]>" && git format-patch --no-to --to="Someone Else <[email protected]>" \ --stdout master..side >patch12 &&
@@ -373,7 +373,7 @@ test_expect_success '--no-cc overrides config.cc' ' git config --replace-all format.cc \ "C E Cipient <[email protected]>" && - git config --replace-all branch.side.cc \ + git config --replace-all format.side.cc \ "B R Anch3 <[email protected]>" && git format-patch --no-cc --stdout master..side >patch13 && sed -e "/^\$/q" patch13 >hdrs13 &&
@@ -1538,7 +1538,7 @@ test_expect_success 'format patch ignores color.ui' ' ' test_expect_success 'cover letter with config subject' ' - test_config branch.rebuild-1.coverSubject "config subject" && + test_config format.rebuild-1.coverSubject "config subject" && git checkout rebuild-1 && git format-patch --stdout --cover-letter master >actual && grep "Subject: \[PATCH 0/2\] config subject" actual
@@ -1551,7 +1551,7 @@ test_expect_success 'cover letter with command-line subject' ' ' test_expect_success 'cover letter with command-line subject overrides config' ' - test_config branch.rebuild-1.coverSubject "config subject" && + test_config format.rebuild-1.coverSubject "config subject" && git checkout rebuild-1 && git format-patch --stdout --cover-letter --cover-subject "command-line subject" master >actual && grep "Subject: \[PATCH 0/2\] command-line subject" actual
Signature · 1 line
2.21.0.1049.geb646f7864
PATCH v2 1/6 t4014: clean up style
In Git's tests, there is typically no space between the redirection operator and the filename. Remove these spaces.
Since output is silenced when running without -v and debugging output is useful with -v, remove redirections to /dev/null.
Change here-docs from <<\EOF to <<-\EOF so that they can be indented along with the rest of the test case.
Finally, refactor to remove Git commands upstream of pipe. This way, if an invocation of a Git command fails, the return code won't be lost. Keep upstream non-Git commands since we have to assume a base level of sanity.
--- t/t4014-format-patch.sh | 614 +++++++++++++++++++++------------------- 1 file changed, 319 insertions(+), 295 deletions(-)
t/t4014-format-patch.sh +319 -295
@@ -34,7 +34,8 @@ test_expect_success setup ' git commit -m "Side changes #3 with \\n backslash-n in it." && git checkout master && - git diff-tree -p C2 | git apply --index && + git diff-tree -p C2 >patch && + git apply --index <patch && test_tick && git commit -m "Master accepts moral equivalent of #2"
@@ -77,7 +78,7 @@ test_expect_success "format-patch doesn't consider merge commits" ' git checkout -b merger master && test_tick && git merge --no-ff slave && - cnt=$(git format-patch -3 --stdout | grep "^From " | wc -l) && + cnt=$(git format-patch -3 --stdout >patch && grep "^From " patch | wc -l) && test $cnt = 3 '
@@ -85,21 +86,22 @@ test_expect_success "format-patch result applies" ' git checkout -b rebuild-0 master && git am -3 patch0 && - cnt=$(git rev-list master.. | wc -l) && - test $cnt = 2 + git rev-list master.. >list && + test_line_count = 2 list ' test_expect_success "format-patch --ignore-if-in-upstream result applies" ' git checkout -b rebuild-1 master && git am -3 patch1 && - cnt=$(git rev-list master.. | wc -l) && - test $cnt = 2 + git rev-list master.. >list && + test_line_count = 2 list ' test_expect_success 'commit did not screw up the log message' ' - git cat-file commit side | grep "^Side .* with .* backslash-n" + git cat-file commit side >actual && + grep "^Side .* with .* backslash-n" actual '
@@ -112,7 +114,8 @@ test_expect_success 'format-patch did not screw up the log message' ' test_expect_success 'replay did not screw up the log message' ' - git cat-file commit rebuild-1 | grep "^Side .* with .* backslash-n" + git cat-file commit rebuild-1 >actual && + grep "^Side .* with .* backslash-n" actual '
@@ -122,8 +125,8 @@ test_expect_success 'extra headers' ' " && git config --add format.headers "Cc: S E Cipient <[email protected]> " && - git format-patch --stdout master..side > patch2 && - sed -e "/^\$/q" patch2 > hdrs2 && + git format-patch --stdout master..side >patch2 && + sed -e "/^\$/q" patch2 >hdrs2 && grep "^To: R E Cipient <[email protected]>\$" hdrs2 && grep "^Cc: S E Cipient <[email protected]>\$" hdrs2
@@ -134,7 +137,7 @@ test_expect_success 'extra headers without newlines' ' git config --replace-all format.headers "To: R E Cipient <[email protected]>" && git config --add format.headers "Cc: S E Cipient <[email protected]>" && git format-patch --stdout master..side >patch3 && - sed -e "/^\$/q" patch3 > hdrs3 && + sed -e "/^\$/q" patch3 >hdrs3 && grep "^To: R E Cipient <[email protected]>\$" hdrs3 && grep "^Cc: S E Cipient <[email protected]>\$" hdrs3
@@ -144,8 +147,8 @@ test_expect_success 'extra headers with multiple To:s' ' git config --replace-all format.headers "To: R E Cipient <[email protected]>" && git config --add format.headers "To: S E Cipient <[email protected]>" && - git format-patch --stdout master..side > patch4 && - sed -e "/^\$/q" patch4 > hdrs4 && + git format-patch --stdout master..side >patch4 && + sed -e "/^\$/q" patch4 >hdrs4 && grep "^To: R E Cipient <[email protected]>,\$" hdrs4 && grep "^ *S E Cipient <[email protected]>\$" hdrs4 '
@@ -153,72 +156,82 @@ test_expect_success 'extra headers with multiple To:s' ' test_expect_success 'additional command line cc (ascii)' ' git config --replace-all format.headers "Cc: R E Cipient <[email protected]>" && - git format-patch --cc="S E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch5 && - grep "^Cc: R E Cipient <[email protected]>,\$" patch5 && - grep "^ *S E Cipient <[email protected]>\$" patch5 + git format-patch --cc="S E Cipient <[email protected]>" --stdout master..side >patch5 && + sed -e "/^\$/q" patch5 >hdrs5 && + grep "^Cc: R E Cipient <[email protected]>,\$" hdrs5 && + grep "^ *S E Cipient <[email protected]>\$" hdrs5 ' test_expect_failure 'additional command line cc (rfc822)' ' git config --replace-all format.headers "Cc: R E Cipient <[email protected]>" && - git format-patch --cc="S. E. Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch5 && - grep "^Cc: R E Cipient <[email protected]>,\$" patch5 && - grep "^ *\"S. E. Cipient\" <[email protected]>\$" patch5 + git format-patch --cc="S. E. Cipient <[email protected]>" --stdout master..side >patch5 && + sed -e "/^\$/q" patch5 >hdrs5 && + grep "^Cc: R E Cipient <[email protected]>,\$" hdrs5 && + grep "^ *\"S. E. Cipient\" <[email protected]>\$" hdrs5 ' test_expect_success 'command line headers' ' git config --unset-all format.headers && - git format-patch --add-header="Cc: R E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch6 && - grep "^Cc: R E Cipient <[email protected]>\$" patch6 + git format-patch --add-header="Cc: R E Cipient <[email protected]>" --stdout master..side >patch6 && + sed -e "/^\$/q" patch6 >hdrs6 && + grep "^Cc: R E Cipient <[email protected]>\$" hdrs6 ' test_expect_success 'configuration headers and command line headers' ' git config --replace-all format.headers "Cc: R E Cipient <[email protected]>" && - git format-patch --add-header="Cc: S E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch7 && - grep "^Cc: R E Cipient <[email protected]>,\$" patch7 && - grep "^ *S E Cipient <[email protected]>\$" patch7 + git format-patch --add-header="Cc: S E Cipient <[email protected]>" --stdout master..side >patch7 && + sed -e "/^\$/q" patch7 >hdrs7 && + grep "^Cc: R E Cipient <[email protected]>,\$" hdrs7 && + grep "^ *S E Cipient <[email protected]>\$" hdrs7 ' test_expect_success 'command line To: header (ascii)' ' git config --unset-all format.headers && - git format-patch --to="R E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch8 && - grep "^To: R E Cipient <[email protected]>\$" patch8 + git format-patch --to="R E Cipient <[email protected]>" --stdout master..side >patch8 && + sed -e "/^\$/q" patch8 >hdrs8 && + grep "^To: R E Cipient <[email protected]>\$" hdrs8 ' test_expect_failure 'command line To: header (rfc822)' ' - git format-patch --to="R. E. Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch8 && - grep "^To: \"R. E. Cipient\" <[email protected]>\$" patch8 + git format-patch --to="R. E. Cipient <[email protected]>" --stdout master..side >patch8 && + sed -e "/^\$/q" patch8 >hdrs8 && + grep "^To: \"R. E. Cipient\" <[email protected]>\$" hdrs8 ' test_expect_failure 'command line To: header (rfc2047)' ' - git format-patch --to="R Ä Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch8 && - grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" patch8 + git format-patch --to="R Ä Cipient <[email protected]>" --stdout master..side >patch8 && + sed -e "/^\$/q" patch8 >hdrs8 && + grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" hdrs8 ' test_expect_success 'configuration To: header (ascii)' ' git config format.to "R E Cipient <[email protected]>" && - git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && - grep "^To: R E Cipient <[email protected]>\$" patch9 + git format-patch --stdout master..side >patch9 && + sed -e "/^\$/q" patch9 >hdrs9 && + grep "^To: R E Cipient <[email protected]>\$" hdrs9 ' test_expect_failure 'configuration To: header (rfc822)' ' git config format.to "R. E. Cipient <[email protected]>" && - git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && - grep "^To: \"R. E. Cipient\" <[email protected]>\$" patch9 + git format-patch --stdout master..side >patch9 && + sed -e "/^\$/q" patch9 >hdrs9 && + grep "^To: \"R. E. Cipient\" <[email protected]>\$" hdrs9 ' test_expect_failure 'configuration To: header (rfc2047)' ' git config format.to "R Ä Cipient <[email protected]>" && - git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && - grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" patch9 + git format-patch --stdout master..side >patch9 && + sed -e "/^\$/q" patch9 >hdrs9 && + grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" hdrs9 ' # check_patch <patch>: Verify that <patch> looks like a half-sane
@@ -231,52 +244,52 @@ check_patch () { test_expect_success 'format.from=false' ' - git -c format.from=false format-patch --stdout master..side | - sed -e "/^\$/q" >patch && + git -c format.from=false format-patch --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && check_patch patch && - ! grep "^From: C O Mitter <[email protected]>\$" patch + ! grep "^From: C O Mitter <[email protected]>\$" hdrs ' test_expect_success 'format.from=true' ' - git -c format.from=true format-patch --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - grep "^From: C O Mitter <[email protected]>\$" patch + git -c format.from=true format-patch --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + grep "^From: C O Mitter <[email protected]>\$" hdrs ' test_expect_success 'format.from with address' ' - git -c format.from="F R Om <[email protected]>" format-patch --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - grep "^From: F R Om <[email protected]>\$" patch + git -c format.from="F R Om <[email protected]>" format-patch --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + grep "^From: F R Om <[email protected]>\$" hdrs ' test_expect_success '--no-from overrides format.from' ' - git -c format.from="F R Om <[email protected]>" format-patch --no-from --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - ! grep "^From: F R Om <[email protected]>\$" patch + git -c format.from="F R Om <[email protected]>" format-patch --no-from --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + ! grep "^From: F R Om <[email protected]>\$" hdrs ' test_expect_success '--from overrides format.from' ' - git -c format.from="F R Om <[email protected]>" format-patch --from --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - ! grep "^From: F R Om <[email protected]>\$" patch + git -c format.from="F R Om <[email protected]>" format-patch --from --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + ! grep "^From: F R Om <[email protected]>\$" hdrs ' test_expect_success '--no-to overrides config.to' ' git config --replace-all format.to \ "R E Cipient <[email protected]>" && - git format-patch --no-to --stdout master..side | - sed -e "/^\$/q" >patch10 && - check_patch patch10 && - ! grep "^To: R E Cipient <[email protected]>\$" patch10 + git format-patch --no-to --stdout master..side >patch10 && + sed -e "/^\$/q" patch10 >hdrs10 && + check_patch hdrs10 && + ! grep "^To: R E Cipient <[email protected]>\$" hdrs10 ' test_expect_success '--no-to and --to replaces config.to' '
@@ -284,31 +297,31 @@ test_expect_success '--no-to and --to replaces config.to' ' git config --replace-all format.to \ "Someone <[email protected]>" && git format-patch --no-to --to="Someone Else <[email protected]>" \ - --stdout master..side | - sed -e "/^\$/q" >patch11 && - check_patch patch11 && - ! grep "^To: Someone <[email protected]>\$" patch11 && - grep "^To: Someone Else <[email protected]>\$" patch11 + --stdout master..side >patch11 && + sed -e "/^\$/q" patch11 >hdrs11 && + check_patch hdrs11 && + ! grep "^To: Someone <[email protected]>\$" hdrs11 && + grep "^To: Someone Else <[email protected]>\$" hdrs11 ' test_expect_success '--no-cc overrides config.cc' ' git config --replace-all format.cc \ "C E Cipient <[email protected]>" && - git format-patch --no-cc --stdout master..side | - sed -e "/^\$/q" >patch12 && - check_patch patch12 && - ! grep "^Cc: C E Cipient <[email protected]>\$" patch12 + git format-patch --no-cc --stdout master..side >patch12 && + sed -e "/^\$/q" patch12 >hdrs12 && + check_patch hdrs12 && + ! grep "^Cc: C E Cipient <[email protected]>\$" hdrs12 ' test_expect_success '--no-add-header overrides config.headers' ' git config --replace-all format.headers \ "Header1: B E Cipient <[email protected]>" && - git format-patch --no-add-header --stdout master..side | - sed -e "/^\$/q" >patch13 && - check_patch patch13 && - ! grep "^Header1: B E Cipient <[email protected]>\$" patch13 + git format-patch --no-add-header --stdout master..side >patch13 && + sed -e "/^\$/q" patch13 >hdrs13 && + check_patch hdrs13 && + ! grep "^Header1: B E Cipient <[email protected]>\$" hdrs13 ' test_expect_success 'multiple files' '
@@ -338,7 +351,7 @@ test_expect_success 'reroll count (-v)' ' check_threading () { expect="$1" && shift && - (git format-patch --stdout "$@"; echo $? > status.out) | + (git format-patch --stdout "$@"; echo $? >status.out) | # Prints everything between the Message-ID and In-Reply-To, # and replaces all Message-ID-lookalikes by a sequence number perl -ne '
@@ -353,12 +366,12 @@ check_threading () { print; } print "---\n" if /^From /i; - ' > actual && + ' >actual && test 0 = "$(cat status.out)" && test_cmp "$expect" actual } -cat >> expect.no-threading <<EOF +cat >>expect.no-threading <<EOF --- --- ---
@@ -369,7 +382,7 @@ test_expect_success 'no threading' ' check_threading expect.no-threading master ' -cat > expect.thread <<EOF +cat >expect.thread <<EOF --- Message-Id: <0> ---
@@ -386,7 +399,7 @@ test_expect_success 'thread' ' check_threading expect.thread --thread master ' -cat > expect.in-reply-to <<EOF +cat >expect.in-reply-to <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -406,7 +419,7 @@ test_expect_success 'thread in-reply-to' ' --thread master ' -cat > expect.cover-letter <<EOF +cat >expect.cover-letter <<EOF --- Message-Id: <0> ---
@@ -427,7 +440,7 @@ test_expect_success 'thread cover-letter' ' check_threading expect.cover-letter --cover-letter --thread master ' -cat > expect.cl-irt <<EOF +cat >expect.cl-irt <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -459,7 +472,7 @@ test_expect_success 'thread explicit shallow' ' --in-reply-to="<test.message>" --thread=shallow master ' -cat > expect.deep <<EOF +cat >expect.deep <<EOF --- Message-Id: <0> ---
@@ -477,7 +490,7 @@ test_expect_success 'thread deep' ' check_threading expect.deep --thread=deep master ' -cat > expect.deep-irt <<EOF +cat >expect.deep-irt <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -500,7 +513,7 @@ test_expect_success 'thread deep in-reply-to' ' --in-reply-to="<test.message>" master ' -cat > expect.deep-cl <<EOF +cat >expect.deep-cl <<EOF --- Message-Id: <0> ---
@@ -524,7 +537,7 @@ test_expect_success 'thread deep cover-letter' ' check_threading expect.deep-cl --cover-letter --thread=deep master ' -cat > expect.deep-cl-irt <<EOF +cat >expect.deep-cl-irt <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -606,7 +619,7 @@ test_expect_success 'cover-letter inherits diff options' ' ' -cat > expect << EOF +cat >expect <<EOF This is an excessively long subject line for a message due to the habit some projects have of not having a short, one-line subject at the start of the commit message, but rather sticking a whole
@@ -619,12 +632,12 @@ EOF test_expect_success 'shortlog of cover-letter wraps overly-long onelines' ' git format-patch --cover-letter -2 && - sed -e "1,/A U Thor/d" -e "/^\$/q" < 0000-cover-letter.patch > output && + sed -e "1,/A U Thor/d" -e "/^\$/q" <0000-cover-letter.patch >output && test_cmp expect output ' -cat > expect << EOF +cat >expect <<EOF index $before..$after 100644 --- a/file +++ b/file
@@ -646,7 +659,7 @@ test_expect_success 'format-patch respects -U' ' ' -cat > expect << EOF +cat >expect <<EOF diff --git a/file b/file index $before..$after 100644
@@ -662,7 +675,7 @@ EOF test_expect_success 'format-patch -p suppresses stat' ' git format-patch -p -2 && - sed -e "1,/^\$/d" -e "/^+5/q" < 0001-This-is-an-excessively-long-subject-line-for-a-messa.patch > output && + sed -e "1,/^\$/d" -e "/^+5/q" <0001-This-is-an-excessively-long-subject-line-for-a-messa.patch >output && test_cmp expect output '
@@ -717,7 +730,7 @@ test_expect_success 'format-patch from a subdirectory (3)' ' ' test_expect_success 'format-patch --in-reply-to' ' - git format-patch -1 --stdout --in-reply-to "[email protected]" > patch8 && + git format-patch -1 --stdout --in-reply-to "[email protected]" >patch8 && grep "^In-Reply-To: <[email protected]>" patch8 && grep "^References: <[email protected]>" patch8 '
@@ -738,20 +751,20 @@ test_expect_success 'format-patch --notes --signoff' ' sed "1,/^---$/d" out | grep "test message" ' -echo "fatal: --name-only does not make sense" > expect.name-only -echo "fatal: --name-status does not make sense" > expect.name-status -echo "fatal: --check does not make sense" > expect.check +echo "fatal: --name-only does not make sense" >expect.name-only +echo "fatal: --name-status does not make sense" >expect.name-status +echo "fatal: --check does not make sense" >expect.check test_expect_success 'options no longer allowed for format-patch' ' - test_must_fail git format-patch --name-only 2> output && + test_must_fail git format-patch --name-only 2>output && test_i18ncmp expect.name-only output && - test_must_fail git format-patch --name-status 2> output && + test_must_fail git format-patch --name-status 2>output && test_i18ncmp expect.name-status output && - test_must_fail git format-patch --check 2> output && + test_must_fail git format-patch --check 2>output && test_i18ncmp expect.check output' test_expect_success 'format-patch --numstat should produce a patch' ' - git format-patch --numstat --stdout master..side > output && + git format-patch --numstat --stdout master..side >output && test 5 = $(grep "^diff --git a/" output | wc -l)' test_expect_success 'format-patch -- <path>' '
@@ -763,20 +776,22 @@ test_expect_success 'format-patch --ignore-if-in-upstream HEAD' ' git format-patch --ignore-if-in-upstream HEAD ' -git_version="$(git --version | sed "s/.* //")" +git_version="$(git --version >version && sed "s/.* //" version)" signature() { printf "%s\n%s\n\n" "-- " "${1:-$git_version}" } test_expect_success 'format-patch default signature' ' - git format-patch --stdout -1 | tail -n 3 >output && + git format-patch --stdout -1 >patch && + tail -n 3 patch >output && signature >expect && test_cmp expect output ' test_expect_success 'format-patch --signature' ' - git format-patch --stdout --signature="my sig" -1 | tail -n 3 >output && + git format-patch --stdout --signature="my sig" -1 >patch && + tail -n 3 patch >output && signature "my sig" >expect && test_cmp expect output '
@@ -1167,282 +1182,282 @@ append_signoff() test_expect_success 'signoff: commit with no body' ' append_signoff </dev/null >actual && - cat <<\EOF | sed "s/EOL$//" >expected && -4:Subject: [PATCH] EOL -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat <<-\EOF | sed "s/EOL$//" >expected && + 4:Subject: [PATCH] EOL + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: commit with only subject' ' echo subject | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: commit with only subject that does not end with NL' ' printf subject | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: no existing signoffs' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + body + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: no existing signoffs and no trailing NL' ' printf "subject\n\nbody" | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: some random signoff' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: my@house -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: my@house -12:Signed-off-by: C O Mitter <[email protected]> -EOF + Signed-off-by: my@house + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: my@house + 12:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: misc conforming footer elements' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: my@house -(cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709) -Tested-by: Some One <[email protected]> -Bug: 1234 -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: my@house -15:Signed-off-by: C O Mitter <[email protected]> -EOF + Signed-off-by: my@house + (cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709) + Tested-by: Some One <[email protected]> + Bug: 1234 + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: my@house + 15:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: some random signoff-alike' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body -Fooled-by-me: my@house -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -11: -12:Signed-off-by: C O Mitter <[email protected]> -EOF + body + Fooled-by-me: my@house + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 11: + 12:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: not really a signoff' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -I want to mention about Signed-off-by: here. -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:I want to mention about Signed-off-by: here. -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + I want to mention about Signed-off-by: here. + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:I want to mention about Signed-off-by: here. + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: not really a signoff (2)' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -My unfortunate -Signed-off-by: example happens to be wrapped here. -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10:Signed-off-by: example happens to be wrapped here. -11:Signed-off-by: C O Mitter <[email protected]> -EOF + My unfortunate + Signed-off-by: example happens to be wrapped here. + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10:Signed-off-by: example happens to be wrapped here. + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: valid S-o-b paragraph in the middle' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -Signed-off-by: my@house -Signed-off-by: your@house + Signed-off-by: my@house + Signed-off-by: your@house -A lot of houses. -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: my@house -10:Signed-off-by: your@house -11: -13: -14:Signed-off-by: C O Mitter <[email protected]> -EOF + A lot of houses. + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: my@house + 10:Signed-off-by: your@house + 11: + 13: + 14:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: the same signoff at the end' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: C O Mitter <[email protected]> -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + Signed-off-by: C O Mitter <[email protected]> + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: the same signoff at the end, no trailing NL' ' printf "subject\n\nSigned-off-by: C O Mitter <[email protected]>" | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: the same signoff NOT at the end' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: C O Mitter <[email protected]> -Signed-off-by: my@house -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -12:Signed-off-by: my@house -EOF + Signed-off-by: C O Mitter <[email protected]> + Signed-off-by: my@house + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + 12:Signed-off-by: my@house + EOF test_cmp expected actual ' test_expect_success 'signoff: tolerate garbage in conforming footer' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Tested-by: my@house -Some Trash -Signed-off-by: C O Mitter <[email protected]> -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -13:Signed-off-by: C O Mitter <[email protected]> -EOF + Tested-by: my@house + Some Trash + Signed-off-by: C O Mitter <[email protected]> + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 13:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: respect trailer config' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -Myfooter: x -Some Trash -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -11: -12:Signed-off-by: C O Mitter <[email protected]> -EOF + Myfooter: x + Some Trash + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 11: + 12:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual && test_config trailer.Myfooter.ifexists add && - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -Myfooter: x -Some Trash -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + Myfooter: x + Some Trash + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: footer begins with non-signoff without @ sign' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Reviewed-id: Noone -Tested-by: my@house -Change-id: Ideadbeef -Signed-off-by: C O Mitter <[email protected]> -Bug: 1234 -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -14:Signed-off-by: C O Mitter <[email protected]> -EOF + Reviewed-id: Noone + Tested-by: my@house + Change-id: Ideadbeef + Signed-off-by: C O Mitter <[email protected]> + Bug: 1234 + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 14:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual '
@@ -1458,42 +1473,42 @@ test_expect_success 'cover letter using branch description (1)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter master >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (2)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter rebuild-1~2..rebuild-1 >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (3)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter ^master rebuild-1 >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (4)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter master.. >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (5)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter -2 HEAD >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (6)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter -2 >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter with nothing' '
@@ -1547,7 +1562,8 @@ test_expect_success 'format-patch format.outputDirectory option' ' test_config format.outputDirectory patches && rm -fr patches && git format-patch master..side && - test $(git rev-list master..side | wc -l) -eq $(ls patches | wc -l) + git rev-list master..side >list && + test_line_count = $(ls patches | wc -l) list ' test_expect_success 'format-patch -o overrides format.outputDirectory' '
@@ -1560,13 +1576,21 @@ test_expect_success 'format-patch -o overrides format.outputDirectory' ' test_expect_success 'format-patch --base' ' git checkout side && - git format-patch --stdout --base=HEAD~3 -1 | tail -n 7 >actual1 && - git format-patch --stdout --base=HEAD~3 HEAD~.. | tail -n 7 >actual2 && + git format-patch --stdout --base=HEAD~3 -1 >patch && + tail -n 7 patch >actual1 && + git format-patch --stdout --base=HEAD~3 HEAD~.. >patch && + tail -n 7 patch >actual2 && echo >expected && echo "base-commit: $(git rev-parse HEAD~3)" >>expected && - echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --stable | awk "{print \$1}")" >>expected && - echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --stable | awk "{print \$1}")" >>expected && - signature >> expected && + git show --patch HEAD~2 >patch && + git patch-id --stable <patch >patch.id.raw && + awk "{print \$1}" <patch.id.raw >patch.id && + echo "prerequisite-patch-id: $(cat patch.id)" >>expected && + git show --patch HEAD~1 >patch && + git patch-id --stable <patch >patch.id.raw && + awk "{print \$1}" <patch.id.raw >patch.id && + echo "prerequisite-patch-id: $(cat patch.id)" >>expected && + signature >>expected && test_cmp expected actual1 && test_cmp expected actual2 '
Signature · 1 line
2.21.0.1049.geb646f7864
PATCH v2 2/6 Doc: add more detail for git-format-patch
In reply to Denton LiuIn git-format-patch.txt, we were missing some key user information. First of all, using the --to and --cc options don't override format.to and format.cc variables, respectively. They add on to each other. Document this.
In addition, document the special value of --base=auto.
Finally, while we're at it, surround option arguments with <>.
--- Documentation/git-format-patch.txt | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
Documentation/git-format-patch.txt +11 -6
@@ -17,9 +17,9 @@ SYNOPSIS [--signature-file=<file>] [-n | --numbered | -N | --no-numbered] [--start-number <n>] [--numbered-files] - [--in-reply-to=Message-Id] [--suffix=.<sfx>] + [--in-reply-to=<Message-Id>] [--suffix=.<sfx>] [--ignore-if-in-upstream] - [--rfc] [--subject-prefix=Subject-Prefix] + [--rfc] [--subject-prefix=<Subject-Prefix>] [(--reroll-count|-v) <n>] [--to=<email>] [--cc=<email>] [--[no-]cover-letter] [--quiet] [--notes[=<ref>]]
@@ -158,7 +158,7 @@ Beware that the default for 'git send-email' is to thread emails itself. If you want `git format-patch` to take care of threading, you will want to ensure that threading is disabled for `git send-email`. ---in-reply-to=Message-Id:: +--in-reply-to=<Message-Id>:: Make the first mail (or all the mails with `--no-thread`) appear as a reply to the given Message-Id, which avoids breaking threads to provide a new patch series.
@@ -192,13 +192,17 @@ will want to ensure that threading is disabled for `git send-email`. --to=<email>:: Add a `To:` header to the email headers. This is in addition - to any configured headers, and may be used multiple times. + to any configured headers, and may be used multiple times. The + emails given will be used along with any emails given by + `format.to` configurations. The negated form `--no-to` discards all `To:` headers added so far (from config or command line). --cc=<email>:: Add a `Cc:` header to the email headers. This is in addition - to any configured headers, and may be used multiple times. + to any configured headers, and may be used multiple times. The + emails given will be used along with any emails given by + `format.cc` configurations. The negated form `--no-cc` discards all `Cc:` headers added so far (from config or command line).
@@ -309,7 +313,8 @@ you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`. --base=<commit>:: Record the base tree information to identify the state the patch series applies to. See the BASE TREE INFORMATION section - below for details. + below for details. If <commit> is equal to "auto", a base commit + is automatically chosen. --root:: Treat the revision argument as a <revision range>, even if it
Signature · 1 line
2.21.0.1049.geb646f7864
PATCH v2 3/6 format-patch: make cover letter subject configurable
In reply to Denton LiuWe used to populate the subject of the cover letter generated by git-format-patch with "*** SUBJECT HERE ***". However, if a user submits multiple patchsets, they may want to keep a consistent subject between rerolls.
If git-format-patch is run on a branch that has format.<branch-name>.coverSubject defined, make the cover letter's subject be that value instead of the generic "*** SUBJECT HERE ***".
In addition, add the --cover-subject option to override this setting.
Finally, make git branch -d also remove any format.<branch-name>.* configs, just like it currently removes all branch.<branch-name>.* configs.
--- Documentation/config/format.txt | 5 ++++ Documentation/git-format-patch.txt | 12 +++++++++ builtin/branch.c | 16 +++++++++--- builtin/log.c | 41 +++++++++++++++++++++++++----- t/t3200-branch.sh | 4 ++- t/t4014-format-patch.sh | 20 +++++++++++++++ t/t9902-completion.sh | 5 +++- 7 files changed, 91 insertions(+), 12 deletions(-)
Documentation/config/format.txt +5 -0
@@ -36,6 +36,11 @@ format.subjectPrefix:: The default for format-patch is to output files with the '[PATCH]' subject prefix. Use this variable to change that prefix. +format.<branch-name>.coverSubject:: + When format-patch generates a cover letter for the given + <branch-name>, use the specified subject for the cover letter + instead of the generic template. + format.signature:: The default for format-patch is to output a signature containing the Git version number. Use this variable to change that default.
Documentation/git-format-patch.txt +12 -0
@@ -19,6 +19,7 @@ SYNOPSIS [--start-number <n>] [--numbered-files] [--in-reply-to=<Message-Id>] [--suffix=.<sfx>] [--ignore-if-in-upstream] + [--cover-subject=<subject>] [--rfc] [--subject-prefix=<Subject-Prefix>] [(--reroll-count|-v) <n>] [--to=<email>] [--cc=<email>]
@@ -170,6 +171,10 @@ will want to ensure that threading is disabled for `git send-email`. patches being generated, and any patch that matches is ignored. +--cover-subject=<subject>:: + Instead of using the default "*** SUBJECT HERE ***" subject for + the cover letter, use the given <subject>. + --subject-prefix=<Subject-Prefix>:: Instead of the standard '[PATCH]' prefix in the subject line, instead use '[<Subject-Prefix>]'. This
@@ -346,6 +351,13 @@ attachments, and sign off patches with configuration variables. coverletter = auto ------------ +In addition, for a specific branch, you can specify a custom cover +letter subject. + +------------ +[format "branch-name"] + coverSubject = "subject for branch-name only" +------------ DISCUSSION ----------
builtin/branch.c +13 -3
@@ -178,12 +178,22 @@ static int check_branch_commit(const char *branchname, const char *refname,return 0 ; } +static const char *branch_specific_config[] = { +"branch" , +"format" , +NULL +}; +static void delete_branch_config (const char *branchname) {struct strbuf buf =STRBUF_INIT ; -strbuf_addf (&buf,"branch.%s" , branchname); -if (git_config_rename_section (buf.buf,NULL ) <0 ) -warning (_ ("Update of config-file failed" )); +int i; +for (i =0 ; branch_specific_config[i]; i++) { +strbuf_addf (&buf,"%s.%s" , branch_specific_config[i], branchname); +if (git_config_rename_section (buf.buf,NULL ) <0 ) +warning (_ ("Update of config-file failed" )); +strbuf_reset (&buf); + }strbuf_release (&buf); }
builtin/log.c +34 -7
95 lines not on this page · raw message
t/t3200-branch.sh +3 -1
@@ -782,9 +782,11 @@ test_expect_success 'test tracking setup via --track but deeper' ' ' test_expect_success 'test deleting branch deletes branch config' ' + git config format.my7.coverSubject "cover subject" && git branch -d my7 && test -z "$(git config branch.my7.remote)" && - test -z "$(git config branch.my7.merge)" + test -z "$(git config branch.my7.merge)" && + test -z "$(git config format.my7.coverSubject)" ' test_expect_success 'test deleting branch without config' '
t/t4014-format-patch.sh +20 -0
@@ -1469,6 +1469,26 @@ test_expect_success 'format patch ignores color.ui' ' test_cmp expect actual ' +test_expect_success 'cover letter with config subject' ' + test_config format.rebuild-1.coverSubject "config subject" && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter master >actual && + grep "Subject: \[PATCH 0/2\] config subject" actual +' + +test_expect_success 'cover letter with command-line subject' ' + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --cover-subject "command-line subject" master >actual && + grep "Subject: \[PATCH 0/2\] command-line subject" actual +' + +test_expect_success 'cover letter with command-line subject overrides config' ' + test_config format.rebuild-1.coverSubject "config subject" && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --cover-subject "command-line subject" master >actual && + grep "Subject: \[PATCH 0/2\] command-line subject" actual +' + test_expect_success 'cover letter using branch description (1)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello &&
t/t9902-completion.sh +4 -1
@@ -1548,7 +1548,10 @@ test_expect_success 'complete tree filename with metacharacters' ' ' test_expect_success PERL 'send-email' ' - test_completion "git send-email --cov" "--cover-letter " && + test_completion "git send-email --cov" <<-\EOF && + --cover-letter Z + --cover-subject=Z + EOF test_completion "git send-email ma" "master " '
Signature · 1 line
2.21.0.1049.geb646f7864
PATCH v2 4/6 format-patch: move extra_headers logic later
In reply to Denton LiuIn a future patch, we need to perform the addition of To: and Cc:
to extra_headers after the branch_name logic. Simply transpose this logic later in the function so that this happens. (This patch is best viewed with git diff --color-moved.)
Note that this logic only depends on the git_config and repo_init_revisions and is depended on by the patch creation logic which is directly below it so this move is effectively a no-op as no dependencies being reordered.
--- builtin/log.c | 58 +++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 29 deletions(-)
builtin/log.c +29 -29
@@ -1680,35 +1680,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) rev.subject_prefix =strbuf_detach (&sprefix,NULL ); } -for (i =0 ; i < extra_hdr.nr; i++) { -strbuf_addstr (&buf, extra_hdr.items[i].string); -strbuf_addch (&buf,'\n' ); - } - -if (extra_to.nr) -strbuf_addstr (&buf,"To: " ); -for (i =0 ; i < extra_to.nr; i++) { -if (i) -strbuf_addstr (&buf," " ); -strbuf_addstr (&buf, extra_to.items[i].string); -if (i +1 < extra_to.nr) -strbuf_addch (&buf,',' ); -strbuf_addch (&buf,'\n' ); - } - -if (extra_cc.nr) -strbuf_addstr (&buf,"Cc: " ); -for (i =0 ; i < extra_cc.nr; i++) { -if (i) -strbuf_addstr (&buf," " ); -strbuf_addstr (&buf, extra_cc.items[i].string); -if (i +1 < extra_cc.nr) -strbuf_addch (&buf,',' ); -strbuf_addch (&buf,'\n' ); - } - - rev.extra_headers =strbuf_detach (&buf,NULL ); -if (from) {if (split_ident_line (&rev.from_ident, from,strlen (from)))die (_ ("invalid ident line: %s" ), from);
@@ -1811,6 +1782,35 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } } +for (i =0 ; i < extra_hdr.nr; i++) { +strbuf_addstr (&buf, extra_hdr.items[i].string); +strbuf_addch (&buf,'\n' ); + } + +if (extra_to.nr) +strbuf_addstr (&buf,"To: " ); +for (i =0 ; i < extra_to.nr; i++) { +if (i) +strbuf_addstr (&buf," " ); +strbuf_addstr (&buf, extra_to.items[i].string); +if (i +1 < extra_to.nr) +strbuf_addch (&buf,',' ); +strbuf_addch (&buf,'\n' ); + } + +if (extra_cc.nr) +strbuf_addstr (&buf,"Cc: " ); +for (i =0 ; i < extra_cc.nr; i++) { +if (i) +strbuf_addstr (&buf," " ); +strbuf_addstr (&buf, extra_cc.items[i].string); +if (i +1 < extra_cc.nr) +strbuf_addch (&buf,',' ); +strbuf_addch (&buf,'\n' ); + } + + rev.extra_headers =strbuf_detach (&buf,NULL ); +/* * We cannot move this anywhere earlier because we do want to * know if --root was given explicitly from the command line.
Signature · 1 line
2.21.0.1049.geb646f7864
PATCH v2 5/6 string-list: create string_list_append_all
In reply to Denton LiuIn a future patch, we'll need to take one string_list and append it to the end of another. Create the string_list_append_all function which does this.
--- string-list.c | 9 +++++++++ string-list.h | 7 +++++++ 2 files changed, 16 insertions(+)
string-list.c +9 -0
@@ -215,6 +215,15 @@ struct string_list_item *string_list_append(struct string_list *list, list->strdup_strings ? xstrdup(string) : (char *)string); } +void string_list_append_all (struct string_list *list, +const struct string_list *append_list) +{ +struct string_list_item *item; +ALLOC_GROW (list->items, list->nr + append_list->nr, list->alloc); +for_each_string_list_item (item, append_list) +string_list_append (list, item->string); +} +/* * Encapsulate the compare function pointer because ISO C99 forbids * casting from void * to a function pointer and vice versa.
string-list.h +7 -0
@@ -208,6 +208,13 @@ struct string_list_item *string_list_append(struct string_list *list, const char*/ struct string_list_item *string_list_append_nodup (struct string_list *list,char *string); +/** +* Add all strings in append_list to list. If list->strdup_string is +* set, then each string is copied; otherwise the new string_list_entry +* refers to the entry in the append_list. +*/ +void string_list_append_all (struct string_list *list,const struct string_list *append_list); +/** * Sort the list's entries by string value in `strcmp()` order. */
Signature · 1 line
2.21.0.1049.geb646f7864
PATCH v2 6/6 format-patch: read branch-specific To: and Cc: headers
In reply to Denton LiuIf a user wishes to keep track of whom to Cc: on individual patchsets, they must manually keep track of each recipient and fill it in with the --cc option on git-format-patch each time. However, on the Git mailing list, Cc:'s are typically never dropped. As a result, it would be nice to have a method to keep track of recipients on a per-branch basis.
Currently, git-format-patch gets its To: headers from the --to options and the format.to config variable. The Cc: header is derived similarly.
In addition to the above, read To: and Cc: headers from format.<branch-name>.to and format.<branch-name>.cc so that users can have branch-specific configuration options.
--- Documentation/config/format.txt | 7 +- Documentation/git-format-patch.txt | 10 +-- builtin/log.c | 63 +++++++++++++++-- t/t3200-branch.sh | 4 ++ t/t4014-format-patch.sh | 108 +++++++++++++++++++++++------ 5 files changed, 162 insertions(+), 30 deletions(-)
Documentation/config/format.txt +5 -2
@@ -28,9 +28,12 @@ format.headers:: format.to:: format.cc:: +format.<branch-name>.to:: +format.<branch-name>.cc:: Additional recipients to include in a patch to be submitted - by mail. See the --to and --cc options in - linkgit:git-format-patch[1]. + by mail. For the <branch-name> options, the recipients are only + included if patches are generated for the given <branch-name>. + See the --to and --cc options in linkgit:git-format-patch[1]. format.subjectPrefix:: The default for format-patch is to output files with the '[PATCH]'
Documentation/git-format-patch.txt +6 -4
@@ -199,7 +199,7 @@ will want to ensure that threading is disabled for `git send-email`. Add a `To:` header to the email headers. This is in addition to any configured headers, and may be used multiple times. The emails given will be used along with any emails given by - `format.to` configurations. + `format.to` and `format.<branch-name>.to` configurations. The negated form `--no-to` discards all `To:` headers added so far (from config or command line).
@@ -207,7 +207,7 @@ will want to ensure that threading is disabled for `git send-email`. Add a `Cc:` header to the email headers. This is in addition to any configured headers, and may be used multiple times. The emails given will be used along with any emails given by - `format.cc` configurations. + `format.cc` and `format.<branch-name>.cc` configurations. The negated form `--no-cc` discards all `Cc:` headers added so far (from config or command line).
@@ -335,7 +335,7 @@ CONFIGURATION ------------- You can specify extra mail header lines to be added to each message, defaults for the subject prefix and file suffix, number patches when -outputting more than one patch, add "To" or "Cc:" headers, configure +outputting more than one patch, add "To:" or "Cc:" headers, configure attachments, and sign off patches with configuration variables. ------------
@@ -352,11 +352,13 @@ attachments, and sign off patches with configuration variables. ------------ In addition, for a specific branch, you can specify a custom cover -letter subject. +letter subject, and add additional "To:" or "Cc:" headers. ------------ [format "branch-name"] coverSubject = "subject for branch-name only" + to = <email> + cc = <email> ------------ DISCUSSION
builtin/log.c +59 -4
95 lines not on this page · raw message
t/t3200-branch.sh +4 -0
@@ -783,10 +783,14 @@ test_expect_success 'test tracking setup via --track but deeper' ' test_expect_success 'test deleting branch deletes branch config' ' git config format.my7.coverSubject "cover subject" && + git config format.my7.to "To Me <[email protected]>" && + git config format.my7.cc "Cc Me <[email protected]>" && git branch -d my7 && test -z "$(git config branch.my7.remote)" && test -z "$(git config branch.my7.merge)" && test -z "$(git config format.my7.coverSubject)" + test -z "$(git config format.my7.to)" && + test -z "$(git config format.my7.cc)" ' test_expect_success 'test deleting branch without config' '
t/t4014-format-patch.sh +88 -20
157 lines not on this page · raw message
Signature · 1 line
2.21.0.1049.geb646f7864
Quoted 6 lines · Denton Liu
Documentation/config/format.txt +0
-0@@ -28,14 +28,22 @@ format.headers::
Documentation/config/format.txt format.headers:: · line 36
Quoted 10 lines
Documentation/config/format.txt +5
-2format.to:: format.cc:: +format.<branch-name>.to:: +format.<branch-name>.cc:: Additional recipients to include in a patch to be submitted - by mail. See the --to and --cc options in - linkgit:git-format-patch[1]. + by mail. For the <branch-name> options, the recipients are only + included if patches are generated for the given <branch-name>. + See the --to and --cc options in linkgit:git-format-patch[1].
An obvious question that somebody else may raise is:
What makes the branch name that special? What guarantees that it would stay to be the *only* thing that affects the choice of these variables?
An obvious answer to that is "nothing---we are painting ourselves in a corner we cannot easily get out of with this design".
If we want to drive format-patch differently depending on the combination of the worktree location *and* the branch the patches are generated from, we can do something like:
[includeif "gitdir:/path/to/worktree/1"] path = one.inc [includeif "gitdir:/path/to/worktree/2"] path = two.inc
and then have one.inc/two.inc have customized definition of these format.<branch>.{to,cc,...} variables.
But at that point, Ævar's "wouldn't this fit better with includeif" suggestion becomes more and more appropriate. Once we invent the way to combine the conditions for includeIf, it would benefit not just this set of variables but all others that will follow in the future.
Having said that, as long as we are fine with the plan to deprecate and remove these three-level variables this patch introdues in the future, I think it is OK to have them as a temporary stop-gap measure.
Documentation/config/format.txt format.headers:: · line 45
Quoted 4 lines
Documentation/config/format.txt +4
-0+format.<branch-name>.coverSubject:: + When format-patch generates a cover letter for the given + <branch-name>, use the specified subject for the cover letter + instead of the generic template.
I still think it is a mistake that this has to be given separately and possibly redundantly from the branch description.
Documentation/config/format.txt format.headers:: · line 45
Quoted 5 lines
Documentation/config/format.txt +5
-0+static const char *branch_specific_config[] = { + "branch", + "format", + NULL +};
Yuck. This will break a workflow where a fixed branch with a known configuration is deleted and recreated over and over again (e.g. think of "for-linus" branches used for request-pull in each merge window).
Documentation/config/format.txt format.headers::
Quoted 13 lines
Documentation/config/format.txt +7
-3static void delete_branch_config(const char *branchname) { struct strbuf buf = STRBUF_INIT; - strbuf_addf(&buf, "branch.%s", branchname); - if (git_config_rename_section(buf.buf, NULL) < 0) - warning(_("Update of config-file failed")); + int i; + for (i = 0; branch_specific_config[i]; i++) { + strbuf_addf(&buf, "%s.%s", branch_specific_config[i], branchname); + if (git_config_rename_section(buf.buf, NULL) < 0) + warning(_("Update of config-file failed")); + strbuf_reset(&buf); + }
This will hardcode the unwarranted limitation that the second level of the format.*.var hierarchy MUST be branch names and nothing else, won't it?
Hi Junio,
Quoted 35 lines · Junio C Hamano
Quoted 6 lines · Denton Liu
Documentation/config/format.txt +0
-0@@ -28,14 +28,22 @@ format.headers::Documentation/config/format.txt format.headers:: · line 36
Quoted 10 lines
Documentation/config/format.txt +5
-2format.to:: format.cc:: +format.<branch-name>.to:: +format.<branch-name>.cc:: Additional recipients to include in a patch to be submitted - by mail. See the --to and --cc options in - linkgit:git-format-patch[1]. + by mail. For the <branch-name> options, the recipients are only + included if patches are generated for the given <branch-name>. + See the --to and --cc options in linkgit:git-format-patch[1].An obvious question that somebody else may raise is:
What makes the branch name that special? What guarantees that it would stay to be the *only* thing that affects the choice of these variables?
An obvious answer to that is "nothing---we are painting ourselves in a corner we cannot easily get out of with this design".
If we want to drive format-patch differently depending on the combination of the worktree location *and* the branch the patches are generated from, we can do something like:
[includeif "gitdir:/path/to/worktree/1"] path = one.inc [includeif "gitdir:/path/to/worktree/2"] path = two.inc
Quoted 8 lines
and then have one.inc/two.inc have customized definition of these format.<branch>.{to,cc,...} variables.
But at that point, Ævar's "wouldn't this fit better with includeif" suggestion becomes more and more appropriate. Once we invent the way to combine the conditions for includeIf, it would benefit not just this set of variables but all others that will follow in the future.
Hmm, I'm starting to like Ævar's idea more the more I think about it.
Quoted 6 lines
Having said that, as long as we are fine with the plan to deprecate and remove these three-level variables this patch introdues in the future, I think it is OK to have them as a temporary stop-gap measure.
Quoted 7 lines
Documentation/config/format.txt format.headers:: · line 45
Quoted 4 lines
Documentation/config/format.txt +4
-0+format.<branch-name>.coverSubject:: + When format-patch generates a cover letter for the given + <branch-name>, use the specified subject for the cover letter + instead of the generic template.I still think it is a mistake that this has to be given separately and possibly redundantly from the branch description.
I forgot about incorporating this. Since we don't need a branch-specific coverSubject anymore, we can push everything into a includeif since now format.<name>.coverSubject doesn't really need to exist.
I'm going to repurpose --cover-subject format.coverSubject to be a boolean option which'll mean "process the description and if you can extract a subject out of it, put it on the cover letter". This way, we can maintain backwards compatability in case users have some specific use-case.
Unless you'd like this processing to be the default behaviour? I'm impartial either way.
Quoted 11 lines
Documentation/config/format.txt format.headers:: · line 45
Quoted 6 lines
Documentation/config/format.txt +5
-0+static const char *branch_specific_config[] = { + "branch", + "format", + NULL +};Yuck. This will break a workflow where a fixed branch with a known configuration is deleted and recreated over and over again (e.g. think of "for-linus" branches used for request-pull in each merge window).
I suppose when we implement onBranch, you'd prefer git branch -d to also not discard those sections.
Quoted 10 lines
Quoted 10 lines
Documentation/config/format.txt +3
-3static void delete_branch_config(const char *branchname) { struct strbuf buf = STRBUF_INIT; - strbuf_addf(&buf, "branch.%s", branchname); - if (git_config_rename_section(buf.buf, NULL) < 0) - warning(_("Update of config-file failed")); + int i; + for (i = 0; branch_specific_config[i]; i++) { + strbuf_addf(&buf, "%s.%s", branch_specific_config[i], branchname);
Quoted 9 lines
Documentation/config/format.txt
Quoted 4 lines
Documentation/config/format.txt +4
-0+ if (git_config_rename_section(buf.buf, NULL) < 0) + warning(_("Update of config-file failed")); + strbuf_reset(&buf); + }This will hardcode the unwarranted limitation that the second level of the format.*.var hierarchy MUST be branch names and nothing else, won't it?
I was expecting it to only be branch names but now let's take a different approach.
Consider patches 3-6 dropped. I'd like to queue 1-2, though, since they're just cleanup patches.
Also, expect a onBranch patchset some time in the future (not the near future, school is busy).
Thanks for your feedback, Junio.
Hi Junio,
I just realised that my use-cases wouldn't be fully covered with the onBranch configuration option.
Quoted 41 lines · Denton Liu
Hi Junio,
Quoted 38 lines · Junio C Hamano
Quoted 6 lines · Denton Liu
Documentation/config/format.txt +0
-0@@ -28,14 +28,22 @@ format.headers::Documentation/config/format.txt format.headers:: · line 36
Quoted 10 lines
Documentation/config/format.txt +5
-2format.to:: format.cc:: +format.<branch-name>.to:: +format.<branch-name>.cc:: Additional recipients to include in a patch to be submitted - by mail. See the --to and --cc options in - linkgit:git-format-patch[1]. + by mail. For the <branch-name> options, the recipients are only + included if patches are generated for the given <branch-name>. + See the --to and --cc options in linkgit:git-format-patch[1].An obvious question that somebody else may raise is:
What makes the branch name that special? What guarantees that it would stay to be the *only* thing that affects the choice of these variables?
An obvious answer to that is "nothing---we are painting ourselves in a corner we cannot easily get out of with this design".
If we want to drive format-patch differently depending on the combination of the worktree location *and* the branch the patches are generated from, we can do something like:
[includeif "gitdir:/path/to/worktree/1"] path = one.inc [includeif "gitdir:/path/to/worktree/2"] path = two.inc
and then have one.inc/two.inc have customized definition of these format.<branch>.{to,cc,...} variables.
Quoted 8 lines
Quoted 5 lines
But at that point, Ævar's "wouldn't this fit better with includeif" suggestion becomes more and more appropriate. Once we invent the way to combine the conditions for includeIf, it would benefit not just this set of variables but all others that will follow in the future.
Hmm, I'm starting to like Ævar's idea more the more I think about it.
There is one limitation with onBranch. Suppose someone runs
$ git checkout other $ git format-patch master..feature
Then, with onBranch, they'd use get the To and Cc of other. But with format.feature.*, format-patch correctly handles this and will use feature's To and Cc.
Quoted 5 lines
Quoted 5 lines
Having said that, as long as we are fine with the plan to deprecate and remove these three-level variables this patch introdues in the future, I think it is OK to have them as a temporary stop-gap measure.
With this new discovery, I'm not sure it'd be possible to deprecate it without losing a use-case.
Quoted 57 lines
Quoted 8 lines
Documentation/config/format.txt format.headers:: · line 45
Quoted 5 lines
Documentation/config/format.txt +4
-0+format.<branch-name>.coverSubject:: + When format-patch generates a cover letter for the given + <branch-name>, use the specified subject for the cover letter + instead of the generic template.I still think it is a mistake that this has to be given separately and possibly redundantly from the branch description.
I forgot about incorporating this. Since we don't need a branch-specific coverSubject anymore, we can push everything into a includeif since now format.<name>.coverSubject doesn't really need to exist.
I'm going to repurpose --cover-subject format.coverSubject to be a boolean option which'll mean "process the description and if you can extract a subject out of it, put it on the cover letter". This way, we can maintain backwards compatability in case users have some specific use-case.
Unless you'd like this processing to be the default behaviour? I'm impartial either way.
Quoted 11 lines
Documentation/config/format.txt format.headers:: · line 45
Quoted 6 lines
Documentation/config/format.txt +5
-0+static const char *branch_specific_config[] = { + "branch", + "format", + NULL +};Yuck. This will break a workflow where a fixed branch with a known configuration is deleted and recreated over and over again (e.g. think of "for-linus" branches used for request-pull in each merge window).
I suppose when we implement
onBranch, you'd prefergit branch -dto also not discard those sections.Quoted 10 lines
Quoted 10 lines
Documentation/config/format.txt +3
-3static void delete_branch_config(const char *branchname) { struct strbuf buf = STRBUF_INIT; - strbuf_addf(&buf, "branch.%s", branchname); - if (git_config_rename_section(buf.buf, NULL) < 0) - warning(_("Update of config-file failed")); + int i; + for (i = 0; branch_specific_config[i]; i++) { + strbuf_addf(&buf, "%s.%s", branch_specific_config[i], branchname);Quoted 9 lines
Documentation/config/format.txt
Quoted 4 lines
Documentation/config/format.txt +4
-0+ if (git_config_rename_section(buf.buf, NULL) < 0) + warning(_("Update of config-file failed")); + strbuf_reset(&buf); + }This will hardcode the unwarranted limitation that the second level of the format.*.var hierarchy MUST be branch names and nothing else, won't it?
Quoted 5 lines
I was expecting it to only be branch names but now let's take a different approach.
Consider patches 3-6 dropped. I'd like to queue 1-2, though, since they're just cleanup patches.
In light of this, I don't plan on dropping 3-6 anymore. I'm going to reroll the new behaviour of coverSubject.
Quoted 5 lines
Also, expect a onBranch patchset some time in the future (not the near future, school is busy).
Thanks for your feedback, Junio.
v3 cover teach branch-specific options for format-patch
In reply to Denton LiuHi Junio,
I've gotten rid of all the format.*.coverSubject stuff and replaced it with a generic format.inferCoverSubject that will read the subject from the branch description. I've also made git branch -d stop deleting the format.<branch>.* variables.
A new addition in this patchset is that format-patch is now taught to understand the format.<branch-name>.outputDirectory configuration.
Changes since v2:
* Replaced format.<branch-name>.coverSubject and --cover-subject with format.inferCoverSubject and --infer-cover-subject which reads the subject from the branch description
* Do not let git branch -d delete format.<branch-name>.* configs
* More documentation cleanup
* Taught format-patch to read format.<branch-name>.outputDirectory as well
Changes since v1:
* Used format.<branch-name>.* variables instead of branch.<branch-name>.*
Denton Liu (8):
t4014: clean up style
Doc: add more detail for git-format-patch
format-patch: infer cover letter from branch description
format-patch: move extra_headers logic later
string-list: create string_list_append_all
format-patch: read branch-specific To: and Cc: headers
format-patch: move output_directory logic later
format-patch: read branch-specific output directory
Documentation/config/format.txt | 17 +- Documentation/git-format-patch.txt | 44 +- builtin/log.c | 237 ++++++--- string-list.c | 9 + string-list.h | 7 + t/t4014-format-patch.sh | 739 +++++++++++++++++------------ 6 files changed, 667 insertions(+), 386 deletions(-)
Range-diff against v2:
1: 92d7be10aa = 1: 82c0dc9cc8 t4014: clean up style 2: 930a021b7f ! 2: a8cc599fd2 Doc: add more detail for git-format-patch
@@ -9,7 +9,10 @@
In addition, document the special value of --base=auto.
- Finally, while we're at it, surround option arguments with <>.
+ Next, while we're at it, surround option arguments with <>.
+
+ Finally, document the format.outputDirectory config and change
+ format.coverletter to use camelcase.
@@ -67,3 +70,25 @@
--root::
Treat the revision argument as a <revision range>, even if it
+@@
+ -------------
+ You can specify extra mail header lines to be added to each message,
+ defaults for the subject prefix and file suffix, number patches when +-outputting more than one patch, add "To" or "Cc:" headers, configure +-attachments, and sign off patches with configuration variables. ++outputting more than one patch, add "To:" or "Cc:" headers, configure ++attachments, change the patch output directory, and sign off patches ++with configuration variables.
+
+ ------------
+ [format]
+@@
+ cc = <email>
+ attach [ = mime-boundary-string ]
+ signOff = true
+- coverletter = auto
++ outputDirectory = <directory>
++ coverLetter = auto
+ ------------
+
+
3: 075e2c0721 < -: ---------- format-patch: make cover letter subject configurable -: ---------- > 3: e3b8c96b1c format-patch: infer cover letter from branch description 4: 323179377e ! 4: 52ee126825 format-patch: move extra_headers logic later
@@ -7,10 +7,10 @@
logic later in the function so that this happens. (This patch is best viewed with git diff --color-moved.)
- Note that this logic only depends on the git_config and
+ Note that this logic only depends on git_config and
repo_init_revisions and is depended on by the patch creation logic
- which is directly below it so this move is effectively a no-op as
- no dependencies being reordered.
+ which is directly below it so this move is effectively a no-op as no
+ dependencies being reordered.
5: 7a8fa4f5f6 = 5: 27c60c715c string-list: create string_list_append_all 6: 9d7338f067 ! 6: f2a1546b2d format-patch: read branch-specific To: and Cc: headers
@@ -59,29 +59,20 @@
far (from config or command line).
@@
- -------------
- You can specify extra mail header lines to be added to each message,
- defaults for the subject prefix and file suffix, number patches when --outputting more than one patch, add "To" or "Cc:" headers, configure -+outputting more than one patch, add "To:" or "Cc:" headers, configure
- attachments, and sign off patches with configuration variables. -
- ------------
-@@
+ inferCoverSubject = true
------------
- In addition, for a specific branch, you can specify a custom cover --letter subject.
++In addition, for a specific branch, you can specify a custom cover
+letter subject, and add additional "To:" or "Cc:" headers.
-
- ------------
- [format "branch-name"]
- coverSubject = "subject for branch-name only"
++
++------------
++[format "branch-name"]
+ to = <email>
+ cc = <email>
- ------------
++------------
DISCUSSION
+ ----------
diff --git a/builtin/log.c b/builtin/log.c
--- a/builtin/log.c
@@ -96,7 +87,7 @@
static void add_header(const char *value)
{
@@
- return 0;
+ fprintf(rev->diffopt.file, "\n");
}
+static void add_branch_headers(struct rev_info *rev, const char *branch_name)
@@ -186,25 +177,6 @@
strbuf_addstr(&buf, extra_hdr.items[i].string); strbuf_addch(&buf, '\n');
- diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
- --- a/t/t3200-branch.sh
- +++ b/t/t3200-branch.sh
-@@
-
- test_expect_success 'test deleting branch deletes branch config' '
- git config format.my7.coverSubject "cover subject" &&
-+ git config format.my7.to "To Me <[email protected]>" &&
-+ git config format.my7.cc "Cc Me <[email protected]>" &&
- git branch -d my7 &&
- test -z "$(git config branch.my7.remote)" &&
- test -z "$(git config branch.my7.merge)" &&
- test -z "$(git config format.my7.coverSubject)"
-+ test -z "$(git config format.my7.to)" &&
-+ test -z "$(git config format.my7.cc)"
- '
-
- test_expect_success 'test deleting branch without config' ' -
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh --- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
-: ---------- > 7: 70e28c5472 format-patch: move output_directory logic later -: ---------- > 8: b23c3c16f7 format-patch: read branch-specific output directory
Signature · 1 line
2.22.0.rc1.169.g49223abbf8
PATCH v3 1/8 t4014: clean up style
In Git's tests, there is typically no space between the redirection operator and the filename. Remove these spaces.
Since output is silenced when running without -v and debugging output is useful with -v, remove redirections to /dev/null.
Change here-docs from <<\EOF to <<-\EOF so that they can be indented along with the rest of the test case.
Finally, refactor to remove Git commands upstream of pipe. This way, if an invocation of a Git command fails, the return code won't be lost. Keep upstream non-Git commands since we have to assume a base level of sanity.
--- t/t4014-format-patch.sh | 614 +++++++++++++++++++++------------------- 1 file changed, 319 insertions(+), 295 deletions(-)
t/t4014-format-patch.sh +319 -295
@@ -34,7 +34,8 @@ test_expect_success setup ' git commit -m "Side changes #3 with \\n backslash-n in it." && git checkout master && - git diff-tree -p C2 | git apply --index && + git diff-tree -p C2 >patch && + git apply --index <patch && test_tick && git commit -m "Master accepts moral equivalent of #2"
@@ -77,7 +78,7 @@ test_expect_success "format-patch doesn't consider merge commits" ' git checkout -b merger master && test_tick && git merge --no-ff slave && - cnt=$(git format-patch -3 --stdout | grep "^From " | wc -l) && + cnt=$(git format-patch -3 --stdout >patch && grep "^From " patch | wc -l) && test $cnt = 3 '
@@ -85,21 +86,22 @@ test_expect_success "format-patch result applies" ' git checkout -b rebuild-0 master && git am -3 patch0 && - cnt=$(git rev-list master.. | wc -l) && - test $cnt = 2 + git rev-list master.. >list && + test_line_count = 2 list ' test_expect_success "format-patch --ignore-if-in-upstream result applies" ' git checkout -b rebuild-1 master && git am -3 patch1 && - cnt=$(git rev-list master.. | wc -l) && - test $cnt = 2 + git rev-list master.. >list && + test_line_count = 2 list ' test_expect_success 'commit did not screw up the log message' ' - git cat-file commit side | grep "^Side .* with .* backslash-n" + git cat-file commit side >actual && + grep "^Side .* with .* backslash-n" actual '
@@ -112,7 +114,8 @@ test_expect_success 'format-patch did not screw up the log message' ' test_expect_success 'replay did not screw up the log message' ' - git cat-file commit rebuild-1 | grep "^Side .* with .* backslash-n" + git cat-file commit rebuild-1 >actual && + grep "^Side .* with .* backslash-n" actual '
@@ -122,8 +125,8 @@ test_expect_success 'extra headers' ' " && git config --add format.headers "Cc: S E Cipient <[email protected]> " && - git format-patch --stdout master..side > patch2 && - sed -e "/^\$/q" patch2 > hdrs2 && + git format-patch --stdout master..side >patch2 && + sed -e "/^\$/q" patch2 >hdrs2 && grep "^To: R E Cipient <[email protected]>\$" hdrs2 && grep "^Cc: S E Cipient <[email protected]>\$" hdrs2
@@ -134,7 +137,7 @@ test_expect_success 'extra headers without newlines' ' git config --replace-all format.headers "To: R E Cipient <[email protected]>" && git config --add format.headers "Cc: S E Cipient <[email protected]>" && git format-patch --stdout master..side >patch3 && - sed -e "/^\$/q" patch3 > hdrs3 && + sed -e "/^\$/q" patch3 >hdrs3 && grep "^To: R E Cipient <[email protected]>\$" hdrs3 && grep "^Cc: S E Cipient <[email protected]>\$" hdrs3
@@ -144,8 +147,8 @@ test_expect_success 'extra headers with multiple To:s' ' git config --replace-all format.headers "To: R E Cipient <[email protected]>" && git config --add format.headers "To: S E Cipient <[email protected]>" && - git format-patch --stdout master..side > patch4 && - sed -e "/^\$/q" patch4 > hdrs4 && + git format-patch --stdout master..side >patch4 && + sed -e "/^\$/q" patch4 >hdrs4 && grep "^To: R E Cipient <[email protected]>,\$" hdrs4 && grep "^ *S E Cipient <[email protected]>\$" hdrs4 '
@@ -153,72 +156,82 @@ test_expect_success 'extra headers with multiple To:s' ' test_expect_success 'additional command line cc (ascii)' ' git config --replace-all format.headers "Cc: R E Cipient <[email protected]>" && - git format-patch --cc="S E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch5 && - grep "^Cc: R E Cipient <[email protected]>,\$" patch5 && - grep "^ *S E Cipient <[email protected]>\$" patch5 + git format-patch --cc="S E Cipient <[email protected]>" --stdout master..side >patch5 && + sed -e "/^\$/q" patch5 >hdrs5 && + grep "^Cc: R E Cipient <[email protected]>,\$" hdrs5 && + grep "^ *S E Cipient <[email protected]>\$" hdrs5 ' test_expect_failure 'additional command line cc (rfc822)' ' git config --replace-all format.headers "Cc: R E Cipient <[email protected]>" && - git format-patch --cc="S. E. Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch5 && - grep "^Cc: R E Cipient <[email protected]>,\$" patch5 && - grep "^ *\"S. E. Cipient\" <[email protected]>\$" patch5 + git format-patch --cc="S. E. Cipient <[email protected]>" --stdout master..side >patch5 && + sed -e "/^\$/q" patch5 >hdrs5 && + grep "^Cc: R E Cipient <[email protected]>,\$" hdrs5 && + grep "^ *\"S. E. Cipient\" <[email protected]>\$" hdrs5 ' test_expect_success 'command line headers' ' git config --unset-all format.headers && - git format-patch --add-header="Cc: R E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch6 && - grep "^Cc: R E Cipient <[email protected]>\$" patch6 + git format-patch --add-header="Cc: R E Cipient <[email protected]>" --stdout master..side >patch6 && + sed -e "/^\$/q" patch6 >hdrs6 && + grep "^Cc: R E Cipient <[email protected]>\$" hdrs6 ' test_expect_success 'configuration headers and command line headers' ' git config --replace-all format.headers "Cc: R E Cipient <[email protected]>" && - git format-patch --add-header="Cc: S E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch7 && - grep "^Cc: R E Cipient <[email protected]>,\$" patch7 && - grep "^ *S E Cipient <[email protected]>\$" patch7 + git format-patch --add-header="Cc: S E Cipient <[email protected]>" --stdout master..side >patch7 && + sed -e "/^\$/q" patch7 >hdrs7 && + grep "^Cc: R E Cipient <[email protected]>,\$" hdrs7 && + grep "^ *S E Cipient <[email protected]>\$" hdrs7 ' test_expect_success 'command line To: header (ascii)' ' git config --unset-all format.headers && - git format-patch --to="R E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch8 && - grep "^To: R E Cipient <[email protected]>\$" patch8 + git format-patch --to="R E Cipient <[email protected]>" --stdout master..side >patch8 && + sed -e "/^\$/q" patch8 >hdrs8 && + grep "^To: R E Cipient <[email protected]>\$" hdrs8 ' test_expect_failure 'command line To: header (rfc822)' ' - git format-patch --to="R. E. Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch8 && - grep "^To: \"R. E. Cipient\" <[email protected]>\$" patch8 + git format-patch --to="R. E. Cipient <[email protected]>" --stdout master..side >patch8 && + sed -e "/^\$/q" patch8 >hdrs8 && + grep "^To: \"R. E. Cipient\" <[email protected]>\$" hdrs8 ' test_expect_failure 'command line To: header (rfc2047)' ' - git format-patch --to="R Ä Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch8 && - grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" patch8 + git format-patch --to="R Ä Cipient <[email protected]>" --stdout master..side >patch8 && + sed -e "/^\$/q" patch8 >hdrs8 && + grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" hdrs8 ' test_expect_success 'configuration To: header (ascii)' ' git config format.to "R E Cipient <[email protected]>" && - git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && - grep "^To: R E Cipient <[email protected]>\$" patch9 + git format-patch --stdout master..side >patch9 && + sed -e "/^\$/q" patch9 >hdrs9 && + grep "^To: R E Cipient <[email protected]>\$" hdrs9 ' test_expect_failure 'configuration To: header (rfc822)' ' git config format.to "R. E. Cipient <[email protected]>" && - git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && - grep "^To: \"R. E. Cipient\" <[email protected]>\$" patch9 + git format-patch --stdout master..side >patch9 && + sed -e "/^\$/q" patch9 >hdrs9 && + grep "^To: \"R. E. Cipient\" <[email protected]>\$" hdrs9 ' test_expect_failure 'configuration To: header (rfc2047)' ' git config format.to "R Ä Cipient <[email protected]>" && - git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && - grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" patch9 + git format-patch --stdout master..side >patch9 && + sed -e "/^\$/q" patch9 >hdrs9 && + grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" hdrs9 ' # check_patch <patch>: Verify that <patch> looks like a half-sane
@@ -231,52 +244,52 @@ check_patch () { test_expect_success 'format.from=false' ' - git -c format.from=false format-patch --stdout master..side | - sed -e "/^\$/q" >patch && + git -c format.from=false format-patch --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && check_patch patch && - ! grep "^From: C O Mitter <[email protected]>\$" patch + ! grep "^From: C O Mitter <[email protected]>\$" hdrs ' test_expect_success 'format.from=true' ' - git -c format.from=true format-patch --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - grep "^From: C O Mitter <[email protected]>\$" patch + git -c format.from=true format-patch --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + grep "^From: C O Mitter <[email protected]>\$" hdrs ' test_expect_success 'format.from with address' ' - git -c format.from="F R Om <[email protected]>" format-patch --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - grep "^From: F R Om <[email protected]>\$" patch + git -c format.from="F R Om <[email protected]>" format-patch --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + grep "^From: F R Om <[email protected]>\$" hdrs ' test_expect_success '--no-from overrides format.from' ' - git -c format.from="F R Om <[email protected]>" format-patch --no-from --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - ! grep "^From: F R Om <[email protected]>\$" patch + git -c format.from="F R Om <[email protected]>" format-patch --no-from --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + ! grep "^From: F R Om <[email protected]>\$" hdrs ' test_expect_success '--from overrides format.from' ' - git -c format.from="F R Om <[email protected]>" format-patch --from --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - ! grep "^From: F R Om <[email protected]>\$" patch + git -c format.from="F R Om <[email protected]>" format-patch --from --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + ! grep "^From: F R Om <[email protected]>\$" hdrs ' test_expect_success '--no-to overrides config.to' ' git config --replace-all format.to \ "R E Cipient <[email protected]>" && - git format-patch --no-to --stdout master..side | - sed -e "/^\$/q" >patch10 && - check_patch patch10 && - ! grep "^To: R E Cipient <[email protected]>\$" patch10 + git format-patch --no-to --stdout master..side >patch10 && + sed -e "/^\$/q" patch10 >hdrs10 && + check_patch hdrs10 && + ! grep "^To: R E Cipient <[email protected]>\$" hdrs10 ' test_expect_success '--no-to and --to replaces config.to' '
@@ -284,31 +297,31 @@ test_expect_success '--no-to and --to replaces config.to' ' git config --replace-all format.to \ "Someone <[email protected]>" && git format-patch --no-to --to="Someone Else <[email protected]>" \ - --stdout master..side | - sed -e "/^\$/q" >patch11 && - check_patch patch11 && - ! grep "^To: Someone <[email protected]>\$" patch11 && - grep "^To: Someone Else <[email protected]>\$" patch11 + --stdout master..side >patch11 && + sed -e "/^\$/q" patch11 >hdrs11 && + check_patch hdrs11 && + ! grep "^To: Someone <[email protected]>\$" hdrs11 && + grep "^To: Someone Else <[email protected]>\$" hdrs11 ' test_expect_success '--no-cc overrides config.cc' ' git config --replace-all format.cc \ "C E Cipient <[email protected]>" && - git format-patch --no-cc --stdout master..side | - sed -e "/^\$/q" >patch12 && - check_patch patch12 && - ! grep "^Cc: C E Cipient <[email protected]>\$" patch12 + git format-patch --no-cc --stdout master..side >patch12 && + sed -e "/^\$/q" patch12 >hdrs12 && + check_patch hdrs12 && + ! grep "^Cc: C E Cipient <[email protected]>\$" hdrs12 ' test_expect_success '--no-add-header overrides config.headers' ' git config --replace-all format.headers \ "Header1: B E Cipient <[email protected]>" && - git format-patch --no-add-header --stdout master..side | - sed -e "/^\$/q" >patch13 && - check_patch patch13 && - ! grep "^Header1: B E Cipient <[email protected]>\$" patch13 + git format-patch --no-add-header --stdout master..side >patch13 && + sed -e "/^\$/q" patch13 >hdrs13 && + check_patch hdrs13 && + ! grep "^Header1: B E Cipient <[email protected]>\$" hdrs13 ' test_expect_success 'multiple files' '
@@ -338,7 +351,7 @@ test_expect_success 'reroll count (-v)' ' check_threading () { expect="$1" && shift && - (git format-patch --stdout "$@"; echo $? > status.out) | + (git format-patch --stdout "$@"; echo $? >status.out) | # Prints everything between the Message-ID and In-Reply-To, # and replaces all Message-ID-lookalikes by a sequence number perl -ne '
@@ -353,12 +366,12 @@ check_threading () { print; } print "---\n" if /^From /i; - ' > actual && + ' >actual && test 0 = "$(cat status.out)" && test_cmp "$expect" actual } -cat >> expect.no-threading <<EOF +cat >>expect.no-threading <<EOF --- --- ---
@@ -369,7 +382,7 @@ test_expect_success 'no threading' ' check_threading expect.no-threading master ' -cat > expect.thread <<EOF +cat >expect.thread <<EOF --- Message-Id: <0> ---
@@ -386,7 +399,7 @@ test_expect_success 'thread' ' check_threading expect.thread --thread master ' -cat > expect.in-reply-to <<EOF +cat >expect.in-reply-to <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -406,7 +419,7 @@ test_expect_success 'thread in-reply-to' ' --thread master ' -cat > expect.cover-letter <<EOF +cat >expect.cover-letter <<EOF --- Message-Id: <0> ---
@@ -427,7 +440,7 @@ test_expect_success 'thread cover-letter' ' check_threading expect.cover-letter --cover-letter --thread master ' -cat > expect.cl-irt <<EOF +cat >expect.cl-irt <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -459,7 +472,7 @@ test_expect_success 'thread explicit shallow' ' --in-reply-to="<test.message>" --thread=shallow master ' -cat > expect.deep <<EOF +cat >expect.deep <<EOF --- Message-Id: <0> ---
@@ -477,7 +490,7 @@ test_expect_success 'thread deep' ' check_threading expect.deep --thread=deep master ' -cat > expect.deep-irt <<EOF +cat >expect.deep-irt <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -500,7 +513,7 @@ test_expect_success 'thread deep in-reply-to' ' --in-reply-to="<test.message>" master ' -cat > expect.deep-cl <<EOF +cat >expect.deep-cl <<EOF --- Message-Id: <0> ---
@@ -524,7 +537,7 @@ test_expect_success 'thread deep cover-letter' ' check_threading expect.deep-cl --cover-letter --thread=deep master ' -cat > expect.deep-cl-irt <<EOF +cat >expect.deep-cl-irt <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -606,7 +619,7 @@ test_expect_success 'cover-letter inherits diff options' ' ' -cat > expect << EOF +cat >expect <<EOF This is an excessively long subject line for a message due to the habit some projects have of not having a short, one-line subject at the start of the commit message, but rather sticking a whole
@@ -619,12 +632,12 @@ EOF test_expect_success 'shortlog of cover-letter wraps overly-long onelines' ' git format-patch --cover-letter -2 && - sed -e "1,/A U Thor/d" -e "/^\$/q" < 0000-cover-letter.patch > output && + sed -e "1,/A U Thor/d" -e "/^\$/q" <0000-cover-letter.patch >output && test_cmp expect output ' -cat > expect << EOF +cat >expect <<EOF index $before..$after 100644 --- a/file +++ b/file
@@ -646,7 +659,7 @@ test_expect_success 'format-patch respects -U' ' ' -cat > expect << EOF +cat >expect <<EOF diff --git a/file b/file index $before..$after 100644
@@ -662,7 +675,7 @@ EOF test_expect_success 'format-patch -p suppresses stat' ' git format-patch -p -2 && - sed -e "1,/^\$/d" -e "/^+5/q" < 0001-This-is-an-excessively-long-subject-line-for-a-messa.patch > output && + sed -e "1,/^\$/d" -e "/^+5/q" <0001-This-is-an-excessively-long-subject-line-for-a-messa.patch >output && test_cmp expect output '
@@ -717,7 +730,7 @@ test_expect_success 'format-patch from a subdirectory (3)' ' ' test_expect_success 'format-patch --in-reply-to' ' - git format-patch -1 --stdout --in-reply-to "[email protected]" > patch8 && + git format-patch -1 --stdout --in-reply-to "[email protected]" >patch8 && grep "^In-Reply-To: <[email protected]>" patch8 && grep "^References: <[email protected]>" patch8 '
@@ -738,20 +751,20 @@ test_expect_success 'format-patch --notes --signoff' ' sed "1,/^---$/d" out | grep "test message" ' -echo "fatal: --name-only does not make sense" > expect.name-only -echo "fatal: --name-status does not make sense" > expect.name-status -echo "fatal: --check does not make sense" > expect.check +echo "fatal: --name-only does not make sense" >expect.name-only +echo "fatal: --name-status does not make sense" >expect.name-status +echo "fatal: --check does not make sense" >expect.check test_expect_success 'options no longer allowed for format-patch' ' - test_must_fail git format-patch --name-only 2> output && + test_must_fail git format-patch --name-only 2>output && test_i18ncmp expect.name-only output && - test_must_fail git format-patch --name-status 2> output && + test_must_fail git format-patch --name-status 2>output && test_i18ncmp expect.name-status output && - test_must_fail git format-patch --check 2> output && + test_must_fail git format-patch --check 2>output && test_i18ncmp expect.check output' test_expect_success 'format-patch --numstat should produce a patch' ' - git format-patch --numstat --stdout master..side > output && + git format-patch --numstat --stdout master..side >output && test 5 = $(grep "^diff --git a/" output | wc -l)' test_expect_success 'format-patch -- <path>' '
@@ -763,20 +776,22 @@ test_expect_success 'format-patch --ignore-if-in-upstream HEAD' ' git format-patch --ignore-if-in-upstream HEAD ' -git_version="$(git --version | sed "s/.* //")" +git_version="$(git --version >version && sed "s/.* //" version)" signature() { printf "%s\n%s\n\n" "-- " "${1:-$git_version}" } test_expect_success 'format-patch default signature' ' - git format-patch --stdout -1 | tail -n 3 >output && + git format-patch --stdout -1 >patch && + tail -n 3 patch >output && signature >expect && test_cmp expect output ' test_expect_success 'format-patch --signature' ' - git format-patch --stdout --signature="my sig" -1 | tail -n 3 >output && + git format-patch --stdout --signature="my sig" -1 >patch && + tail -n 3 patch >output && signature "my sig" >expect && test_cmp expect output '
@@ -1167,282 +1182,282 @@ append_signoff() test_expect_success 'signoff: commit with no body' ' append_signoff </dev/null >actual && - cat <<\EOF | sed "s/EOL$//" >expected && -4:Subject: [PATCH] EOL -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat <<-\EOF | sed "s/EOL$//" >expected && + 4:Subject: [PATCH] EOL + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: commit with only subject' ' echo subject | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: commit with only subject that does not end with NL' ' printf subject | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: no existing signoffs' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + body + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: no existing signoffs and no trailing NL' ' printf "subject\n\nbody" | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: some random signoff' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: my@house -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: my@house -12:Signed-off-by: C O Mitter <[email protected]> -EOF + Signed-off-by: my@house + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: my@house + 12:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: misc conforming footer elements' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: my@house -(cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709) -Tested-by: Some One <[email protected]> -Bug: 1234 -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: my@house -15:Signed-off-by: C O Mitter <[email protected]> -EOF + Signed-off-by: my@house + (cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709) + Tested-by: Some One <[email protected]> + Bug: 1234 + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: my@house + 15:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: some random signoff-alike' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body -Fooled-by-me: my@house -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -11: -12:Signed-off-by: C O Mitter <[email protected]> -EOF + body + Fooled-by-me: my@house + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 11: + 12:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: not really a signoff' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -I want to mention about Signed-off-by: here. -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:I want to mention about Signed-off-by: here. -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + I want to mention about Signed-off-by: here. + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:I want to mention about Signed-off-by: here. + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: not really a signoff (2)' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -My unfortunate -Signed-off-by: example happens to be wrapped here. -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10:Signed-off-by: example happens to be wrapped here. -11:Signed-off-by: C O Mitter <[email protected]> -EOF + My unfortunate + Signed-off-by: example happens to be wrapped here. + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10:Signed-off-by: example happens to be wrapped here. + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: valid S-o-b paragraph in the middle' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -Signed-off-by: my@house -Signed-off-by: your@house + Signed-off-by: my@house + Signed-off-by: your@house -A lot of houses. -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: my@house -10:Signed-off-by: your@house -11: -13: -14:Signed-off-by: C O Mitter <[email protected]> -EOF + A lot of houses. + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: my@house + 10:Signed-off-by: your@house + 11: + 13: + 14:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: the same signoff at the end' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: C O Mitter <[email protected]> -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + Signed-off-by: C O Mitter <[email protected]> + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: the same signoff at the end, no trailing NL' ' printf "subject\n\nSigned-off-by: C O Mitter <[email protected]>" | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: the same signoff NOT at the end' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: C O Mitter <[email protected]> -Signed-off-by: my@house -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -12:Signed-off-by: my@house -EOF + Signed-off-by: C O Mitter <[email protected]> + Signed-off-by: my@house + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + 12:Signed-off-by: my@house + EOF test_cmp expected actual ' test_expect_success 'signoff: tolerate garbage in conforming footer' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Tested-by: my@house -Some Trash -Signed-off-by: C O Mitter <[email protected]> -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -13:Signed-off-by: C O Mitter <[email protected]> -EOF + Tested-by: my@house + Some Trash + Signed-off-by: C O Mitter <[email protected]> + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 13:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: respect trailer config' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -Myfooter: x -Some Trash -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -11: -12:Signed-off-by: C O Mitter <[email protected]> -EOF + Myfooter: x + Some Trash + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 11: + 12:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual && test_config trailer.Myfooter.ifexists add && - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -Myfooter: x -Some Trash -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + Myfooter: x + Some Trash + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: footer begins with non-signoff without @ sign' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Reviewed-id: Noone -Tested-by: my@house -Change-id: Ideadbeef -Signed-off-by: C O Mitter <[email protected]> -Bug: 1234 -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -14:Signed-off-by: C O Mitter <[email protected]> -EOF + Reviewed-id: Noone + Tested-by: my@house + Change-id: Ideadbeef + Signed-off-by: C O Mitter <[email protected]> + Bug: 1234 + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 14:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual '
@@ -1458,42 +1473,42 @@ test_expect_success 'cover letter using branch description (1)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter master >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (2)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter rebuild-1~2..rebuild-1 >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (3)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter ^master rebuild-1 >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (4)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter master.. >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (5)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter -2 HEAD >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (6)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter -2 >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter with nothing' '
@@ -1547,7 +1562,8 @@ test_expect_success 'format-patch format.outputDirectory option' ' test_config format.outputDirectory patches && rm -fr patches && git format-patch master..side && - test $(git rev-list master..side | wc -l) -eq $(ls patches | wc -l) + git rev-list master..side >list && + test_line_count = $(ls patches | wc -l) list ' test_expect_success 'format-patch -o overrides format.outputDirectory' '
@@ -1560,13 +1576,21 @@ test_expect_success 'format-patch -o overrides format.outputDirectory' ' test_expect_success 'format-patch --base' ' git checkout side && - git format-patch --stdout --base=HEAD~3 -1 | tail -n 7 >actual1 && - git format-patch --stdout --base=HEAD~3 HEAD~.. | tail -n 7 >actual2 && + git format-patch --stdout --base=HEAD~3 -1 >patch && + tail -n 7 patch >actual1 && + git format-patch --stdout --base=HEAD~3 HEAD~.. >patch && + tail -n 7 patch >actual2 && echo >expected && echo "base-commit: $(git rev-parse HEAD~3)" >>expected && - echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --stable | awk "{print \$1}")" >>expected && - echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --stable | awk "{print \$1}")" >>expected && - signature >> expected && + git show --patch HEAD~2 >patch && + git patch-id --stable <patch >patch.id.raw && + awk "{print \$1}" <patch.id.raw >patch.id && + echo "prerequisite-patch-id: $(cat patch.id)" >>expected && + git show --patch HEAD~1 >patch && + git patch-id --stable <patch >patch.id.raw && + awk "{print \$1}" <patch.id.raw >patch.id && + echo "prerequisite-patch-id: $(cat patch.id)" >>expected && + signature >>expected && test_cmp expected actual1 && test_cmp expected actual2 '
Signature · 1 line
2.22.0.rc1.169.g49223abbf8
PATCH v3 2/8 Doc: add more detail for git-format-patch
In reply to Denton LiuIn git-format-patch.txt, we were missing some key user information. First of all, using the --to and --cc options don't override format.to and format.cc variables, respectively. They add on to each other. Document this.
In addition, document the special value of --base=auto.
Next, while we're at it, surround option arguments with <>.
Finally, document the format.outputDirectory config and change format.coverletter to use camelcase.
--- Documentation/git-format-patch.txt | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-)
Documentation/git-format-patch.txt +16 -9
@@ -17,9 +17,9 @@ SYNOPSIS [--signature-file=<file>] [-n | --numbered | -N | --no-numbered] [--start-number <n>] [--numbered-files] - [--in-reply-to=Message-Id] [--suffix=.<sfx>] + [--in-reply-to=<Message-Id>] [--suffix=.<sfx>] [--ignore-if-in-upstream] - [--rfc] [--subject-prefix=Subject-Prefix] + [--rfc] [--subject-prefix=<Subject-Prefix>] [(--reroll-count|-v) <n>] [--to=<email>] [--cc=<email>] [--[no-]cover-letter] [--quiet] [--notes[=<ref>]]
@@ -158,7 +158,7 @@ Beware that the default for 'git send-email' is to thread emails itself. If you want `git format-patch` to take care of threading, you will want to ensure that threading is disabled for `git send-email`. ---in-reply-to=Message-Id:: +--in-reply-to=<Message-Id>:: Make the first mail (or all the mails with `--no-thread`) appear as a reply to the given Message-Id, which avoids breaking threads to provide a new patch series.
@@ -192,13 +192,17 @@ will want to ensure that threading is disabled for `git send-email`. --to=<email>:: Add a `To:` header to the email headers. This is in addition - to any configured headers, and may be used multiple times. + to any configured headers, and may be used multiple times. The + emails given will be used along with any emails given by + `format.to` configurations. The negated form `--no-to` discards all `To:` headers added so far (from config or command line). --cc=<email>:: Add a `Cc:` header to the email headers. This is in addition - to any configured headers, and may be used multiple times. + to any configured headers, and may be used multiple times. The + emails given will be used along with any emails given by + `format.cc` configurations. The negated form `--no-cc` discards all `Cc:` headers added so far (from config or command line).
@@ -309,7 +313,8 @@ you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`. --base=<commit>:: Record the base tree information to identify the state the patch series applies to. See the BASE TREE INFORMATION section - below for details. + below for details. If <commit> is equal to "auto", a base commit + is automatically chosen. --root:: Treat the revision argument as a <revision range>, even if it
@@ -325,8 +330,9 @@ CONFIGURATION ------------- You can specify extra mail header lines to be added to each message, defaults for the subject prefix and file suffix, number patches when -outputting more than one patch, add "To" or "Cc:" headers, configure -attachments, and sign off patches with configuration variables. +outputting more than one patch, add "To:" or "Cc:" headers, configure +attachments, change the patch output directory, and sign off patches +with configuration variables. ------------ [format]
@@ -338,7 +344,8 @@ attachments, and sign off patches with configuration variables. cc = <email> attach [ = mime-boundary-string ] signOff = true - coverletter = auto + outputDirectory = <directory> + coverLetter = auto ------------
Signature · 1 line
2.22.0.rc1.169.g49223abbf8
PATCH v3 3/8 format-patch: infer cover letter from branch description
In reply to Denton LiuWe used to populate the subject of the cover letter generated by git-format-patch with "*** SUBJECT HERE ***". However, if a user submits multiple patchsets, they may want to keep a consistent subject between rerolls.
If git-format-patch is run with --infer-cover-letter or format.inferCoverSubject, infer the subject for the cover letter from the top line(s) of a branch description, similar to how a subject is read from a commit message.
--- Documentation/config/format.txt | 5 +++ Documentation/git-format-patch.txt | 10 ++++++ builtin/log.c | 58 ++++++++++++++++++------------ t/t4014-format-patch.sh | 33 +++++++++++++++++ 4 files changed, 84 insertions(+), 22 deletions(-)
Documentation/config/format.txt +5 -0
@@ -36,6 +36,11 @@ format.subjectPrefix:: The default for format-patch is to output files with the '[PATCH]' subject prefix. Use this variable to change that prefix. +format.<branch-name>.inferCoverSubject:: + A boolean that controls whether or not to infer the subject for + the cover letter based on the branch's description. See the + --infer-cover-subject option in linkgit:git-format-patch[1]. + format.signature:: The default for format-patch is to output a signature containing the Git version number. Use this variable to change that default.
Documentation/git-format-patch.txt +10 -0
@@ -19,6 +19,7 @@ SYNOPSIS [--start-number <n>] [--numbered-files] [--in-reply-to=<Message-Id>] [--suffix=.<sfx>] [--ignore-if-in-upstream] + [--[no-]infer-cover-subject] [--rfc] [--subject-prefix=<Subject-Prefix>] [(--reroll-count|-v) <n>] [--to=<email>] [--cc=<email>]
@@ -170,6 +171,14 @@ will want to ensure that threading is disabled for `git send-email`. patches being generated, and any patch that matches is ignored. +--[no-]infer-cover-subject:: + Instead of using the default "*** SUBJECT HERE ***" subject for + the cover letter, infer the subject from the branch's + description. ++ +Similar to a commit message, the subject is inferred as the beginning of +the description up to and excluding the first blank line. + --subject-prefix=<Subject-Prefix>:: Instead of the standard '[PATCH]' prefix in the subject line, instead use '[<Subject-Prefix>]'. This
@@ -346,6 +355,7 @@ with configuration variables. signOff = true outputDirectory = <directory> coverLetter = auto + inferCoverSubject = true ------------
builtin/log.c +36 -22
119 lines not on this page · raw message
t/t4014-format-patch.sh +33 -0
@@ -1469,6 +1469,39 @@ test_expect_success 'format patch ignores color.ui' ' test_cmp expect actual ' +test_expect_success 'cover letter with config subject' ' + test_config branch.rebuild-1.description "config subject + +body" && + test_config format.inferCoverSubject true && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter master >actual && + grep "^Subject: \[PATCH 0/2\] config subject$" actual && + grep "^body" actual +' + +test_expect_success 'cover letter with command-line subject' ' + test_config branch.rebuild-1.description "command-line subject + +body" && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --infer-cover-subject master >actual && + grep "^Subject: \[PATCH 0/2\] command-line subject$" actual && + grep "^body" actual +' + +test_expect_success 'cover letter with command-line --no-infer-cover-subject overrides config' ' + test_config branch.rebuild-1.description "config subject + +body" && + test_config format.inferCoverSubject true && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --no-infer-cover-subject master >actual && + grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual && + grep "^config subject" actual && + grep "^body" actual +' + test_expect_success 'cover letter using branch description (1)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello &&
Signature · 1 line
2.22.0.rc1.169.g49223abbf8
PATCH v3 4/8 format-patch: move extra_headers logic later
In reply to Denton LiuIn a future patch, we need to perform the addition of To: and Cc:
to extra_headers after the branch_name logic. Simply transpose this logic later in the function so that this happens. (This patch is best viewed with git diff --color-moved.)
Note that this logic only depends on git_config and repo_init_revisions and is depended on by the patch creation logic which is directly below it so this move is effectively a no-op as no dependencies being reordered.
--- builtin/log.c | 58 +++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 29 deletions(-)
builtin/log.c +29 -29
@@ -1667,35 +1667,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) rev.subject_prefix =strbuf_detach (&sprefix,NULL ); } -for (i =0 ; i < extra_hdr.nr; i++) { -strbuf_addstr (&buf, extra_hdr.items[i].string); -strbuf_addch (&buf,'\n' ); - } - -if (extra_to.nr) -strbuf_addstr (&buf,"To: " ); -for (i =0 ; i < extra_to.nr; i++) { -if (i) -strbuf_addstr (&buf," " ); -strbuf_addstr (&buf, extra_to.items[i].string); -if (i +1 < extra_to.nr) -strbuf_addch (&buf,',' ); -strbuf_addch (&buf,'\n' ); - } - -if (extra_cc.nr) -strbuf_addstr (&buf,"Cc: " ); -for (i =0 ; i < extra_cc.nr; i++) { -if (i) -strbuf_addstr (&buf," " ); -strbuf_addstr (&buf, extra_cc.items[i].string); -if (i +1 < extra_cc.nr) -strbuf_addch (&buf,',' ); -strbuf_addch (&buf,'\n' ); - } - - rev.extra_headers =strbuf_detach (&buf,NULL ); -if (from) {if (split_ident_line (&rev.from_ident, from,strlen (from)))die (_ ("invalid ident line: %s" ), from);
@@ -1798,6 +1769,35 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } } +for (i =0 ; i < extra_hdr.nr; i++) { +strbuf_addstr (&buf, extra_hdr.items[i].string); +strbuf_addch (&buf,'\n' ); + } + +if (extra_to.nr) +strbuf_addstr (&buf,"To: " ); +for (i =0 ; i < extra_to.nr; i++) { +if (i) +strbuf_addstr (&buf," " ); +strbuf_addstr (&buf, extra_to.items[i].string); +if (i +1 < extra_to.nr) +strbuf_addch (&buf,',' ); +strbuf_addch (&buf,'\n' ); + } + +if (extra_cc.nr) +strbuf_addstr (&buf,"Cc: " ); +for (i =0 ; i < extra_cc.nr; i++) { +if (i) +strbuf_addstr (&buf," " ); +strbuf_addstr (&buf, extra_cc.items[i].string); +if (i +1 < extra_cc.nr) +strbuf_addch (&buf,',' ); +strbuf_addch (&buf,'\n' ); + } + + rev.extra_headers =strbuf_detach (&buf,NULL ); +/* * We cannot move this anywhere earlier because we do want to * know if --root was given explicitly from the command line.
Signature · 1 line
2.22.0.rc1.169.g49223abbf8
PATCH v3 5/8 string-list: create string_list_append_all
In reply to Denton LiuIn a future patch, we'll need to take one string_list and append it to the end of another. Create the string_list_append_all function which does this.
--- string-list.c | 9 +++++++++ string-list.h | 7 +++++++ 2 files changed, 16 insertions(+)
string-list.c +9 -0
@@ -215,6 +215,15 @@ struct string_list_item *string_list_append(struct string_list *list, list->strdup_strings ? xstrdup(string) : (char *)string); } +void string_list_append_all (struct string_list *list, +const struct string_list *append_list) +{ +struct string_list_item *item; +ALLOC_GROW (list->items, list->nr + append_list->nr, list->alloc); +for_each_string_list_item (item, append_list) +string_list_append (list, item->string); +} +/* * Encapsulate the compare function pointer because ISO C99 forbids * casting from void * to a function pointer and vice versa.
string-list.h +7 -0
@@ -208,6 +208,13 @@ struct string_list_item *string_list_append(struct string_list *list, const char*/ struct string_list_item *string_list_append_nodup (struct string_list *list,char *string); +/** +* Add all strings in append_list to list. If list->strdup_string is +* set, then each string is copied; otherwise the new string_list_entry +* refers to the entry in the append_list. +*/ +void string_list_append_all (struct string_list *list,const struct string_list *append_list); +/** * Sort the list's entries by string value in `strcmp()` order. */
Signature · 1 line
2.22.0.rc1.169.g49223abbf8
PATCH v3 6/8 format-patch: read branch-specific To: and Cc: headers
In reply to Denton LiuIf a user wishes to keep track of whom to Cc: on individual patchsets, they must manually keep track of each recipient and fill it in with the --cc option on git-format-patch each time. However, on the Git mailing list, Cc:'s are typically never dropped. As a result, it would be nice to have a method to keep track of recipients on a per-branch basis.
Currently, git-format-patch gets its To: headers from the --to options and the format.to config variable. The Cc: header is derived similarly.
In addition to the above, read To: and Cc: headers from format.<branch-name>.to and format.<branch-name>.cc so that users can have branch-specific configuration options.
--- Documentation/config/format.txt | 7 +- Documentation/git-format-patch.txt | 12 +++- builtin/log.c | 63 +++++++++++++++-- t/t4014-format-patch.sh | 108 +++++++++++++++++++++++------ 4 files changed, 162 insertions(+), 28 deletions(-)
Documentation/config/format.txt +5 -2
@@ -28,9 +28,12 @@ format.headers:: format.to:: format.cc:: +format.<branch-name>.to:: +format.<branch-name>.cc:: Additional recipients to include in a patch to be submitted - by mail. See the --to and --cc options in - linkgit:git-format-patch[1]. + by mail. For the <branch-name> options, the recipients are only + included if patches are generated for the given <branch-name>. + See the --to and --cc options in linkgit:git-format-patch[1]. format.subjectPrefix:: The default for format-patch is to output files with the '[PATCH]'
Documentation/git-format-patch.txt +10 -2
@@ -203,7 +203,7 @@ the description up to and excluding the first blank line. Add a `To:` header to the email headers. This is in addition to any configured headers, and may be used multiple times. The emails given will be used along with any emails given by - `format.to` configurations. + `format.to` and `format.<branch-name>.to` configurations. The negated form `--no-to` discards all `To:` headers added so far (from config or command line).
@@ -211,7 +211,7 @@ the description up to and excluding the first blank line. Add a `Cc:` header to the email headers. This is in addition to any configured headers, and may be used multiple times. The emails given will be used along with any emails given by - `format.cc` configurations. + `format.cc` and `format.<branch-name>.cc` configurations. The negated form `--no-cc` discards all `Cc:` headers added so far (from config or command line).
@@ -358,6 +358,14 @@ with configuration variables. inferCoverSubject = true ------------ +In addition, for a specific branch, you can specify a custom cover +letter subject, and add additional "To:" or "Cc:" headers. + +------------ +[format "branch-name"] + to = <email> + cc = <email> +------------ DISCUSSION ----------
builtin/log.c +59 -4
95 lines not on this page · raw message
t/t4014-format-patch.sh +88 -20
157 lines not on this page · raw message
Signature · 1 line
2.22.0.rc1.169.g49223abbf8
PATCH v3 7/8 format-patch: move output_directory logic later
In reply to Denton LiuIn a future patch, we need to create the output_directory after the branch_name logic. Simply transpose this logic later in the function so that this happens. (This patch is best viewed with git diff --color-moved.)
Note that this logic only depends on git_config and the parseopt logic and is depended on by the patch creation logic which is directly below it so this move is effectively a no-op as no dependencies being reordered.
--- Documentation/git-format-patch.txt | 4 ++-- builtin/log.c | 36 +++++++++++++++--------------- 2 files changed, 20 insertions(+), 20 deletions(-)
Documentation/git-format-patch.txt +2 -2
@@ -358,8 +358,8 @@ with configuration variables. inferCoverSubject = true ------------ -In addition, for a specific branch, you can specify a custom cover -letter subject, and add additional "To:" or "Cc:" headers. +In addition, for a specific branch, you can add additional "To:" or +"Cc:" headers. ------------ [format "branch-name"]
builtin/log.c +18 -18
@@ -1771,24 +1771,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)if (rev.show_notes)init_display_notes (&rev.notes_opt); -if (!output_directory && !use_stdout) - output_directory = config_output_directory; - -if (!use_stdout) - output_directory =set_outdir (prefix, output_directory); -else -setup_pager (); - -if (output_directory) { -if (rev.diffopt.use_color !=GIT_COLOR_ALWAYS ) - rev.diffopt.use_color =GIT_COLOR_NEVER ; -if (use_stdout) -die (_ ("standard output, or directory, which one?" )); -if (mkdir (output_directory,0777 ) <0 && errno !=EEXIST ) -die_errno (_ ("could not create directory '%s'" ), - output_directory); - } -if (rev.pending.nr ==1 ) {int check_head =0 ;
@@ -1822,6 +1804,24 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } } +if (!output_directory && !use_stdout) + output_directory = config_output_directory; + +if (!use_stdout) + output_directory =set_outdir (prefix, output_directory); +else +setup_pager (); + +if (output_directory) { +if (rev.diffopt.use_color !=GIT_COLOR_ALWAYS ) + rev.diffopt.use_color =GIT_COLOR_NEVER ; +if (use_stdout) +die (_ ("standard output, or directory, which one?" )); +if (mkdir (output_directory,0777 ) <0 && errno !=EEXIST ) +die_errno (_ ("could not create directory '%s'" ), + output_directory); + } +add_branch_headers (&rev, branch_name);for (i =0 ; i < extra_hdr.nr; i++) {
Signature · 1 line
2.22.0.rc1.169.g49223abbf8
PATCH v3 8/8 format-patch: read branch-specific output directory
In reply to Denton LiuIf a user wishes to have a per-branch output directory for patches, they must manually specify this on the command-line with -o for each invocation of format-patch. However, this can be cumbersome for a user to keep track of.
Read format.<branch-name>.outputDirectory to give a branch-specific output directory that would override format.outputDirectory.
--- Documentation/config/format.txt | 5 ++++- Documentation/git-format-patch.txt | 3 ++- builtin/log.c | 26 ++++++++++++++++++++++++-- t/t4014-format-patch.sh | 18 +++++++++++++++--- 4 files changed, 45 insertions(+), 7 deletions(-)
Documentation/config/format.txt +4 -1
@@ -87,8 +87,11 @@ format.coverLetter:: generate a cover-letter only when there's more than one patch. format.outputDirectory:: +format.<branch-name>.outputDirectory:: Set a custom directory to store the resulting files instead of the - current working directory. + current working directory. If patches are being generated for + <branch-name>, the latter option takes priority if it exists, + otherwise we will fallback to the former. format.useAutoBase:: A boolean value which lets you enable the `--base=auto` option of
Documentation/git-format-patch.txt +2 -1
@@ -359,12 +359,13 @@ with configuration variables. ------------ In addition, for a specific branch, you can add additional "To:" or -"Cc:" headers. +"Cc:" headers and change the patch output directory. ------------ [format "branch-name"] to = <email> cc = <email> + outputDirectory = <directory> ------------ DISCUSSION
builtin/log.c +24 -2
@@ -1023,6 +1023,24 @@ static void show_diffstat(struct rev_info *rev,fprintf (rev->diffopt.file,"\n" ); } +static const char *get_branch_output_dir (struct rev_info *rev,const char *branch_name) +{ +struct strbuf buf =STRBUF_INIT ; +const char *output_directory; + +if (!branch_name) + branch_name =find_branch_name (rev); + +if (!branch_name || !*branch_name) +return NULL ; + +strbuf_addf (&buf,"format.%s.outputdirectory" , branch_name); +git_config_get_string_const (buf.buf, &output_directory); +strbuf_release (&buf); + +return output_directory; +} +static void add_branch_headers (struct rev_info *rev,const char *branch_name) {struct strbuf buf =STRBUF_INIT ;
@@ -1804,8 +1822,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } } -if (!output_directory && !use_stdout) - output_directory = config_output_directory; +if (!use_stdout) { +if (!output_directory) + output_directory =get_branch_output_dir (&rev, branch_name); +if (!output_directory) + output_directory = config_output_directory; + }if (!use_stdout) output_directory =set_outdir (prefix, output_directory);
t/t4014-format-patch.sh +15 -3
@@ -1667,12 +1667,24 @@ test_expect_success 'format-patch format.outputDirectory option' ' test_line_count = $(ls patches | wc -l) list ' -test_expect_success 'format-patch -o overrides format.outputDirectory' ' +test_expect_success 'format-patch format.side.outputDirectory option overrides format.outputDirectory' ' test_config format.outputDirectory patches && - rm -fr patches patchset && + test_config format.side.outputDirectory sidepatches && + rm -fr patches sidepatches && + git format-patch master..side && + git rev-list master..side >list && + test_path_is_missing patches && + test_line_count = $(ls sidepatches | wc -l) list +' + +test_expect_success 'format-patch -o overrides format.outputDirectory and format.side.outputDirectory' ' + test_config format.outputDirectory patches && + test_config format.side.outputDirectory sidepatches && + rm -fr patches sidepatches patchset && git format-patch master..side -o patchset && test_path_is_missing patches && - test_path_is_dir patchset + test_path_is_missing sidepatches && + test_line_count = $(ls patchset | wc -l) list ' test_expect_success 'format-patch --base' '
Signature · 1 line
2.22.0.rc1.169.g49223abbf8
Quoted 9 lines · Denton Liu
Hi Junio,
I've gotten rid of all the
format.*.coverSubjectstuff and replaced it with a genericformat.inferCoverSubjectthat will read the subject from the branch description. I've also madegit branch -dstop deleting theformat.<branch>.*variables.A new addition in this patchset is that format-patch is now taught to understand the
format.<branch-name>.outputDirectoryconfiguration.
[...]
Quick ping for this topic.
Thanks,
Denton
RFC PATCH 1/1 config: learn the "onbranch:" includeIf condition
In reply to Junio C HamanoCurrently, if a user wishes to have individual settings per branch, they are required to manually keep track of the settings in their head and manually set the options on the command-line or change the config at each branch.
Teach config the "onbranch:" includeIf condition so that it can conditionally include configuration files if the branch is checked out in the current worktree.
---
I decided to go ahead and implement the includeIf onbranch semantics for fun. For completeness, I'm sending it to the list but I'm not really sure if this should get merged, since I don't really have a use-case for this, especially if we go the branch-specific format-patch config route.
Another thing to note is that this change doesn't completely cover all the use-cases that the branch-specific format-patch does. In particular, if I run
$ git checkout foo $ git format-patch master..bar
with the format.bar.*, we'd get bar-specific configs, whereas with includeIf "onbranch:bar", we'd fail to include bar-specific configs and, more dangerously, we'd be including foo's configs.
But let's see how it goes.
Documentation/config.txt | 10 ++++++++++ config.c | 16 ++++++++++++++++ t/t1305-config-include.sh | 13 +++++++++++++ 3 files changed, 39 insertions(+)
Documentation/config.txt +10 -0
@@ -144,6 +144,11 @@ refer to linkgit:gitignore[5] for details. For convenience: This is the same as `gitdir` except that matching is done case-insensitively (e.g. on case-insensitive file sytems) +`onbranch`:: + The data that follows the keyword `onbranch:` is taken to be a + name of a local branch. If we are in a worktree where that + branch is currently checked out, the include condition is met. + A few more notes on matching via `gitdir` and `gitdir/i`: * Symlinks in `$GIT_DIR` are not resolved before matching.
@@ -206,6 +211,11 @@ Example [includeIf "gitdir:/path/to/group/"] path = foo.inc + ; include only if we are in a worktree where foo-branch is + ; currently checked out + [includeIf "onbranch:foo-branch"] + path = foo.inc + Values ~~~~~~
config.c +16 -0
@@ -19,6 +19,7 @@#include "utf8.h" #include "dir.h" #include "color.h" +#include "refs.h" struct config_source {struct config_source *prev;
@@ -264,6 +265,19 @@ static int include_by_gitdir(const struct config_options *opts,return ret; } +static int include_by_branch (const char *cond,size_t cond_len) +{ +int flags; +const char *refname =resolve_ref_unsafe ("HEAD" ,0 ,NULL , &flags); +const char *shortname; + +if (!refname || !(flags &REF_ISSYMREF ) || + !skip_prefix (refname,"refs/heads/" , &shortname)) +return 0 ; + +return !strncmp (cond, shortname, cond_len); +} +static int include_condition_is_true (const struct config_options *opts,const char *cond,size_t cond_len) {
@@ -272,6 +286,8 @@ static int include_condition_is_true(const struct config_options *opts,return include_by_gitdir (opts, cond, cond_len,0 ); else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len)) return include_by_gitdir(opts, cond, cond_len, 1); + else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len)) +return include_by_branch (cond, cond_len);/* unknown conditionals are always false */ return 0 ;
t/t1305-config-include.sh +13 -0
@@ -309,6 +309,19 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icas ) ' +test_expect_success 'conditional include, onbranch' ' + ( + cd bar && + echo "[includeIf \"onbranch:foo-branch\"]path=bar9" >>.git/config && + echo "[test]nine=9" >.git/bar9 && + test_must_fail git config test.nine && + git checkout -b foo-branch && + echo 9 >expect && + git config test.nine >actual && + test_cmp expect actual + ) +' + test_expect_success 'include cycles are detected' ' cat >.gitconfig <<-\EOF && [test]value = gitconfig
Signature · 1 line
2.22.0.rc1.169.g49223abbf8
Re: [RFC PATCH] config: learn the "onbranch:" includeIf condition
Hi,
Quoted 8 lines · Denton Liu
Currently, if a user wishes to have individual settings per branch, they are required to manually keep track of the settings in their head and manually set the options on the command-line or change the config at each branch.
Teach config the "onbranch:" includeIf condition so that it can conditionally include configuration files if the branch is checked out in the current worktree.
What a coincidence. I actually wished for something like this, to have branch-specific aliases.
However, I would need this to handle patterns (via wildmatch()?) rather than branch names.
Quoted 9 lines
I decided to go ahead and implement the includeIf onbranch semantics for fun. For completeness, I'm sending it to the list but I'm not really sure if this should get merged, since I don't really have a use-case for this, especially if we go the branch-specific format-patch config route.
Another thing to note is that this change doesn't completely cover all the use-cases that the branch-specific format-patch does. In particular, if I run
Quoted 6 lines
$ git checkout foo $ git format-patch master..barwith the
format.bar.*, we'd get bar-specific configs, whereas withincludeIf "onbranch:bar", we'd fail to include bar-specific configs and, more dangerously, we'd be including foo's configs.
I actually think that this is fine. "on branch" means that you are on the specified branch, not that you merely mention the branch name on the command-line (in which case there would be the ambiguity "did the user mean master or bar?").
Ciao,
Dscho
Re: [RFC PATCH] config: learn the "onbranch:" includeIf condition
Hi Johannes,
Quoted 13 lines · Johannes Schindelin
Hi,
Quoted 8 lines · Denton Liu
Currently, if a user wishes to have individual settings per branch, they are required to manually keep track of the settings in their head and manually set the options on the command-line or change the config at each branch.
Teach config the "onbranch:" includeIf condition so that it can conditionally include configuration files if the branch is checked out in the current worktree.
Quoted 5 lines
What a coincidence. I actually wished for something like this, to have branch-specific aliases.
However, I would need this to handle patterns (via
wildmatch()?) rather than branch names.
Do you mean that we should be able to match a branch by pattern? So, for example, if we had
[includeIf "onbranch:mas*"]
we'd match if we were on "master"?
Quoted 13 lines
Quoted 13 lines
I decided to go ahead and implement the includeIf onbranch semantics for fun. For completeness, I'm sending it to the list but I'm not really sure if this should get merged, since I don't really have a use-case for this, especially if we go the branch-specific format-patch config route.
Another thing to note is that this change doesn't completely cover all the use-cases that the branch-specific format-patch does. In particular, if I run
$ git checkout foo $ git format-patch master..bar
Quoted 8 lines
Quoted 3 lines
with the
format.bar.*, we'd get bar-specific configs, whereas withincludeIf "onbranch:bar", we'd fail to include bar-specific configs and, more dangerously, we'd be including foo's configs.I actually think that this is fine. "on branch" means that you are on the specified branch, not that you merely mention the branch name on the command-line (in which case there would be the ambiguity "did the user mean
masterorbar?").
The reason why I brought this up as a use case was because currently, when format-patch generates a cover letter, with the above, it'll use bar's branch description to populate it even if "foo" is checked out. As a result, when implementing the branch-specific format-patch stuff, I wanted to make this consistent so that we wouldn't end up in a situation where the cover letter has the branch's description but is missing its Cc's.
Quoted 3 lines
Ciao,
Dscho
Re: [RFC PATCH] config: learn the "onbranch:" includeIf condition
Hi Denton,
Quoted 19 lines · Denton Liu
Quoted 11 lines · Johannes Schindelin
Quoted 8 lines · Denton Liu
Currently, if a user wishes to have individual settings per branch, they are required to manually keep track of the settings in their head and manually set the options on the command-line or change the config at each branch.
Teach config the "onbranch:" includeIf condition so that it can conditionally include configuration files if the branch is checked out in the current worktree.
Quoted 5 lines
What a coincidence. I actually wished for something like this, to have branch-specific aliases.
However, I would need this to handle patterns (via
wildmatch()?) rather than branch names.
Quoted 6 lines
Do you mean that we should be able to match a branch by pattern? So, for example, if we had
[includeIf "onbranch:mas*"]
we'd match if we were on "master"?
Yes, precisely.
I would use this for the "ever-green" branches of Git for Windows, i.e. the branches that are continuously rebasing Git for Windows' branch thicket on top of maint, master, next & pu. Those are called shears/maint, shears/master, etc (for historical reasons) in
https://github.com/git-for-windows/git.
Quoted 22 lines
Quoted 13 lines
Quoted 13 lines
I decided to go ahead and implement the includeIf onbranch semantics for fun. For completeness, I'm sending it to the list but I'm not really sure if this should get merged, since I don't really have a use-case for this, especially if we go the branch-specific format-patch config route.
Another thing to note is that this change doesn't completely cover all the use-cases that the branch-specific format-patch does. In particular, if I run
$ git checkout foo $ git format-patch master..barQuoted 8 lines
Quoted 3 lines
with the
format.bar.*, we'd get bar-specific configs, whereas withincludeIf "onbranch:bar", we'd fail to include bar-specific configs and, more dangerously, we'd be including foo's configs.I actually think that this is fine. "on branch" means that you are on the specified branch, not that you merely mention the branch name on the command-line (in which case there would be the ambiguity "did the user mean
masterorbar?").
Quoted 7 lines
The reason why I brought this up as a use case was because currently, when format-patch generates a cover letter, with the above, it'll use bar's branch description to populate it even if "foo" is checked out. As a result, when implementing the branch-specific format-patch stuff, I wanted to make this consistent so that we wouldn't end up in a situation where the cover letter has the branch's description but is missing its Cc's.
That strikes me as a different use case than includeIf. I could imagine that you'd want a setting like formatpatch.detecttargetbranch = auto or some such that would pick up the format.bar* settings if there was *one* rev argument, and it was a commit range (or a tip commit), *and* it obviously referred to a single target branch.
It's just a scenario that is *very* specific to git format-patch.
For example, I would not, ever, want git log ..next to pick up a config specific to next just because I mentioned a commit range with range as the tip to start from.
Ciao,
Dscho
Re: [RFC PATCH] config: learn the "onbranch:" includeIf condition
Quoted 8 lines · Johannes Schindelin
Hi Denton,
Quoted 4 lines · Denton Liu
Quoted 2 lines · Johannes Schindelin
On Thu, 30 May 2019, Denton Liu wrote:
[...]
Quoted 31 lines
Quoted 23 lines
Quoted 14 lines
Quoted 14 lines
I decided to go ahead and implement the includeIf onbranch semantics for fun. For completeness, I'm sending it to the list but I'm not really sure if this should get merged, since I don't really have a use-case for this, especially if we go the branch-specific format-patch config route.
Another thing to note is that this change doesn't completely cover all the use-cases that the branch-specific format-patch does. In particular, if I run
$ git checkout foo $ git format-patch master..barQuoted 8 lines
Quoted 3 lines
with the
format.bar.*, we'd get bar-specific configs, whereas withincludeIf "onbranch:bar", we'd fail to include bar-specific configs and, more dangerously, we'd be including foo's configs.I actually think that this is fine. "on branch" means that you are on the specified branch, not that you merely mention the branch name on the command-line (in which case there would be the ambiguity "did the user mean
masterorbar?").Quoted 7 lines
The reason why I brought this up as a use case was because currently, when format-patch generates a cover letter, with the above, it'll use bar's branch description to populate it even if "foo" is checked out. As a result, when implementing the branch-specific format-patch stuff, I wanted to make this consistent so that we wouldn't end up in a situation where the cover letter has the branch's description but is missing its Cc's.
Quoted 5 lines
That strikes me as a different use case than
includeIf. I could imagine that you'd want a setting likeformatpatch.detecttargetbranch = autoor some such that would pick up theformat.bar*settings if there was *one* rev argument, and it was a commit range (or a tip commit), *and* it obviously referred to a single target branch.
Correct. For context, upthread I initially implemented the branch-specific format-patch configs but Ævar suggested that we implement the onbranch config semantics instead.
So I was just addressing the fact that this patch can't supercede the branch-specific format-patch stuff since they have different use cases so the other patchset has to coexist with this one. I'm happy to see that we're both in agreement about this.
Quoted 6 lines
It's just a scenario that is *very* specific to
git format-patch.For example, I would not, ever, want
git log ..nextto pick up a config specific tonextjust because I mentioned a commit range withrangeas the tip to start from.
Yeah, I'd never dream of implementing something that gross ;)
Quoted 3 lines
Ciao,
Dscho
PATCH v2 1/1 config: learn the "onbranch:" includeIf condition
In reply to Denton LiuCurrently, if a user wishes to have individual settings per branch, they are required to manually keep track of the settings in their head and manually set the options on the command-line or change the config at each branch.
Teach config the "onbranch:" includeIf condition so that it can conditionally include configuration files if the branch that is checked out in the current worktree matches the pattern given.
---
Thanks for taking a look, Johannes. I've modified the patch to match with wildcards now.
Changes since v1:
* Allow onbranch: to specify a pattern instead of just a static comparison
Interdiff against v1:
diff --git a/Documentation/config.txt b/Documentation/config.txt index 3b9fbe1860..93aa4323c6 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -145,9 +145,11 @@ refer to linkgit:gitignore[5] for details. For convenience:
case-insensitively (e.g. on case-insensitive file sytems)
onbranch::
- The data that follows the keyword onbranch: is taken to be a
- name of a local branch. If we are in a worktree where that
- branch is currently checked out, the include condition is met.
+ The data that follows the keyword onbranch: is taken to be a pattern
+ with standard globbing wildcards and two additional ones, **/ and
+ /**, that can match multiple path components. If we are in a worktree
+ where the name of the branch that is currently checked out matches the
+ pattern, the include condition is met.
A few more notes on matching via gitdir and gitdir/i:
diff --git a/config.c b/config.c
index 954e84e13a..48bb435739 100644
--- a/config.c
+++ b/config.c
@@ -268,6 +268,8 @@ static int include_by_gitdir(const struct config_options *opts,
static int include_by_branch(const char *cond, size_t cond_len)
{
int flags;
+ int ret;
+ struct strbuf pattern = STRBUF_INIT;
const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, &flags);
const char *shortname; @@ -275,7 +277,10 @@ static int include_by_branch(const char *cond, size_t cond_len)
!skip_prefix(refname, "refs/heads/", &shortname))
return 0;
- return !strncmp(cond, shortname, cond_len); + strbuf_add(&pattern, cond, cond_len); + ret = !wildmatch(pattern.buf, shortname, WM_PATHNAME); + strbuf_release(&pattern); + return ret; }
static int include_condition_is_true(const struct config_options *opts,
diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh index 062db08ad9..05c7def1f2 100755
--- a/t/t1305-config-include.sh
+++ b/t/t1305-config-include.sh
@@ -314,6 +314,7 @@ test_expect_success 'conditional include, onbranch' '
cd bar &&
echo "[includeIf \"onbranch:foo-branch\"]path=bar9" >>.git/config && echo "[test]nine=9" >.git/bar9 &&
+ git checkout -b master &&
test_must_fail git config test.nine &&
git checkout -b foo-branch &&
echo 9 >expect &&
@@ -322,6 +323,25 @@ test_expect_success 'conditional include, onbranch' '
)
'
+test_expect_success 'conditional include, onbranch, wildcard' '
+ (
+ cd bar &&
+ echo "[includeIf \"onbranch:?oo-*/**\"]path=bar10" >>.git/config &&
+ echo "[test]ten=10" >.git/bar10 &&
+ git checkout -b not-foo-branch/a &&
+ test_must_fail git config test.ten &&
+
+ echo 10 >expect &&
+ git checkout -b foo-branch/a/b/c &&
+ git config test.ten >actual &&
+ test_cmp expect actual &&
+
+ git checkout -b moo-bar/a &&
+ git config test.ten >actual &&
+ test_cmp expect actual
+ )
+'
+
test_expect_success 'include cycles are detected' '
cat >.gitconfig <<-\EOF &&
[test]value = gitconfig
Documentation/config.txt | 12 ++++++++++++ config.c | 21 +++++++++++++++++++++ t/t1305-config-include.sh | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+)
Documentation/config.txt +12 -0
@@ -144,6 +144,13 @@ refer to linkgit:gitignore[5] for details. For convenience: This is the same as `gitdir` except that matching is done case-insensitively (e.g. on case-insensitive file sytems) +`onbranch`:: + The data that follows the keyword `onbranch:` is taken to be a pattern + with standard globbing wildcards and two additional ones, `**/` and + `/**`, that can match multiple path components. If we are in a worktree + where the name of the branch that is currently checked out matches the + pattern, the include condition is met. + A few more notes on matching via `gitdir` and `gitdir/i`: * Symlinks in `$GIT_DIR` are not resolved before matching.
@@ -206,6 +213,11 @@ Example [includeIf "gitdir:/path/to/group/"] path = foo.inc + ; include only if we are in a worktree where foo-branch is + ; currently checked out + [includeIf "onbranch:foo-branch"] + path = foo.inc + Values ~~~~~~
config.c +21 -0
@@ -19,6 +19,7 @@#include "utf8.h" #include "dir.h" #include "color.h" +#include "refs.h" struct config_source {struct config_source *prev;
@@ -264,6 +265,24 @@ static int include_by_gitdir(const struct config_options *opts,return ret; } +static int include_by_branch (const char *cond,size_t cond_len) +{ +int flags; +int ret; +struct strbuf pattern =STRBUF_INIT ; +const char *refname =resolve_ref_unsafe ("HEAD" ,0 ,NULL , &flags); +const char *shortname; + +if (!refname || !(flags &REF_ISSYMREF ) || + !skip_prefix (refname,"refs/heads/" , &shortname)) +return 0 ; + +strbuf_add (&pattern, cond, cond_len); + ret = !wildmatch (pattern.buf, shortname,WM_PATHNAME ); +strbuf_release (&pattern); +return ret; +} +static int include_condition_is_true (const struct config_options *opts,const char *cond,size_t cond_len) {
@@ -272,6 +291,8 @@ static int include_condition_is_true(const struct config_options *opts,return include_by_gitdir (opts, cond, cond_len,0 ); else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len)) return include_by_gitdir(opts, cond, cond_len, 1); + else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len)) +return include_by_branch (cond, cond_len);/* unknown conditionals are always false */ return 0 ;
t/t1305-config-include.sh +33 -0
@@ -309,6 +309,39 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icas ) ' +test_expect_success 'conditional include, onbranch' ' + ( + cd bar && + echo "[includeIf \"onbranch:foo-branch\"]path=bar9" >>.git/config && + echo "[test]nine=9" >.git/bar9 && + git checkout -b master && + test_must_fail git config test.nine && + git checkout -b foo-branch && + echo 9 >expect && + git config test.nine >actual && + test_cmp expect actual + ) +' + +test_expect_success 'conditional include, onbranch, wildcard' ' + ( + cd bar && + echo "[includeIf \"onbranch:?oo-*/**\"]path=bar10" >>.git/config && + echo "[test]ten=10" >.git/bar10 && + git checkout -b not-foo-branch/a && + test_must_fail git config test.ten && + + echo 10 >expect && + git checkout -b foo-branch/a/b/c && + git config test.ten >actual && + test_cmp expect actual && + + git checkout -b moo-bar/a && + git config test.ten >actual && + test_cmp expect actual + ) +' + test_expect_success 'include cycles are detected' ' cat >.gitconfig <<-\EOF && [test]value = gitconfig
Signature · 1 line
2.22.0.rc1.169.g49223abbf8
Re: [PATCH v2] config: learn the "onbranch:" includeIf condition
Hi Denton,
Quoted 8 lines · Denton Liu
Currently, if a user wishes to have individual settings per branch, they are required to manually keep track of the settings in their head and manually set the options on the command-line or change the config at each branch.
Teach config the "onbranch:" includeIf condition so that it can conditionally include configuration files if the branch that is checked out in the current worktree matches the pattern given.
This looks good to me.
Thanks,
Dscho
Quoted 224 lines
Signed-off-by Denton Liu <[email protected]>---
Thanks for taking a look, Johannes. I've modified the patch to match with wildcards now.
Changes since v1:
* Allow onbranch: to specify a pattern instead of just a static comparison
Interdiff against v1:
diff --gita/Documentation/config.txtb/Documentation/config.txtindex3b9fbe1860..93aa4323c6100644
---a/Documentation/config.txt
+++b/Documentation/config.txt
@@ -145,9 +145,11 @@ refer to linkgit:gitignore[5] for details. For convenience:
case-insensitively (e.g. on case-insensitive file sytems)`onbranch`::- The data that follows the keyword
onbranch:is taken to be a
- name of a local branch. If we are in a worktree where that
- branch is currently checked out, the include condition is met.
+ The data that follows the keywordonbranch:is taken to be a pattern
+ with standard globbing wildcards and two additional ones,**/and
+/**, that can match multiple path components. If we are in a worktree
+ where the name of the branch that is currently checked out matches the
+ pattern, the include condition is met.A few more notes on matching via
gitdirandgitdir/i:diff --git a/config.c b/config.c index 954e84e13a..48bb435739 100644 --- a/config.c +++ b/config.c @@ -268,6 +268,8 @@ static int include_by_gitdir(const struct config_options *opts, static int include_by_branch(const char *cond, size_t cond_len) { int flags; + int ret; + struct strbuf pattern = STRBUF_INIT; const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, &flags); const char *shortname;@@ -275,7 +277,10 @@ static int
include_by_branch(const char *cond, size_t cond_len)
!skip_prefix(refname, "refs/heads/", &shortname))
return 0;- return !strncmp(cond, shortname, cond_len); + strbuf_add(&pattern, cond, cond_len); + ret = !wildmatch(pattern.buf, shortname, WM_PATHNAME); + strbuf_release(&pattern); + return ret; }static int include_condition_is_true(const struct
config_options*opts,
diff --gita/t/t1305-config-include.shb/t/t1305-config-include.shindex062db08ad9..05c7def1f2100755
---a/t/t1305-config-include.sh
+++b/t/t1305-config-include.sh
@@ -314,6 +314,7 @@test_expect_success'conditional include, onbranch' '
cd bar &&
echo "[includeIf \"onbranch:foo-branch\"]path=bar9" >>.git/config && echo "[test]nine=9" >.git/bar9 &&
+ git checkout -b master &&
test_must_failgit config test.nine &&
git checkout -b foo-branch &&
echo 9 >expect &&
@@ -322,6 +323,25 @@test_expect_success'conditional include, onbranch' '
)
'+test_expect_success 'conditional include, onbranch, wildcard' '
+ (
+ cd bar &&
+ echo "[includeIf \"onbranch:?oo-*/**\"]path=bar10" >>.git/config &&
+ echo "[test]ten=10" >.git/bar10 &&
+ git checkout -b not-foo-branch/a &&
+test_must_failgit config test.ten &&
+
+ echo 10 >expect &&
+ git checkout -b foo-branch/a/b/c &&
+ git config test.ten >actual &&
+test_cmpexpect actual &&
+
+ git checkout -b moo-bar/a &&
+ git config test.ten >actual &&
+test_cmpexpect actual
+ )
+'
+
test_expect_success'include cycles are detected' '
cat >.gitconfig <<-\EOF &&
[test]value = gitconfigDocumentation/config.txt | 12 ++++++++++++ config.c | 21 +++++++++++++++++++++ t/t1305-config-include.sh | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+)Documentation/config.txt +12
-0@@ -144,6 +144,13 @@ refer to linkgit:gitignore[5] for details. For convenience: This is the same as `gitdir` except that matching is done case-insensitively (e.g. on case-insensitive file sytems) +`onbranch`:: + The data that follows the keyword `onbranch:` is taken to be a pattern + with standard globbing wildcards and two additional ones, `**/` and + `/**`, that can match multiple path components. If we are in a worktree + where the name of the branch that is currently checked out matches the + pattern, the include condition is met. + A few more notes on matching via `gitdir` and `gitdir/i`: * Symlinks in `$GIT_DIR` are not resolved before matching.@@ -206,6 +213,11 @@ Example [includeIf "gitdir:/path/to/group/"] path = foo.inc + ; include only if we are in a worktree where foo-branch is + ; currently checked out + [includeIf "onbranch:foo-branch"] + path = foo.inc + Values ~~~~~~config.c +21
-0@@ -19,6 +19,7 @@#include "utf8.h" #include "dir.h" #include "color.h" +#include "refs.h" struct config_source {struct config_source *prev;@@ -264,6 +265,24 @@ static int include_by_gitdir(const struct config_options *opts,return ret; } +static int include_by_branch (const char *cond,size_t cond_len) +{ +int flags; +int ret; +struct strbuf pattern =STRBUF_INIT ; +const char *refname =resolve_ref_unsafe ("HEAD" ,0 ,NULL , &flags); +const char *shortname; + +if (!refname || !(flags &REF_ISSYMREF ) || + !skip_prefix (refname,"refs/heads/" , &shortname)) +return 0 ; + +strbuf_add (&pattern, cond, cond_len); + ret = !wildmatch (pattern.buf, shortname,WM_PATHNAME ); +strbuf_release (&pattern); +return ret; +} +static int include_condition_is_true (const struct config_options *opts,const char *cond,size_t cond_len) {@@ -272,6 +291,8 @@ static int include_condition_is_true(const struct config_options *opts,return include_by_gitdir (opts, cond, cond_len,0 ); else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len)) return include_by_gitdir(opts, cond, cond_len, 1); + else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len)) +return include_by_branch (cond, cond_len);/* unknown conditionals are always false */ return 0 ;t/t1305-config-include.sh +33
-1@@ -309,6 +309,39 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icas ) ' +test_expect_success 'conditional include, onbranch' ' + ( + cd bar && + echo "[includeIf \"onbranch:foo-branch\"]path=bar9" >>.git/config && + echo "[test]nine=9" >.git/bar9 && + git checkout -b master && + test_must_fail git config test.nine && + git checkout -b foo-branch && + echo 9 >expect && + git config test.nine >actual && + test_cmp expect actual + ) +' + +test_expect_success 'conditional include, onbranch, wildcard' ' + ( + cd bar && + echo "[includeIf \"onbranch:?oo-*/**\"]path=bar10" >>.git/config && + echo "[test]ten=10" >.git/bar10 && + git checkout -b not-foo-branch/a && + test_must_fail git config test.ten && + + echo 10 >expect && + git checkout -b foo-branch/a/b/c && + git config test.ten >actual && + test_cmp expect actual && + + git checkout -b moo-bar/a && + git config test.ten >actual && + test_cmp expect actual + ) +' + test_expect_success 'include cycles are detected' ' cat >.gitconfig <<-\EOF && [test]value = gitconfig --2.22.0.rc1.169.g49223abbf8
Re: [PATCH v2] config: learn the "onbranch:" includeIf condition
Hi Denton,
Quoted 7 lines · Johannes Schindelin
Quoted 5 lines · Denton Liu
Currently, if a user wishes to have individual settings per branch, they are required to manually keep track of the settings in their head and manually set the options on the command-line or change the config at each branch.
Quoted 5 lines
Quoted 3 lines
Teach config the "onbranch:" includeIf condition so that it can conditionally include configuration files if the branch that is checked out in the current worktree matches the pattern given.
This looks good to me.
... actually...
Quoted 11 lines
t/t1305-config-include.sh test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icas · line 314
Quoted 11 lines
t/t1305-config-include.sh +3
-0@@ -309,6 +309,39 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icas ) ' +test_expect_success 'conditional include, onbranch' ' + ( + cd bar &&
This bar is a side effect of an earlier test case. To be precise, of this test case:
test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' '
ln -s foo bar && ( cd bar && echo "[includeIf \"gitdir:bar/\"]path=bar7" >>.git/config && echo "[test]seven=7" >.git/bar7 && echo 7 >expect && git config test.seven >actual && test_cmp expect actual )
'
As you can see, this test case is marked with the SYMLINKS prerequisite, and hence can be skipped.
I got a crazy idea, though: how about cd foo instead of cd bar? It should still work, as bar is just a symbolic link (unless that test case has been skipped, in which case bar does not even exist) to foo.
And while this still relies on a side effect of an earlier test case ('conditional include, both unanchored', to be precise), at least that test case cannot be skipped because of a missing prerequisite.
The same s/cd bar/cd foo applies to the second test case in this patch, too, of course.
Thanks,
Dscho
Quoted 39 lines
Quoted 37 lines
t/t1305-config-include.sh +30
-1+ echo "[includeIf \"onbranch:foo-branch\"]path=bar9" >>.git/config && + echo "[test]nine=9" >.git/bar9 && + git checkout -b master && + test_must_fail git config test.nine && + git checkout -b foo-branch && + echo 9 >expect && + git config test.nine >actual && + test_cmp expect actual + ) +' + +test_expect_success 'conditional include, onbranch, wildcard' ' + ( + cd bar && + echo "[includeIf \"onbranch:?oo-*/**\"]path=bar10" >>.git/config && + echo "[test]ten=10" >.git/bar10 && + git checkout -b not-foo-branch/a && + test_must_fail git config test.ten && + + echo 10 >expect && + git checkout -b foo-branch/a/b/c && + git config test.ten >actual && + test_cmp expect actual && + + git checkout -b moo-bar/a && + git config test.ten >actual && + test_cmp expect actual + ) +' + test_expect_success 'include cycles are detected' ' cat >.gitconfig <<-\EOF && [test]value = gitconfig --2.22.0.rc1.169.g49223abbf8
Re: [PATCH v2] config: learn the "onbranch:" includeIf condition
In reply to Denton LiuQuoted 9 lines · Denton Liu
Currently, if a user wishes to have individual settings per branch, they are required to manually keep track of the settings in their head and manually set the options on the command-line or change the config at each branch.
Teach config the "onbranch:" includeIf condition so that it can conditionally include configuration files if the branch that is checked out in the current worktree matches the pattern given.
Just wondering, anybody wants special settings on detached head (and if so, what syntax should it be)?
Quoted 5 lines
Documentation/config.txt +0
-0
Documentation/config.txt refer to linkgit:gitignore[5] for details. For convenience: · line 152
Quoted 9 lines
Documentation/config.txt +6
-0@@ -144,6 +144,13 @@ refer to linkgit:gitignore[5] for details. For convenience: This is the same as `gitdir` except that matching is done case-insensitively (e.g. on case-insensitive file sytems) +`onbranch`:: + The data that follows the keyword `onbranch:` is taken to be a pattern + with standard globbing wildcards and two additional ones, `**/` and + `/**`, that can match multiple path components. If we are in a worktree + where the name of the branch that is currently checked out matches the + pattern, the include condition is met.
Supporting transforming "foo/" to "foo/**" would be nice (gitdir and gitdir/i do this). Useful when you organize your branches into "subdirs".
Quoted 4 lines
Documentation/config.txt +0
-0@@ -264,6 +265,24 @@ static int include_by_gitdir(const struct config_options *opts, return ret; }
Documentation/config.txt static int include_by_gitdir(const struct config_options *opts, · line 277
Quoted 10 lines
Documentation/config.txt +10
-0+static int include_by_branch(const char *cond, size_t cond_len) +{ + int flags; + int ret; + struct strbuf pattern = STRBUF_INIT; + const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, &flags); + const char *shortname; + + if (!refname || !(flags & REF_ISSYMREF) || + !skip_prefix(refname, "refs/heads/", &shortname))
We probably don't even need to check more than !refname. Symbolic refs from HEAD must be refs/heads/* or it's an error (fsck will complain). But it's probably also ok to stay strict.
Quoted 7 lines
Documentation/config.txt +7
-0+ return 0; + + strbuf_add(&pattern, cond, cond_len); + ret = !wildmatch(pattern.buf, shortname, WM_PATHNAME); + strbuf_release(&pattern); + return ret; +}
Signature · 1 line
Duy
PATCH v3 1/1 config: learn the "onbranch:" includeIf condition
In reply to Denton LiuCurrently, if a user wishes to have individual settings per branch, they are required to manually keep track of the settings in their head and manually set the options on the command-line or change the config at each branch.
Teach config the "onbranch:" includeIf condition so that it can conditionally include configuration files if the branch that is checked out in the current worktree matches the pattern given.
---
Thanks for the review, Johannes and Duy. I've incorporated both of your suggestions into this round.
Notes:
Changes since v2:
* Run test-cases outside foo/ since the subdirectory is not necessary
* Implicitly add ** when there is a trailing /
Changes since v1:
* Allow onbranch: to specify a pattern instead of just a static comparison
Interdiff against v2:
diff --git a/Documentation/config.txt b/Documentation/config.txt index 93aa4323c6..e3f5bc3396 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -145,11 +145,18 @@ refer to linkgit:gitignore[5] for details. For convenience:
case-insensitively (e.g. on case-insensitive file sytems)
onbranch::
- The data that follows the keyword onbranch: is taken to be a pattern
- with standard globbing wildcards and two additional ones, **/ and
- /**, that can match multiple path components. If we are in a worktree
- where the name of the branch that is currently checked out matches the
- pattern, the include condition is met.
+ The data that follows the keyword onbranch: is taken to be a
+ pattern with standard globbing wildcards and two additional
+ ones, **/ and /**, that can match multiple path components.
+ If we are in a worktree where the name of the branch that is
+ currently checked out matches the pattern, the include condition
+ is met.
++
+If the pattern ends with /, ** will be automatically added. For +example, the pattern foo/ becomes foo/**. In other words, it matches +all branches that begin with foo/. This is useful if your branches are +organized hierarchically and you would like to apply a configuration to +all the branches in that hierarchy.
A few more notes on matching via gitdir and gitdir/i:
diff --git a/config.c b/config.c
index 48bb435739..ad4166e243 100644
--- a/config.c
+++ b/config.c
@@ -171,6 +171,12 @@ static int handle_path_include(const char *path, struct config_include_data *inc
return ret;
}
+static void add_trailing_starstar_for_dir(struct strbuf *pat)
+{
+ if (pat->len && is_dir_sep(pat->buf[pat->len - 1]))
+ strbuf_addstr(pat, "**");
+}
+
static int prepare_include_condition_pattern(struct strbuf *pat)
{
struct strbuf path = STRBUF_INIT;
@@ -200,8 +206,7 @@ static int prepare_include_condition_pattern(struct strbuf *pat)
} else if (!is_absolute_path(pat->buf))
strbuf_insert(pat, 0, "**/", 3);
- if (pat->len && is_dir_sep(pat->buf[pat->len - 1]))
- strbuf_addstr(pat, "**");
+ add_trailing_starstar_for_dir(pat);strbuf_release(&path); return prefix; @@ -278,6 +283,7 @@ static int include_by_branch(const char *cond, size_t cond_len) return 0; strbuf_add(&pattern, cond, cond_len); + add_trailing_starstar_for_dir(&pattern); ret = !wildmatch(pattern.buf, shortname, WM_PATHNAME); strbuf_release(&pattern); return ret; diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh index 05c7def1f2..9571e366f8 100755 --- a/t/t1305-config-include.sh +++ b/t/t1305-config-include.sh @@ -310,36 +310,42 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icas '
test_expect_success 'conditional include, onbranch' '
- (
- cd bar &&
- echo "[includeIf \"onbranch:foo-branch\"]path=bar9" >>.git/config &&
- echo "[test]nine=9" >.git/bar9 &&
- git checkout -b master &&
- test_must_fail git config test.nine &&
- git checkout -b foo-branch &&
- echo 9 >expect &&
- git config test.nine >actual &&
- test_cmp expect actual
- )
+ echo "[includeIf \"onbranch:foo-branch\"]path=bar9" >>.git/config &&
+ echo "[test]nine=9" >.git/bar9 &&
+ git checkout -b master &&
+ test_must_fail git config test.nine &&
+ git checkout -b foo-branch &&
+ echo 9 >expect &&
+ git config test.nine >actual &&
+ test_cmp expect actual
'
test_expect_success 'conditional include, onbranch, wildcard' '
- (
- cd bar &&
- echo "[includeIf \"onbranch:?oo-*/**\"]path=bar10" >>.git/config &&
- echo "[test]ten=10" >.git/bar10 &&
- git checkout -b not-foo-branch/a &&
- test_must_fail git config test.ten &&
-
- echo 10 >expect &&
- git checkout -b foo-branch/a/b/c &&
- git config test.ten >actual &&
- test_cmp expect actual &&
-
- git checkout -b moo-bar/a &&
- git config test.ten >actual &&
- test_cmp expect actual
- )
+ echo "[includeIf \"onbranch:?oo-*/**\"]path=bar10" >>.git/config &&
+ echo "[test]ten=10" >.git/bar10 &&
+ git checkout -b not-foo-branch/a &&
+ test_must_fail git config test.ten &&
+
+ echo 10 >expect &&
+ git checkout -b foo-branch/a/b/c &&
+ git config test.ten >actual &&
+ test_cmp expect actual &&
+
+ git checkout -b moo-bar/a &&
+ git config test.ten >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'conditional include, onbranch, implicit /** for /' '
+ echo "[includeIf \"onbranch:foo-dir/\"]path=bar11" >>.git/config &&
+ echo "[test]eleven=11" >.git/bar11 &&
+ git checkout -b not-foo-dir/a &&
+ test_must_fail git config test.eleven &&
+
+ echo 11 >expect &&
+ git checkout -b foo-dir/a/b/c &&
+ git config test.eleven >actual &&
+ test_cmp expect actual
'
test_expect_success 'include cycles are detected' '
Documentation/config.txt | 19 +++++++++++++++++++ config.c | 31 +++++++++++++++++++++++++++++-- t/t1305-config-include.sh | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-)
Documentation/config.txt +19 -0
@@ -144,6 +144,20 @@ refer to linkgit:gitignore[5] for details. For convenience: This is the same as `gitdir` except that matching is done case-insensitively (e.g. on case-insensitive file sytems) +`onbranch`:: + The data that follows the keyword `onbranch:` is taken to be a + pattern with standard globbing wildcards and two additional + ones, `**/` and `/**`, that can match multiple path components. + If we are in a worktree where the name of the branch that is + currently checked out matches the pattern, the include condition + is met. ++ +If the pattern ends with `/`, `**` will be automatically added. For +example, the pattern `foo/` becomes `foo/**`. In other words, it matches +all branches that begin with `foo/`. This is useful if your branches are +organized hierarchically and you would like to apply a configuration to +all the branches in that hierarchy. + A few more notes on matching via `gitdir` and `gitdir/i`: * Symlinks in `$GIT_DIR` are not resolved before matching.
@@ -206,6 +220,11 @@ Example [includeIf "gitdir:/path/to/group/"] path = foo.inc + ; include only if we are in a worktree where foo-branch is + ; currently checked out + [includeIf "onbranch:foo-branch"] + path = foo.inc + Values ~~~~~~
config.c +29 -2
@@ -19,6 +19,7 @@#include "utf8.h" #include "dir.h" #include "color.h" +#include "refs.h" struct config_source {struct config_source *prev;
@@ -170,6 +171,12 @@ static int handle_path_include(const char *path, struct config_include_data *increturn ret; } +static void add_trailing_starstar_for_dir (struct strbuf *pat) +{ +if (pat->len &&is_dir_sep (pat->buf[pat->len -1 ])) +strbuf_addstr (pat,"**" ); +} +static int prepare_include_condition_pattern (struct strbuf *pat) {struct strbuf path =STRBUF_INIT ;
@@ -199,8 +206,7 @@ static int prepare_include_condition_pattern(struct strbuf *pat) }else if (!is_absolute_path (pat->buf))strbuf_insert (pat,0 ,"**/" ,3 ); -if (pat->len &&is_dir_sep (pat->buf[pat->len -1 ])) -strbuf_addstr (pat,"**" ); +add_trailing_starstar_for_dir (pat);strbuf_release (&path);return prefix;
@@ -264,6 +270,25 @@ static int include_by_gitdir(const struct config_options *opts,return ret; } +static int include_by_branch (const char *cond,size_t cond_len) +{ +int flags; +int ret; +struct strbuf pattern =STRBUF_INIT ; +const char *refname =resolve_ref_unsafe ("HEAD" ,0 ,NULL , &flags); +const char *shortname; + +if (!refname || !(flags &REF_ISSYMREF ) || + !skip_prefix (refname,"refs/heads/" , &shortname)) +return 0 ; + +strbuf_add (&pattern, cond, cond_len); +add_trailing_starstar_for_dir (&pattern); + ret = !wildmatch (pattern.buf, shortname,WM_PATHNAME ); +strbuf_release (&pattern); +return ret; +} +static int include_condition_is_true (const struct config_options *opts,const char *cond,size_t cond_len) {
@@ -272,6 +297,8 @@ static int include_condition_is_true(const struct config_options *opts,return include_by_gitdir (opts, cond, cond_len,0 ); else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len)) return include_by_gitdir(opts, cond, cond_len, 1); + else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len)) +return include_by_branch (cond, cond_len);/* unknown conditionals are always false */ return 0 ;
t/t1305-config-include.sh +39 -0
@@ -309,6 +309,45 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icas ) ' +test_expect_success 'conditional include, onbranch' ' + echo "[includeIf \"onbranch:foo-branch\"]path=bar9" >>.git/config && + echo "[test]nine=9" >.git/bar9 && + git checkout -b master && + test_must_fail git config test.nine && + git checkout -b foo-branch && + echo 9 >expect && + git config test.nine >actual && + test_cmp expect actual +' + +test_expect_success 'conditional include, onbranch, wildcard' ' + echo "[includeIf \"onbranch:?oo-*/**\"]path=bar10" >>.git/config && + echo "[test]ten=10" >.git/bar10 && + git checkout -b not-foo-branch/a && + test_must_fail git config test.ten && + + echo 10 >expect && + git checkout -b foo-branch/a/b/c && + git config test.ten >actual && + test_cmp expect actual && + + git checkout -b moo-bar/a && + git config test.ten >actual && + test_cmp expect actual +' + +test_expect_success 'conditional include, onbranch, implicit /** for /' ' + echo "[includeIf \"onbranch:foo-dir/\"]path=bar11" >>.git/config && + echo "[test]eleven=11" >.git/bar11 && + git checkout -b not-foo-dir/a && + test_must_fail git config test.eleven && + + echo 11 >expect && + git checkout -b foo-dir/a/b/c && + git config test.eleven >actual && + test_cmp expect actual +' + test_expect_success 'include cycles are detected' ' cat >.gitconfig <<-\EOF && [test]value = gitconfig
Signature · 1 line
2.22.0.rc1.169.g49223abbf8
Re: [PATCH v3] config: learn the "onbranch:" includeIf condition
Hi Denton,
Quoted 12 lines · Denton Liu
Currently, if a user wishes to have individual settings per branch, they are required to manually keep track of the settings in their head and manually set the options on the command-line or change the config at each branch.
Teach config the "onbranch:" includeIf condition so that it can conditionally include configuration files if the branch that is checked out in the current worktree matches the pattern given.
Signed-off-by Denton Liu <[email protected]>---
Quoted 7 lines
Thanks for the review, Johannes and Duy. I've incorporated both of your suggestions into this round.
Notes:
Changes since v2:* Run test-cases outside foo/ since the subdirectory is not necessary
That should indeed take care of my concern. Thank you! Dscho
v3 cover teach branch-specific options for format-patch
In reply to Denton LiuHi all,
Although 'config: learn the "onbranch:" includeIf condition'[1] seems to be on track for "next", the content in this patchset is not entirely superseded by it.
Patches 1 and 2 should be relatively uncontroversial since they just do a bit of cleanup.
Patch 3 is a new feature that isn't included in the config onbranch stuff at all. In introduces the --infer-cover-subject command-line option which would allow a cover-letter's subject to be automatically inferred from the branch's description.
Finally, patches 4-8 are all needed to implement branch-specific format-patch options. Although this behaviour can be replicated by the config onbranch patches, it's not a direct replacement. Consider the following:
$ git checkout foo $ git format-patch master..bar
With config onbranch, this would generate patches using foo's settings but with this patchset, we would generate patches using bar's settings, which seems more desirable and intuitive for users.
I suppose if adding a format.<branch>.* option is controversial since we won't be sure if we're adding other intermediate format keys, we could follow onbranch convention and use format.forbranch:<branch>.* as configuration keys instead.
Thanks,
Denton
Changes since v2:
* Replaced format.<branch-name>.coverSubject and --cover-subject with format.inferCoverSubject and --infer-cover-subject which reads the subject from the branch description
* Do not let git branch -d delete format.<branch-name>.* configs
* More documentation cleanup
* Taught format-patch to read format.<branch-name>.outputDirectory as well
Changes since v1:
* Used format.<branch-name>.* variables instead of branch.<branch-name>.*
Denton Liu (8):
t4014: clean up style
Doc: add more detail for git-format-patch
format-patch: infer cover letter from branch description
format-patch: move extra_headers logic later
string-list: create string_list_append_all
format-patch: read branch-specific To: and Cc: headers
format-patch: move output_directory logic later
format-patch: read branch-specific output directory
Documentation/config/format.txt | 17 +- Documentation/git-format-patch.txt | 44 +- builtin/log.c | 237 ++++++--- string-list.c | 9 + string-list.h | 7 + t/t4014-format-patch.sh | 739 +++++++++++++++++------------ 6 files changed, 667 insertions(+), 386 deletions(-)
Range-diff against v2:
1: 75474e18f4 = 1: 650f04bc04 t4014: clean up style 2: 9ae349bf8a ! 2: 14b40b1dec Doc: add more detail for git-format-patch
@@ -9,7 +9,10 @@
In addition, document the special value of --base=auto.
- Finally, while we're at it, surround option arguments with <>.
+ Next, while we're at it, surround option arguments with <>.
+
+ Finally, document the format.outputDirectory config and change
+ format.coverletter to use camelcase.
@@ -67,3 +70,25 @@
--root::
Treat the revision argument as a <revision range>, even if it
+@@
+ -------------
+ You can specify extra mail header lines to be added to each message,
+ defaults for the subject prefix and file suffix, number patches when +-outputting more than one patch, add "To" or "Cc:" headers, configure +-attachments, and sign off patches with configuration variables. ++outputting more than one patch, add "To:" or "Cc:" headers, configure ++attachments, change the patch output directory, and sign off patches ++with configuration variables.
+
+ ------------
+ [format]
+@@
+ cc = <email>
+ attach [ = mime-boundary-string ]
+ signOff = true
+- coverletter = auto
++ outputDirectory = <directory>
++ coverLetter = auto
+ ------------
+
+
3: c0403f5139 < -: ---------- format-patch: make cover letter subject configurable -: ---------- > 3: ca2b4c21c1 format-patch: infer cover letter from branch description 4: 534c6fd48a ! 4: 82a56a0d76 format-patch: move extra_headers logic later
@@ -7,10 +7,10 @@
logic later in the function so that this happens. (This patch is best viewed with git diff --color-moved.)
- Note that this logic only depends on the git_config and
+ Note that this logic only depends on git_config and
repo_init_revisions and is depended on by the patch creation logic
- which is directly below it so this move is effectively a no-op as
- no dependencies being reordered.
+ which is directly below it so this move is effectively a no-op as no
+ dependencies being reordered.
5: 491297c40a = 5: 3554164deb string-list: create string_list_append_all 6: e2c71fa593 ! 6: 6ad1b25858 format-patch: read branch-specific To: and Cc: headers
@@ -59,29 +59,20 @@
far (from config or command line).
@@
- -------------
- You can specify extra mail header lines to be added to each message,
- defaults for the subject prefix and file suffix, number patches when --outputting more than one patch, add "To" or "Cc:" headers, configure -+outputting more than one patch, add "To:" or "Cc:" headers, configure
- attachments, and sign off patches with configuration variables. -
- ------------
-@@
+ inferCoverSubject = true
------------
- In addition, for a specific branch, you can specify a custom cover --letter subject.
++In addition, for a specific branch, you can specify a custom cover
+letter subject, and add additional "To:" or "Cc:" headers.
-
- ------------
- [format "branch-name"]
- coverSubject = "subject for branch-name only"
++
++------------
++[format "branch-name"]
+ to = <email>
+ cc = <email>
- ------------
++------------
DISCUSSION
+ ----------
diff --git a/builtin/log.c b/builtin/log.c
--- a/builtin/log.c
@@ -96,7 +87,7 @@
static void add_header(const char *value)
{
@@
- return 0;
+ fprintf(rev->diffopt.file, "\n");
}
+static void add_branch_headers(struct rev_info *rev, const char *branch_name)
@@ -186,25 +177,6 @@
strbuf_addstr(&buf, extra_hdr.items[i].string); strbuf_addch(&buf, '\n');
- diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
- --- a/t/t3200-branch.sh
- +++ b/t/t3200-branch.sh
-@@
-
- test_expect_success 'test deleting branch deletes branch config' '
- git config format.my7.coverSubject "cover subject" &&
-+ git config format.my7.to "To Me <[email protected]>" &&
-+ git config format.my7.cc "Cc Me <[email protected]>" &&
- git branch -d my7 &&
- test -z "$(git config branch.my7.remote)" &&
- test -z "$(git config branch.my7.merge)" &&
- test -z "$(git config format.my7.coverSubject)"
-+ test -z "$(git config format.my7.to)" &&
-+ test -z "$(git config format.my7.cc)"
- '
-
- test_expect_success 'test deleting branch without config' ' -
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh --- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
-: ---------- > 7: 3bc1b95a4e format-patch: move output_directory logic later -: ---------- > 8: 2cf7c77f59 format-patch: read branch-specific output directory
Signature · 1 line
2.22.0.355.g3bfa262345
PATCH RESEND v3 1/8 t4014: clean up style
In Git's tests, there is typically no space between the redirection operator and the filename. Remove these spaces.
Since output is silenced when running without -v and debugging output is useful with -v, remove redirections to /dev/null.
Change here-docs from <<\EOF to <<-\EOF so that they can be indented along with the rest of the test case.
Finally, refactor to remove Git commands upstream of pipe. This way, if an invocation of a Git command fails, the return code won't be lost. Keep upstream non-Git commands since we have to assume a base level of sanity.
--- t/t4014-format-patch.sh | 614 +++++++++++++++++++++------------------- 1 file changed, 319 insertions(+), 295 deletions(-)
t/t4014-format-patch.sh +319 -295
@@ -34,7 +34,8 @@ test_expect_success setup ' git commit -m "Side changes #3 with \\n backslash-n in it." && git checkout master && - git diff-tree -p C2 | git apply --index && + git diff-tree -p C2 >patch && + git apply --index <patch && test_tick && git commit -m "Master accepts moral equivalent of #2"
@@ -77,7 +78,7 @@ test_expect_success "format-patch doesn't consider merge commits" ' git checkout -b merger master && test_tick && git merge --no-ff slave && - cnt=$(git format-patch -3 --stdout | grep "^From " | wc -l) && + cnt=$(git format-patch -3 --stdout >patch && grep "^From " patch | wc -l) && test $cnt = 3 '
@@ -85,21 +86,22 @@ test_expect_success "format-patch result applies" ' git checkout -b rebuild-0 master && git am -3 patch0 && - cnt=$(git rev-list master.. | wc -l) && - test $cnt = 2 + git rev-list master.. >list && + test_line_count = 2 list ' test_expect_success "format-patch --ignore-if-in-upstream result applies" ' git checkout -b rebuild-1 master && git am -3 patch1 && - cnt=$(git rev-list master.. | wc -l) && - test $cnt = 2 + git rev-list master.. >list && + test_line_count = 2 list ' test_expect_success 'commit did not screw up the log message' ' - git cat-file commit side | grep "^Side .* with .* backslash-n" + git cat-file commit side >actual && + grep "^Side .* with .* backslash-n" actual '
@@ -112,7 +114,8 @@ test_expect_success 'format-patch did not screw up the log message' ' test_expect_success 'replay did not screw up the log message' ' - git cat-file commit rebuild-1 | grep "^Side .* with .* backslash-n" + git cat-file commit rebuild-1 >actual && + grep "^Side .* with .* backslash-n" actual '
@@ -122,8 +125,8 @@ test_expect_success 'extra headers' ' " && git config --add format.headers "Cc: S E Cipient <[email protected]> " && - git format-patch --stdout master..side > patch2 && - sed -e "/^\$/q" patch2 > hdrs2 && + git format-patch --stdout master..side >patch2 && + sed -e "/^\$/q" patch2 >hdrs2 && grep "^To: R E Cipient <[email protected]>\$" hdrs2 && grep "^Cc: S E Cipient <[email protected]>\$" hdrs2
@@ -134,7 +137,7 @@ test_expect_success 'extra headers without newlines' ' git config --replace-all format.headers "To: R E Cipient <[email protected]>" && git config --add format.headers "Cc: S E Cipient <[email protected]>" && git format-patch --stdout master..side >patch3 && - sed -e "/^\$/q" patch3 > hdrs3 && + sed -e "/^\$/q" patch3 >hdrs3 && grep "^To: R E Cipient <[email protected]>\$" hdrs3 && grep "^Cc: S E Cipient <[email protected]>\$" hdrs3
@@ -144,8 +147,8 @@ test_expect_success 'extra headers with multiple To:s' ' git config --replace-all format.headers "To: R E Cipient <[email protected]>" && git config --add format.headers "To: S E Cipient <[email protected]>" && - git format-patch --stdout master..side > patch4 && - sed -e "/^\$/q" patch4 > hdrs4 && + git format-patch --stdout master..side >patch4 && + sed -e "/^\$/q" patch4 >hdrs4 && grep "^To: R E Cipient <[email protected]>,\$" hdrs4 && grep "^ *S E Cipient <[email protected]>\$" hdrs4 '
@@ -153,72 +156,82 @@ test_expect_success 'extra headers with multiple To:s' ' test_expect_success 'additional command line cc (ascii)' ' git config --replace-all format.headers "Cc: R E Cipient <[email protected]>" && - git format-patch --cc="S E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch5 && - grep "^Cc: R E Cipient <[email protected]>,\$" patch5 && - grep "^ *S E Cipient <[email protected]>\$" patch5 + git format-patch --cc="S E Cipient <[email protected]>" --stdout master..side >patch5 && + sed -e "/^\$/q" patch5 >hdrs5 && + grep "^Cc: R E Cipient <[email protected]>,\$" hdrs5 && + grep "^ *S E Cipient <[email protected]>\$" hdrs5 ' test_expect_failure 'additional command line cc (rfc822)' ' git config --replace-all format.headers "Cc: R E Cipient <[email protected]>" && - git format-patch --cc="S. E. Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch5 && - grep "^Cc: R E Cipient <[email protected]>,\$" patch5 && - grep "^ *\"S. E. Cipient\" <[email protected]>\$" patch5 + git format-patch --cc="S. E. Cipient <[email protected]>" --stdout master..side >patch5 && + sed -e "/^\$/q" patch5 >hdrs5 && + grep "^Cc: R E Cipient <[email protected]>,\$" hdrs5 && + grep "^ *\"S. E. Cipient\" <[email protected]>\$" hdrs5 ' test_expect_success 'command line headers' ' git config --unset-all format.headers && - git format-patch --add-header="Cc: R E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch6 && - grep "^Cc: R E Cipient <[email protected]>\$" patch6 + git format-patch --add-header="Cc: R E Cipient <[email protected]>" --stdout master..side >patch6 && + sed -e "/^\$/q" patch6 >hdrs6 && + grep "^Cc: R E Cipient <[email protected]>\$" hdrs6 ' test_expect_success 'configuration headers and command line headers' ' git config --replace-all format.headers "Cc: R E Cipient <[email protected]>" && - git format-patch --add-header="Cc: S E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch7 && - grep "^Cc: R E Cipient <[email protected]>,\$" patch7 && - grep "^ *S E Cipient <[email protected]>\$" patch7 + git format-patch --add-header="Cc: S E Cipient <[email protected]>" --stdout master..side >patch7 && + sed -e "/^\$/q" patch7 >hdrs7 && + grep "^Cc: R E Cipient <[email protected]>,\$" hdrs7 && + grep "^ *S E Cipient <[email protected]>\$" hdrs7 ' test_expect_success 'command line To: header (ascii)' ' git config --unset-all format.headers && - git format-patch --to="R E Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch8 && - grep "^To: R E Cipient <[email protected]>\$" patch8 + git format-patch --to="R E Cipient <[email protected]>" --stdout master..side >patch8 && + sed -e "/^\$/q" patch8 >hdrs8 && + grep "^To: R E Cipient <[email protected]>\$" hdrs8 ' test_expect_failure 'command line To: header (rfc822)' ' - git format-patch --to="R. E. Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch8 && - grep "^To: \"R. E. Cipient\" <[email protected]>\$" patch8 + git format-patch --to="R. E. Cipient <[email protected]>" --stdout master..side >patch8 && + sed -e "/^\$/q" patch8 >hdrs8 && + grep "^To: \"R. E. Cipient\" <[email protected]>\$" hdrs8 ' test_expect_failure 'command line To: header (rfc2047)' ' - git format-patch --to="R Ä Cipient <[email protected]>" --stdout master..side | sed -e "/^\$/q" >patch8 && - grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" patch8 + git format-patch --to="R Ä Cipient <[email protected]>" --stdout master..side >patch8 && + sed -e "/^\$/q" patch8 >hdrs8 && + grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" hdrs8 ' test_expect_success 'configuration To: header (ascii)' ' git config format.to "R E Cipient <[email protected]>" && - git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && - grep "^To: R E Cipient <[email protected]>\$" patch9 + git format-patch --stdout master..side >patch9 && + sed -e "/^\$/q" patch9 >hdrs9 && + grep "^To: R E Cipient <[email protected]>\$" hdrs9 ' test_expect_failure 'configuration To: header (rfc822)' ' git config format.to "R. E. Cipient <[email protected]>" && - git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && - grep "^To: \"R. E. Cipient\" <[email protected]>\$" patch9 + git format-patch --stdout master..side >patch9 && + sed -e "/^\$/q" patch9 >hdrs9 && + grep "^To: \"R. E. Cipient\" <[email protected]>\$" hdrs9 ' test_expect_failure 'configuration To: header (rfc2047)' ' git config format.to "R Ä Cipient <[email protected]>" && - git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && - grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" patch9 + git format-patch --stdout master..side >patch9 && + sed -e "/^\$/q" patch9 >hdrs9 && + grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <[email protected]>\$" hdrs9 ' # check_patch <patch>: Verify that <patch> looks like a half-sane
@@ -231,52 +244,52 @@ check_patch () { test_expect_success 'format.from=false' ' - git -c format.from=false format-patch --stdout master..side | - sed -e "/^\$/q" >patch && + git -c format.from=false format-patch --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && check_patch patch && - ! grep "^From: C O Mitter <[email protected]>\$" patch + ! grep "^From: C O Mitter <[email protected]>\$" hdrs ' test_expect_success 'format.from=true' ' - git -c format.from=true format-patch --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - grep "^From: C O Mitter <[email protected]>\$" patch + git -c format.from=true format-patch --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + grep "^From: C O Mitter <[email protected]>\$" hdrs ' test_expect_success 'format.from with address' ' - git -c format.from="F R Om <[email protected]>" format-patch --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - grep "^From: F R Om <[email protected]>\$" patch + git -c format.from="F R Om <[email protected]>" format-patch --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + grep "^From: F R Om <[email protected]>\$" hdrs ' test_expect_success '--no-from overrides format.from' ' - git -c format.from="F R Om <[email protected]>" format-patch --no-from --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - ! grep "^From: F R Om <[email protected]>\$" patch + git -c format.from="F R Om <[email protected]>" format-patch --no-from --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + ! grep "^From: F R Om <[email protected]>\$" hdrs ' test_expect_success '--from overrides format.from' ' - git -c format.from="F R Om <[email protected]>" format-patch --from --stdout master..side | - sed -e "/^\$/q" >patch && - check_patch patch && - ! grep "^From: F R Om <[email protected]>\$" patch + git -c format.from="F R Om <[email protected]>" format-patch --from --stdout master..side >patch && + sed -e "/^\$/q" patch >hdrs && + check_patch hdrs && + ! grep "^From: F R Om <[email protected]>\$" hdrs ' test_expect_success '--no-to overrides config.to' ' git config --replace-all format.to \ "R E Cipient <[email protected]>" && - git format-patch --no-to --stdout master..side | - sed -e "/^\$/q" >patch10 && - check_patch patch10 && - ! grep "^To: R E Cipient <[email protected]>\$" patch10 + git format-patch --no-to --stdout master..side >patch10 && + sed -e "/^\$/q" patch10 >hdrs10 && + check_patch hdrs10 && + ! grep "^To: R E Cipient <[email protected]>\$" hdrs10 ' test_expect_success '--no-to and --to replaces config.to' '
@@ -284,31 +297,31 @@ test_expect_success '--no-to and --to replaces config.to' ' git config --replace-all format.to \ "Someone <[email protected]>" && git format-patch --no-to --to="Someone Else <[email protected]>" \ - --stdout master..side | - sed -e "/^\$/q" >patch11 && - check_patch patch11 && - ! grep "^To: Someone <[email protected]>\$" patch11 && - grep "^To: Someone Else <[email protected]>\$" patch11 + --stdout master..side >patch11 && + sed -e "/^\$/q" patch11 >hdrs11 && + check_patch hdrs11 && + ! grep "^To: Someone <[email protected]>\$" hdrs11 && + grep "^To: Someone Else <[email protected]>\$" hdrs11 ' test_expect_success '--no-cc overrides config.cc' ' git config --replace-all format.cc \ "C E Cipient <[email protected]>" && - git format-patch --no-cc --stdout master..side | - sed -e "/^\$/q" >patch12 && - check_patch patch12 && - ! grep "^Cc: C E Cipient <[email protected]>\$" patch12 + git format-patch --no-cc --stdout master..side >patch12 && + sed -e "/^\$/q" patch12 >hdrs12 && + check_patch hdrs12 && + ! grep "^Cc: C E Cipient <[email protected]>\$" hdrs12 ' test_expect_success '--no-add-header overrides config.headers' ' git config --replace-all format.headers \ "Header1: B E Cipient <[email protected]>" && - git format-patch --no-add-header --stdout master..side | - sed -e "/^\$/q" >patch13 && - check_patch patch13 && - ! grep "^Header1: B E Cipient <[email protected]>\$" patch13 + git format-patch --no-add-header --stdout master..side >patch13 && + sed -e "/^\$/q" patch13 >hdrs13 && + check_patch hdrs13 && + ! grep "^Header1: B E Cipient <[email protected]>\$" hdrs13 ' test_expect_success 'multiple files' '
@@ -338,7 +351,7 @@ test_expect_success 'reroll count (-v)' ' check_threading () { expect="$1" && shift && - (git format-patch --stdout "$@"; echo $? > status.out) | + (git format-patch --stdout "$@"; echo $? >status.out) | # Prints everything between the Message-ID and In-Reply-To, # and replaces all Message-ID-lookalikes by a sequence number perl -ne '
@@ -353,12 +366,12 @@ check_threading () { print; } print "---\n" if /^From /i; - ' > actual && + ' >actual && test 0 = "$(cat status.out)" && test_cmp "$expect" actual } -cat >> expect.no-threading <<EOF +cat >>expect.no-threading <<EOF --- --- ---
@@ -369,7 +382,7 @@ test_expect_success 'no threading' ' check_threading expect.no-threading master ' -cat > expect.thread <<EOF +cat >expect.thread <<EOF --- Message-Id: <0> ---
@@ -386,7 +399,7 @@ test_expect_success 'thread' ' check_threading expect.thread --thread master ' -cat > expect.in-reply-to <<EOF +cat >expect.in-reply-to <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -406,7 +419,7 @@ test_expect_success 'thread in-reply-to' ' --thread master ' -cat > expect.cover-letter <<EOF +cat >expect.cover-letter <<EOF --- Message-Id: <0> ---
@@ -427,7 +440,7 @@ test_expect_success 'thread cover-letter' ' check_threading expect.cover-letter --cover-letter --thread master ' -cat > expect.cl-irt <<EOF +cat >expect.cl-irt <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -459,7 +472,7 @@ test_expect_success 'thread explicit shallow' ' --in-reply-to="<test.message>" --thread=shallow master ' -cat > expect.deep <<EOF +cat >expect.deep <<EOF --- Message-Id: <0> ---
@@ -477,7 +490,7 @@ test_expect_success 'thread deep' ' check_threading expect.deep --thread=deep master ' -cat > expect.deep-irt <<EOF +cat >expect.deep-irt <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -500,7 +513,7 @@ test_expect_success 'thread deep in-reply-to' ' --in-reply-to="<test.message>" master ' -cat > expect.deep-cl <<EOF +cat >expect.deep-cl <<EOF --- Message-Id: <0> ---
@@ -524,7 +537,7 @@ test_expect_success 'thread deep cover-letter' ' check_threading expect.deep-cl --cover-letter --thread=deep master ' -cat > expect.deep-cl-irt <<EOF +cat >expect.deep-cl-irt <<EOF --- Message-Id: <0> In-Reply-To: <1>
@@ -606,7 +619,7 @@ test_expect_success 'cover-letter inherits diff options' ' ' -cat > expect << EOF +cat >expect <<EOF This is an excessively long subject line for a message due to the habit some projects have of not having a short, one-line subject at the start of the commit message, but rather sticking a whole
@@ -619,12 +632,12 @@ EOF test_expect_success 'shortlog of cover-letter wraps overly-long onelines' ' git format-patch --cover-letter -2 && - sed -e "1,/A U Thor/d" -e "/^\$/q" < 0000-cover-letter.patch > output && + sed -e "1,/A U Thor/d" -e "/^\$/q" <0000-cover-letter.patch >output && test_cmp expect output ' -cat > expect << EOF +cat >expect <<EOF index $before..$after 100644 --- a/file +++ b/file
@@ -646,7 +659,7 @@ test_expect_success 'format-patch respects -U' ' ' -cat > expect << EOF +cat >expect <<EOF diff --git a/file b/file index $before..$after 100644
@@ -662,7 +675,7 @@ EOF test_expect_success 'format-patch -p suppresses stat' ' git format-patch -p -2 && - sed -e "1,/^\$/d" -e "/^+5/q" < 0001-This-is-an-excessively-long-subject-line-for-a-messa.patch > output && + sed -e "1,/^\$/d" -e "/^+5/q" <0001-This-is-an-excessively-long-subject-line-for-a-messa.patch >output && test_cmp expect output '
@@ -717,7 +730,7 @@ test_expect_success 'format-patch from a subdirectory (3)' ' ' test_expect_success 'format-patch --in-reply-to' ' - git format-patch -1 --stdout --in-reply-to "[email protected]" > patch8 && + git format-patch -1 --stdout --in-reply-to "[email protected]" >patch8 && grep "^In-Reply-To: <[email protected]>" patch8 && grep "^References: <[email protected]>" patch8 '
@@ -738,20 +751,20 @@ test_expect_success 'format-patch --notes --signoff' ' sed "1,/^---$/d" out | grep "test message" ' -echo "fatal: --name-only does not make sense" > expect.name-only -echo "fatal: --name-status does not make sense" > expect.name-status -echo "fatal: --check does not make sense" > expect.check +echo "fatal: --name-only does not make sense" >expect.name-only +echo "fatal: --name-status does not make sense" >expect.name-status +echo "fatal: --check does not make sense" >expect.check test_expect_success 'options no longer allowed for format-patch' ' - test_must_fail git format-patch --name-only 2> output && + test_must_fail git format-patch --name-only 2>output && test_i18ncmp expect.name-only output && - test_must_fail git format-patch --name-status 2> output && + test_must_fail git format-patch --name-status 2>output && test_i18ncmp expect.name-status output && - test_must_fail git format-patch --check 2> output && + test_must_fail git format-patch --check 2>output && test_i18ncmp expect.check output' test_expect_success 'format-patch --numstat should produce a patch' ' - git format-patch --numstat --stdout master..side > output && + git format-patch --numstat --stdout master..side >output && test 5 = $(grep "^diff --git a/" output | wc -l)' test_expect_success 'format-patch -- <path>' '
@@ -763,20 +776,22 @@ test_expect_success 'format-patch --ignore-if-in-upstream HEAD' ' git format-patch --ignore-if-in-upstream HEAD ' -git_version="$(git --version | sed "s/.* //")" +git_version="$(git --version >version && sed "s/.* //" version)" signature() { printf "%s\n%s\n\n" "-- " "${1:-$git_version}" } test_expect_success 'format-patch default signature' ' - git format-patch --stdout -1 | tail -n 3 >output && + git format-patch --stdout -1 >patch && + tail -n 3 patch >output && signature >expect && test_cmp expect output ' test_expect_success 'format-patch --signature' ' - git format-patch --stdout --signature="my sig" -1 | tail -n 3 >output && + git format-patch --stdout --signature="my sig" -1 >patch && + tail -n 3 patch >output && signature "my sig" >expect && test_cmp expect output '
@@ -1167,282 +1182,282 @@ append_signoff() test_expect_success 'signoff: commit with no body' ' append_signoff </dev/null >actual && - cat <<\EOF | sed "s/EOL$//" >expected && -4:Subject: [PATCH] EOL -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat <<-\EOF | sed "s/EOL$//" >expected && + 4:Subject: [PATCH] EOL + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: commit with only subject' ' echo subject | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: commit with only subject that does not end with NL' ' printf subject | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: no existing signoffs' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + body + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: no existing signoffs and no trailing NL' ' printf "subject\n\nbody" | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: some random signoff' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: my@house -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: my@house -12:Signed-off-by: C O Mitter <[email protected]> -EOF + Signed-off-by: my@house + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: my@house + 12:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: misc conforming footer elements' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: my@house -(cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709) -Tested-by: Some One <[email protected]> -Bug: 1234 -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: my@house -15:Signed-off-by: C O Mitter <[email protected]> -EOF + Signed-off-by: my@house + (cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709) + Tested-by: Some One <[email protected]> + Bug: 1234 + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: my@house + 15:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: some random signoff-alike' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body -Fooled-by-me: my@house -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -11: -12:Signed-off-by: C O Mitter <[email protected]> -EOF + body + Fooled-by-me: my@house + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 11: + 12:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: not really a signoff' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -I want to mention about Signed-off-by: here. -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:I want to mention about Signed-off-by: here. -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + I want to mention about Signed-off-by: here. + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:I want to mention about Signed-off-by: here. + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: not really a signoff (2)' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -My unfortunate -Signed-off-by: example happens to be wrapped here. -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10:Signed-off-by: example happens to be wrapped here. -11:Signed-off-by: C O Mitter <[email protected]> -EOF + My unfortunate + Signed-off-by: example happens to be wrapped here. + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10:Signed-off-by: example happens to be wrapped here. + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: valid S-o-b paragraph in the middle' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -Signed-off-by: my@house -Signed-off-by: your@house + Signed-off-by: my@house + Signed-off-by: your@house -A lot of houses. -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: my@house -10:Signed-off-by: your@house -11: -13: -14:Signed-off-by: C O Mitter <[email protected]> -EOF + A lot of houses. + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: my@house + 10:Signed-off-by: your@house + 11: + 13: + 14:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: the same signoff at the end' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: C O Mitter <[email protected]> -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + Signed-off-by: C O Mitter <[email protected]> + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: the same signoff at the end, no trailing NL' ' printf "subject\n\nSigned-off-by: C O Mitter <[email protected]>" | append_signoff >actual && - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -9:Signed-off-by: C O Mitter <[email protected]> -EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 9:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: the same signoff NOT at the end' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Signed-off-by: C O Mitter <[email protected]> -Signed-off-by: my@house -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -11:Signed-off-by: C O Mitter <[email protected]> -12:Signed-off-by: my@house -EOF + Signed-off-by: C O Mitter <[email protected]> + Signed-off-by: my@house + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 11:Signed-off-by: C O Mitter <[email protected]> + 12:Signed-off-by: my@house + EOF test_cmp expected actual ' test_expect_success 'signoff: tolerate garbage in conforming footer' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Tested-by: my@house -Some Trash -Signed-off-by: C O Mitter <[email protected]> -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -13:Signed-off-by: C O Mitter <[email protected]> -EOF + Tested-by: my@house + Some Trash + Signed-off-by: C O Mitter <[email protected]> + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 13:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: respect trailer config' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -Myfooter: x -Some Trash -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -11: -12:Signed-off-by: C O Mitter <[email protected]> -EOF + Myfooter: x + Some Trash + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 11: + 12:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual && test_config trailer.Myfooter.ifexists add && - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -Myfooter: x -Some Trash -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -11:Signed-off-by: C O Mitter <[email protected]> -EOF + Myfooter: x + Some Trash + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 11:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual ' test_expect_success 'signoff: footer begins with non-signoff without @ sign' ' - append_signoff <<\EOF >actual && -subject + append_signoff <<-\EOF >actual && + subject -body + body -Reviewed-id: Noone -Tested-by: my@house -Change-id: Ideadbeef -Signed-off-by: C O Mitter <[email protected]> -Bug: 1234 -EOF - cat >expected <<\EOF && -4:Subject: [PATCH] subject -8: -10: -14:Signed-off-by: C O Mitter <[email protected]> -EOF + Reviewed-id: Noone + Tested-by: my@house + Change-id: Ideadbeef + Signed-off-by: C O Mitter <[email protected]> + Bug: 1234 + EOF + cat >expected <<-\EOF && + 4:Subject: [PATCH] subject + 8: + 10: + 14:Signed-off-by: C O Mitter <[email protected]> + EOF test_cmp expected actual '
@@ -1458,42 +1473,42 @@ test_expect_success 'cover letter using branch description (1)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter master >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (2)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter rebuild-1~2..rebuild-1 >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (3)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter ^master rebuild-1 >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (4)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter master.. >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (5)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter -2 HEAD >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter using branch description (6)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && git format-patch --stdout --cover-letter -2 >actual && - grep hello actual >/dev/null + grep hello actual ' test_expect_success 'cover letter with nothing' '
@@ -1547,7 +1562,8 @@ test_expect_success 'format-patch format.outputDirectory option' ' test_config format.outputDirectory patches && rm -fr patches && git format-patch master..side && - test $(git rev-list master..side | wc -l) -eq $(ls patches | wc -l) + git rev-list master..side >list && + test_line_count = $(ls patches | wc -l) list ' test_expect_success 'format-patch -o overrides format.outputDirectory' '
@@ -1560,13 +1576,21 @@ test_expect_success 'format-patch -o overrides format.outputDirectory' ' test_expect_success 'format-patch --base' ' git checkout side && - git format-patch --stdout --base=HEAD~3 -1 | tail -n 7 >actual1 && - git format-patch --stdout --base=HEAD~3 HEAD~.. | tail -n 7 >actual2 && + git format-patch --stdout --base=HEAD~3 -1 >patch && + tail -n 7 patch >actual1 && + git format-patch --stdout --base=HEAD~3 HEAD~.. >patch && + tail -n 7 patch >actual2 && echo >expected && echo "base-commit: $(git rev-parse HEAD~3)" >>expected && - echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --stable | awk "{print \$1}")" >>expected && - echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --stable | awk "{print \$1}")" >>expected && - signature >> expected && + git show --patch HEAD~2 >patch && + git patch-id --stable <patch >patch.id.raw && + awk "{print \$1}" <patch.id.raw >patch.id && + echo "prerequisite-patch-id: $(cat patch.id)" >>expected && + git show --patch HEAD~1 >patch && + git patch-id --stable <patch >patch.id.raw && + awk "{print \$1}" <patch.id.raw >patch.id && + echo "prerequisite-patch-id: $(cat patch.id)" >>expected && + signature >>expected && test_cmp expected actual1 && test_cmp expected actual2 '
Signature · 1 line
2.22.0.355.g3bfa262345
PATCH RESEND v3 2/8 Doc: add more detail for git-format-patch
In reply to Denton LiuIn git-format-patch.txt, we were missing some key user information. First of all, using the --to and --cc options don't override format.to and format.cc variables, respectively. They add on to each other. Document this.
In addition, document the special value of --base=auto.
Next, while we're at it, surround option arguments with <>.
Finally, document the format.outputDirectory config and change format.coverletter to use camelcase.
--- Documentation/git-format-patch.txt | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-)
Documentation/git-format-patch.txt +16 -9
@@ -17,9 +17,9 @@ SYNOPSIS [--signature-file=<file>] [-n | --numbered | -N | --no-numbered] [--start-number <n>] [--numbered-files] - [--in-reply-to=Message-Id] [--suffix=.<sfx>] + [--in-reply-to=<Message-Id>] [--suffix=.<sfx>] [--ignore-if-in-upstream] - [--rfc] [--subject-prefix=Subject-Prefix] + [--rfc] [--subject-prefix=<Subject-Prefix>] [(--reroll-count|-v) <n>] [--to=<email>] [--cc=<email>] [--[no-]cover-letter] [--quiet] [--notes[=<ref>]]
@@ -158,7 +158,7 @@ Beware that the default for 'git send-email' is to thread emails itself. If you want `git format-patch` to take care of threading, you will want to ensure that threading is disabled for `git send-email`. ---in-reply-to=Message-Id:: +--in-reply-to=<Message-Id>:: Make the first mail (or all the mails with `--no-thread`) appear as a reply to the given Message-Id, which avoids breaking threads to provide a new patch series.
@@ -192,13 +192,17 @@ will want to ensure that threading is disabled for `git send-email`. --to=<email>:: Add a `To:` header to the email headers. This is in addition - to any configured headers, and may be used multiple times. + to any configured headers, and may be used multiple times. The + emails given will be used along with any emails given by + `format.to` configurations. The negated form `--no-to` discards all `To:` headers added so far (from config or command line). --cc=<email>:: Add a `Cc:` header to the email headers. This is in addition - to any configured headers, and may be used multiple times. + to any configured headers, and may be used multiple times. The + emails given will be used along with any emails given by + `format.cc` configurations. The negated form `--no-cc` discards all `Cc:` headers added so far (from config or command line).
@@ -309,7 +313,8 @@ you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`. --base=<commit>:: Record the base tree information to identify the state the patch series applies to. See the BASE TREE INFORMATION section - below for details. + below for details. If <commit> is equal to "auto", a base commit + is automatically chosen. --root:: Treat the revision argument as a <revision range>, even if it
@@ -325,8 +330,9 @@ CONFIGURATION ------------- You can specify extra mail header lines to be added to each message, defaults for the subject prefix and file suffix, number patches when -outputting more than one patch, add "To" or "Cc:" headers, configure -attachments, and sign off patches with configuration variables. +outputting more than one patch, add "To:" or "Cc:" headers, configure +attachments, change the patch output directory, and sign off patches +with configuration variables. ------------ [format]
@@ -338,7 +344,8 @@ attachments, and sign off patches with configuration variables. cc = <email> attach [ = mime-boundary-string ] signOff = true - coverletter = auto + outputDirectory = <directory> + coverLetter = auto ------------
Signature · 1 line
2.22.0.355.g3bfa262345
PATCH RESEND v3 3/8 format-patch: infer cover letter from branch description
In reply to Denton LiuWe used to populate the subject of the cover letter generated by git-format-patch with "*** SUBJECT HERE ***". However, if a user submits multiple patchsets, they may want to keep a consistent subject between rerolls.
If git-format-patch is run with --infer-cover-letter or format.inferCoverSubject, infer the subject for the cover letter from the top line(s) of a branch description, similar to how a subject is read from a commit message.
--- Documentation/config/format.txt | 5 +++ Documentation/git-format-patch.txt | 10 ++++++ builtin/log.c | 58 ++++++++++++++++++------------ t/t4014-format-patch.sh | 33 +++++++++++++++++ 4 files changed, 84 insertions(+), 22 deletions(-)
Documentation/config/format.txt +5 -0
@@ -36,6 +36,11 @@ format.subjectPrefix:: The default for format-patch is to output files with the '[PATCH]' subject prefix. Use this variable to change that prefix. +format.<branch-name>.inferCoverSubject:: + A boolean that controls whether or not to infer the subject for + the cover letter based on the branch's description. See the + --infer-cover-subject option in linkgit:git-format-patch[1]. + format.signature:: The default for format-patch is to output a signature containing the Git version number. Use this variable to change that default.
Documentation/git-format-patch.txt +10 -0
@@ -19,6 +19,7 @@ SYNOPSIS [--start-number <n>] [--numbered-files] [--in-reply-to=<Message-Id>] [--suffix=.<sfx>] [--ignore-if-in-upstream] + [--[no-]infer-cover-subject] [--rfc] [--subject-prefix=<Subject-Prefix>] [(--reroll-count|-v) <n>] [--to=<email>] [--cc=<email>]
@@ -170,6 +171,14 @@ will want to ensure that threading is disabled for `git send-email`. patches being generated, and any patch that matches is ignored. +--[no-]infer-cover-subject:: + Instead of using the default "*** SUBJECT HERE ***" subject for + the cover letter, infer the subject from the branch's + description. ++ +Similar to a commit message, the subject is inferred as the beginning of +the description up to and excluding the first blank line. + --subject-prefix=<Subject-Prefix>:: Instead of the standard '[PATCH]' prefix in the subject line, instead use '[<Subject-Prefix>]'. This
@@ -346,6 +355,7 @@ with configuration variables. signOff = true outputDirectory = <directory> coverLetter = auto + inferCoverSubject = true ------------
builtin/log.c +36 -22
119 lines not on this page · raw message
t/t4014-format-patch.sh +33 -0
@@ -1469,6 +1469,39 @@ test_expect_success 'format patch ignores color.ui' ' test_cmp expect actual ' +test_expect_success 'cover letter with config subject' ' + test_config branch.rebuild-1.description "config subject + +body" && + test_config format.inferCoverSubject true && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter master >actual && + grep "^Subject: \[PATCH 0/2\] config subject$" actual && + grep "^body" actual +' + +test_expect_success 'cover letter with command-line subject' ' + test_config branch.rebuild-1.description "command-line subject + +body" && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --infer-cover-subject master >actual && + grep "^Subject: \[PATCH 0/2\] command-line subject$" actual && + grep "^body" actual +' + +test_expect_success 'cover letter with command-line --no-infer-cover-subject overrides config' ' + test_config branch.rebuild-1.description "config subject + +body" && + test_config format.inferCoverSubject true && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --no-infer-cover-subject master >actual && + grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual && + grep "^config subject" actual && + grep "^body" actual +' + test_expect_success 'cover letter using branch description (1)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello &&
Signature · 1 line
2.22.0.355.g3bfa262345
PATCH RESEND v3 4/8 format-patch: move extra_headers logic later
In reply to Denton LiuIn a future patch, we need to perform the addition of To: and Cc:
to extra_headers after the branch_name logic. Simply transpose this logic later in the function so that this happens. (This patch is best viewed with git diff --color-moved.)
Note that this logic only depends on git_config and repo_init_revisions and is depended on by the patch creation logic which is directly below it so this move is effectively a no-op as no dependencies being reordered.
--- builtin/log.c | 58 +++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 29 deletions(-)
builtin/log.c +29 -29
@@ -1667,35 +1667,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) rev.subject_prefix =strbuf_detach (&sprefix,NULL ); } -for (i =0 ; i < extra_hdr.nr; i++) { -strbuf_addstr (&buf, extra_hdr.items[i].string); -strbuf_addch (&buf,'\n' ); - } - -if (extra_to.nr) -strbuf_addstr (&buf,"To: " ); -for (i =0 ; i < extra_to.nr; i++) { -if (i) -strbuf_addstr (&buf," " ); -strbuf_addstr (&buf, extra_to.items[i].string); -if (i +1 < extra_to.nr) -strbuf_addch (&buf,',' ); -strbuf_addch (&buf,'\n' ); - } - -if (extra_cc.nr) -strbuf_addstr (&buf,"Cc: " ); -for (i =0 ; i < extra_cc.nr; i++) { -if (i) -strbuf_addstr (&buf," " ); -strbuf_addstr (&buf, extra_cc.items[i].string); -if (i +1 < extra_cc.nr) -strbuf_addch (&buf,',' ); -strbuf_addch (&buf,'\n' ); - } - - rev.extra_headers =strbuf_detach (&buf,NULL ); -if (from) {if (split_ident_line (&rev.from_ident, from,strlen (from)))die (_ ("invalid ident line: %s" ), from);
@@ -1798,6 +1769,35 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } } +for (i =0 ; i < extra_hdr.nr; i++) { +strbuf_addstr (&buf, extra_hdr.items[i].string); +strbuf_addch (&buf,'\n' ); + } + +if (extra_to.nr) +strbuf_addstr (&buf,"To: " ); +for (i =0 ; i < extra_to.nr; i++) { +if (i) +strbuf_addstr (&buf," " ); +strbuf_addstr (&buf, extra_to.items[i].string); +if (i +1 < extra_to.nr) +strbuf_addch (&buf,',' ); +strbuf_addch (&buf,'\n' ); + } + +if (extra_cc.nr) +strbuf_addstr (&buf,"Cc: " ); +for (i =0 ; i < extra_cc.nr; i++) { +if (i) +strbuf_addstr (&buf," " ); +strbuf_addstr (&buf, extra_cc.items[i].string); +if (i +1 < extra_cc.nr) +strbuf_addch (&buf,',' ); +strbuf_addch (&buf,'\n' ); + } + + rev.extra_headers =strbuf_detach (&buf,NULL ); +/* * We cannot move this anywhere earlier because we do want to * know if --root was given explicitly from the command line.
Signature · 1 line
2.22.0.355.g3bfa262345
PATCH RESEND v3 6/8 format-patch: read branch-specific To: and Cc: headers
In reply to Denton LiuIf a user wishes to keep track of whom to Cc: on individual patchsets, they must manually keep track of each recipient and fill it in with the --cc option on git-format-patch each time. However, on the Git mailing list, Cc:'s are typically never dropped. As a result, it would be nice to have a method to keep track of recipients on a per-branch basis.
Currently, git-format-patch gets its To: headers from the --to options and the format.to config variable. The Cc: header is derived similarly.
In addition to the above, read To: and Cc: headers from format.<branch-name>.to and format.<branch-name>.cc so that users can have branch-specific configuration options.
--- Documentation/config/format.txt | 7 +- Documentation/git-format-patch.txt | 12 +++- builtin/log.c | 63 +++++++++++++++-- t/t4014-format-patch.sh | 108 +++++++++++++++++++++++------ 4 files changed, 162 insertions(+), 28 deletions(-)
Documentation/config/format.txt +5 -2
@@ -28,9 +28,12 @@ format.headers:: format.to:: format.cc:: +format.<branch-name>.to:: +format.<branch-name>.cc:: Additional recipients to include in a patch to be submitted - by mail. See the --to and --cc options in - linkgit:git-format-patch[1]. + by mail. For the <branch-name> options, the recipients are only + included if patches are generated for the given <branch-name>. + See the --to and --cc options in linkgit:git-format-patch[1]. format.subjectPrefix:: The default for format-patch is to output files with the '[PATCH]'
Documentation/git-format-patch.txt +10 -2
@@ -203,7 +203,7 @@ the description up to and excluding the first blank line. Add a `To:` header to the email headers. This is in addition to any configured headers, and may be used multiple times. The emails given will be used along with any emails given by - `format.to` configurations. + `format.to` and `format.<branch-name>.to` configurations. The negated form `--no-to` discards all `To:` headers added so far (from config or command line).
@@ -211,7 +211,7 @@ the description up to and excluding the first blank line. Add a `Cc:` header to the email headers. This is in addition to any configured headers, and may be used multiple times. The emails given will be used along with any emails given by - `format.cc` configurations. + `format.cc` and `format.<branch-name>.cc` configurations. The negated form `--no-cc` discards all `Cc:` headers added so far (from config or command line).
@@ -358,6 +358,14 @@ with configuration variables. inferCoverSubject = true ------------ +In addition, for a specific branch, you can specify a custom cover +letter subject, and add additional "To:" or "Cc:" headers. + +------------ +[format "branch-name"] + to = <email> + cc = <email> +------------ DISCUSSION ----------
builtin/log.c +59 -4
95 lines not on this page · raw message
t/t4014-format-patch.sh +88 -20
157 lines not on this page · raw message
Signature · 1 line
2.22.0.355.g3bfa262345
PATCH RESEND v3 5/8 string-list: create string_list_append_all
In reply to Denton LiuIn a future patch, we'll need to take one string_list and append it to the end of another. Create the string_list_append_all function which does this.
--- string-list.c | 9 +++++++++ string-list.h | 7 +++++++ 2 files changed, 16 insertions(+)
string-list.c +9 -0
@@ -215,6 +215,15 @@ struct string_list_item *string_list_append(struct string_list *list, list->strdup_strings ? xstrdup(string) : (char *)string); } +void string_list_append_all (struct string_list *list, +const struct string_list *append_list) +{ +struct string_list_item *item; +ALLOC_GROW (list->items, list->nr + append_list->nr, list->alloc); +for_each_string_list_item (item, append_list) +string_list_append (list, item->string); +} +/* * Encapsulate the compare function pointer because ISO C99 forbids * casting from void * to a function pointer and vice versa.
string-list.h +7 -0
@@ -208,6 +208,13 @@ struct string_list_item *string_list_append(struct string_list *list, const char*/ struct string_list_item *string_list_append_nodup (struct string_list *list,char *string); +/** +* Add all strings in append_list to list. If list->strdup_string is +* set, then each string is copied; otherwise the new string_list_entry +* refers to the entry in the append_list. +*/ +void string_list_append_all (struct string_list *list,const struct string_list *append_list); +/** * Sort the list's entries by string value in `strcmp()` order. */
Signature · 1 line
2.22.0.355.g3bfa262345
PATCH RESEND v3 8/8 format-patch: read branch-specific output directory
In reply to Denton LiuIf a user wishes to have a per-branch output directory for patches, they must manually specify this on the command-line with -o for each invocation of format-patch. However, this can be cumbersome for a user to keep track of.
Read format.<branch-name>.outputDirectory to give a branch-specific output directory that would override format.outputDirectory.
--- Documentation/config/format.txt | 5 ++++- Documentation/git-format-patch.txt | 3 ++- builtin/log.c | 26 ++++++++++++++++++++++++-- t/t4014-format-patch.sh | 18 +++++++++++++++--- 4 files changed, 45 insertions(+), 7 deletions(-)
Documentation/config/format.txt +4 -1
@@ -87,8 +87,11 @@ format.coverLetter:: generate a cover-letter only when there's more than one patch. format.outputDirectory:: +format.<branch-name>.outputDirectory:: Set a custom directory to store the resulting files instead of the - current working directory. + current working directory. If patches are being generated for + <branch-name>, the latter option takes priority if it exists, + otherwise we will fallback to the former. format.useAutoBase:: A boolean value which lets you enable the `--base=auto` option of
Documentation/git-format-patch.txt +2 -1
@@ -359,12 +359,13 @@ with configuration variables. ------------ In addition, for a specific branch, you can add additional "To:" or -"Cc:" headers. +"Cc:" headers and change the patch output directory. ------------ [format "branch-name"] to = <email> cc = <email> + outputDirectory = <directory> ------------ DISCUSSION
builtin/log.c +24 -2
@@ -1023,6 +1023,24 @@ static void show_diffstat(struct rev_info *rev,fprintf (rev->diffopt.file,"\n" ); } +static const char *get_branch_output_dir (struct rev_info *rev,const char *branch_name) +{ +struct strbuf buf =STRBUF_INIT ; +const char *output_directory; + +if (!branch_name) + branch_name =find_branch_name (rev); + +if (!branch_name || !*branch_name) +return NULL ; + +strbuf_addf (&buf,"format.%s.outputdirectory" , branch_name); +git_config_get_string_const (buf.buf, &output_directory); +strbuf_release (&buf); + +return output_directory; +} +static void add_branch_headers (struct rev_info *rev,const char *branch_name) {struct strbuf buf =STRBUF_INIT ;
@@ -1804,8 +1822,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } } -if (!output_directory && !use_stdout) - output_directory = config_output_directory; +if (!use_stdout) { +if (!output_directory) + output_directory =get_branch_output_dir (&rev, branch_name); +if (!output_directory) + output_directory = config_output_directory; + }if (!use_stdout) output_directory =set_outdir (prefix, output_directory);
t/t4014-format-patch.sh +15 -3
@@ -1667,12 +1667,24 @@ test_expect_success 'format-patch format.outputDirectory option' ' test_line_count = $(ls patches | wc -l) list ' -test_expect_success 'format-patch -o overrides format.outputDirectory' ' +test_expect_success 'format-patch format.side.outputDirectory option overrides format.outputDirectory' ' test_config format.outputDirectory patches && - rm -fr patches patchset && + test_config format.side.outputDirectory sidepatches && + rm -fr patches sidepatches && + git format-patch master..side && + git rev-list master..side >list && + test_path_is_missing patches && + test_line_count = $(ls sidepatches | wc -l) list +' + +test_expect_success 'format-patch -o overrides format.outputDirectory and format.side.outputDirectory' ' + test_config format.outputDirectory patches && + test_config format.side.outputDirectory sidepatches && + rm -fr patches sidepatches patchset && git format-patch master..side -o patchset && test_path_is_missing patches && - test_path_is_dir patchset + test_path_is_missing sidepatches && + test_line_count = $(ls patchset | wc -l) list ' test_expect_success 'format-patch --base' '
Signature · 1 line
2.22.0.355.g3bfa262345
PATCH RESEND v3 7/8 format-patch: move output_directory logic later
In reply to Denton LiuIn a future patch, we need to create the output_directory after the branch_name logic. Simply transpose this logic later in the function so that this happens. (This patch is best viewed with git diff --color-moved.)
Note that this logic only depends on git_config and the parseopt logic and is depended on by the patch creation logic which is directly below it so this move is effectively a no-op as no dependencies being reordered.
--- Documentation/git-format-patch.txt | 4 ++-- builtin/log.c | 36 +++++++++++++++--------------- 2 files changed, 20 insertions(+), 20 deletions(-)
Documentation/git-format-patch.txt +2 -2
@@ -358,8 +358,8 @@ with configuration variables. inferCoverSubject = true ------------ -In addition, for a specific branch, you can specify a custom cover -letter subject, and add additional "To:" or "Cc:" headers. +In addition, for a specific branch, you can add additional "To:" or +"Cc:" headers. ------------ [format "branch-name"]
builtin/log.c +18 -18
@@ -1771,24 +1771,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)if (rev.show_notes)init_display_notes (&rev.notes_opt); -if (!output_directory && !use_stdout) - output_directory = config_output_directory; - -if (!use_stdout) - output_directory =set_outdir (prefix, output_directory); -else -setup_pager (); - -if (output_directory) { -if (rev.diffopt.use_color !=GIT_COLOR_ALWAYS ) - rev.diffopt.use_color =GIT_COLOR_NEVER ; -if (use_stdout) -die (_ ("standard output, or directory, which one?" )); -if (mkdir (output_directory,0777 ) <0 && errno !=EEXIST ) -die_errno (_ ("could not create directory '%s'" ), - output_directory); - } -if (rev.pending.nr ==1 ) {int check_head =0 ;
@@ -1822,6 +1804,24 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } } +if (!output_directory && !use_stdout) + output_directory = config_output_directory; + +if (!use_stdout) + output_directory =set_outdir (prefix, output_directory); +else +setup_pager (); + +if (output_directory) { +if (rev.diffopt.use_color !=GIT_COLOR_ALWAYS ) + rev.diffopt.use_color =GIT_COLOR_NEVER ; +if (use_stdout) +die (_ ("standard output, or directory, which one?" )); +if (mkdir (output_directory,0777 ) <0 && errno !=EEXIST ) +die_errno (_ ("could not create directory '%s'" ), + output_directory); + } +add_branch_headers (&rev, branch_name);for (i =0 ; i < extra_hdr.nr; i++) {
Signature · 1 line
2.22.0.355.g3bfa262345
v6 cover format-patch: learn --infer-cover-subject option (also t4014 cleanup)
In reply to Denton LiuCurrently, format-patch only puts "*** SUBJECT HERE ***" when a cover letter is generated. However, it is already smart enough to be able to populate the cover letter with the branch description so there's no reason why it cannot populate the subject as well.
Teach format-patch the --infer-cover-subject option and corresponding format.inferCoverSubject configuration option which will read the subject from the branch description using the same rules as for a commit message (that is, it will expect a subject line followed by a blank line).
This was based on patches 1-3 of an earlier patchset I sent[1].
Changes since v5:
* Remove speculation in log message of 1/3
* Rename pp_from_desc() to prepare_cover_text()
Changes since v4:
* Modify 1/3 to more closely reflect intent of the original author
* Incorporate Junio's suggestions into the documentation
* Extract branch desc logic into pp_from_desc()
* Fix broken tests
Changes since v3:
* Change --infer-cover-subject to --cover-from-description
* No more test cleanup patches (they were merged in 'dl/format-patch-doc-test-cleanup')
Changes since v2:
* Break 1/4 into many different patches (one per paragraph of the original patch)
* Incorporate Eric's documentation/commit message suggestions
Changes since v1:
* Incorporate Eric's suggestions for cleanup in all patches
* Add patch 3/4 to make it clear what is the default value for format.coverLetter (since format.inferCoverSubject was borrowed from this config but it also did not state what the default value was)
* In 1/4, rename all instances of "expected" to "expect"
[1]: https://public-inbox.org/git/[email protected]/
Denton Liu (3):
format-patch: replace erroneous and condition
format-patch: use enum variables
format-patch: teach --cover-from-description option
Documentation/config/format.txt | 6 + Documentation/git-format-patch.txt | 22 ++++ builtin/log.c | 125 +++++++++++++++------ t/t4014-format-patch.sh | 172 +++++++++++++++++++++++++++++ t/t9902-completion.sh | 5 +- 5 files changed, 296 insertions(+), 34 deletions(-)
Range-diff against v5:
1: f89e56545b ! 1: 9d41068e73 format-patch: change erroneous and condition
@@ Metadata
Author: Denton Liu <[email protected]>
## Commit message ##
- format-patch: change erroneous and condition
+ format-patch: replace erroneous and condition
Commit 30984ed2e9 (format-patch: support deep threading, 2009-02-19), introduced the following lines:
@@ Commit message
thread = git_config_bool(var, value) && THREAD_SHALLOW;
Since git_config_bool() returns a bool, the trailing && THREAD_SHALLOW
- is a no-op.
-
- In Python, x and y is equivalent to y if x else x[1]. Since this
- seems to be a Python-ism that's mistakenly leaked into our code, convert
- this to the equivalent C expression.
-
- [1]: https://docs.python.org/3/reference/expressions.html#boolean-operations
-
- Signed-off-by: Denton Liu <[email protected]>
- Signed-off-by: Junio C Hamano <[email protected]>
+ is a no-op. Replace this errorneous and condition with a ternary
+ statement so that it is clear what the configured value is when a
+ boolean is given.
## builtin/log.c ##
@@ builtin/log.c: static int git_format_config(const char *var, const char *value, void *cb)
2: 1fe780b5a4 = 2: 821e706bae format-patch: use enum variables
3: d5cd34a44b ! 3: 42b4a60fd2 format-patch: teach --cover-from-description option
@@ builtin/log.c: static void show_diffstat(struct rev_info *rev,
fprintf(rev->diffopt.file, "\n");
}
-+static void pp_from_desc(struct pretty_print_context *pp,
-+ const char *branch_name,
-+ struct strbuf *sb,
-+ const char *encoding,
-+ int need_8bit_cte)
++static void prepare_cover_text(struct pretty_print_context *pp,
++ const char *branch_name,
++ struct strbuf *sb,
++ const char *encoding,
++ int need_8bit_cte)
+{
+ const char *subject = "*** SUBJECT HERE ***";
+ const char *body = "*** BLURB HERE ***";
@@ builtin/log.c: static void make_cover_letter(struct rev_info *rev, int use_stdou
- pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte);
- pp_remainder(&pp, &msg, &sb, 0);
- add_branch_description(&sb, branch_name);
-+ pp_from_desc(&pp, branch_name, &sb, encoding, need_8bit_cte);
++ prepare_cover_text(&pp, branch_name, &sb, encoding, need_8bit_cte);
fprintf(rev->diffopt.file, "%s\n", sb.buf);
strbuf_release(&sb);Signature · 1 line
2.23.0.17.gd2208d9060
PATCH v6 1/3 format-patch: replace erroneous and condition
Commit 30984ed2e9 (format-patch: support deep threading, 2009-02-19), introduced the following lines:
#define THREAD_SHALLOW 1 [...] thread = git_config_bool(var, value) && THREAD_SHALLOW;
Since git_config_bool() returns a bool, the trailing && THREAD_SHALLOW is a no-op. Replace this errorneous and condition with a ternary statement so that it is clear what the configured value is when a boolean is given.
--- builtin/log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
builtin/log.c +1 -1
@@ -835,7 +835,7 @@ static int git_format_config(const char *var, const char *value, void *cb) thread =THREAD_SHALLOW ;return 0 ; } - thread =git_config_bool (var, value) &&THREAD_SHALLOW ; + thread =git_config_bool (var, value) ?THREAD_SHALLOW :THREAD_UNSET ;return 0 ; }if (!strcmp (var,"format.signoff" )) {
Signature · 1 line
2.23.0.17.gd2208d9060
PATCH v6 2/3 format-patch: use enum variables
In reply to Denton LiuBefore, thread and config_cover_letter were defined as ints even though they behaved as enums. Define actual enums and change these variables to use these new definitions.
--- builtin/log.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-)
builtin/log.c +17 -13
@@ -764,24 +764,28 @@ static void add_header(const char *value) item->string[len] ='\0' ; } -#define THREAD_SHALLOW 1 -#define THREAD_DEEP 2 -static int thread; +enum cover_setting { +COVER_UNSET , +COVER_OFF , +COVER_ON , +COVER_AUTO +}; + +enum thread_level { +THREAD_UNSET , +THREAD_SHALLOW , +THREAD_DEEP +}; + +static enum thread_level thread;static int do_signoff;static int base_auto;static char *from;static const char *signature = git_version_string;static const char *signature_file; -static int config_cover_letter; +static enum cover_setting config_cover_letter;static const char *config_output_directory; -enum { -COVER_UNSET , -COVER_OFF , -COVER_ON , -COVER_AUTO -}; -static int git_format_config (const char *var,const char *value,void *cb) {struct rev_info *rev = cb;
@@ -1248,9 +1252,9 @@ static int output_directory_callback(const struct option *opt, const char *arg,static int thread_callback (const struct option *opt,const char *arg,int unset) { -int *thread = (int *)opt->value; +enum thread_level *thread = (enum thread_level *)opt->value;if (unset) - *thread =0 ; + *thread =THREAD_UNSET ;else if (!arg || !strcmp (arg,"shallow" )) *thread =THREAD_SHALLOW ;else if (!strcmp (arg,"deep" ))
Signature · 1 line
2.23.0.17.gd2208d9060
PATCH v6 3/3 format-patch: teach --cover-from-description option
In reply to Denton LiuBefore, when format-patch generated a cover letter, only the body would be populated with a branch's description while the subject would be populated with placeholder text. However, users may want to have the subject of their cover letter automatically populated in the same way.
Teach format-patch to accept the --cover-from-description option and corresponding format.coverFromDescription config, allowing users to populate different parts of the cover letter (including the subject now).
--- Documentation/config/format.txt | 6 + Documentation/git-format-patch.txt | 22 ++++ builtin/log.c | 95 ++++++++++++---- t/t4014-format-patch.sh | 172 +++++++++++++++++++++++++++++ t/t9902-completion.sh | 5 +- 5 files changed, 279 insertions(+), 21 deletions(-)
Documentation/config/format.txt +6 -0
@@ -36,6 +36,12 @@ format.subjectPrefix:: The default for format-patch is to output files with the '[PATCH]' subject prefix. Use this variable to change that prefix. +format.coverFromDescription:: + The default mode for format-patch to determine which parts of + the cover letter will be populated using the branch's + description. See the `--cover-from-description` option in + linkgit:git-format-patch[1]. + format.signature:: The default for format-patch is to output a signature containing the Git version number. Use this variable to change that default.
Documentation/git-format-patch.txt +22 -0
@@ -19,6 +19,7 @@ SYNOPSIS [--start-number <n>] [--numbered-files] [--in-reply-to=<message id>] [--suffix=.<sfx>] [--ignore-if-in-upstream] + [--cover-from-description=<mode>] [--rfc] [--subject-prefix=<subject prefix>] [(--reroll-count|-v) <n>] [--to=<email>] [--cc=<email>]
@@ -171,6 +172,26 @@ will want to ensure that threading is disabled for `git send-email`. patches being generated, and any patch that matches is ignored. +--cover-from-description=<mode>:: + Controls which parts of the cover letter will be automatically + populated using the branch's description. ++ +If `<mode>` is `message` or `default`, the cover letter subject will be +populated with placeholder text. The body of the cover letter will be +populated with the branch's description. This is the default mode when +no configuration nor command line option is specified. ++ +If `<mode>` is `subject`, the first paragraph of the branch description will +populate the cover letter subject. The remainder of the description will +populate the body of the cover letter. ++ +If `<mode>` is `auto`, if the first paragraph of the branch description +is greater than 100 bytes, then the mode will be `message`, otherwise +`subject` will be used. ++ +If `<mode>` is `none`, both the cover letter subject and body will be +populated with placeholder text. + --subject-prefix=<subject prefix>:: Instead of the standard '[PATCH]' prefix in the subject line, instead use '[<subject prefix>]'. This
@@ -347,6 +368,7 @@ with configuration variables. signOff = true outputDirectory = <directory> coverLetter = auto + coverFromDescription = auto ------------
builtin/log.c +75 -20
166 lines not on this page · raw message
t/t4014-format-patch.sh +172 -0
178 lines not on this page · raw message
t/t9902-completion.sh +4 -1
@@ -1548,7 +1548,10 @@ test_expect_success 'complete tree filename with metacharacters' ' ' test_expect_success PERL 'send-email' ' - test_completion "git send-email --cov" "--cover-letter " && + test_completion "git send-email --cov" <<-\EOF && + --cover-from-description=Z + --cover-letter Z + EOF test_completion "git send-email ma" "master " '
Signature · 1 line
2.23.0.17.gd2208d9060
Re: [PATCH v6 0/3] format-patch: learn --infer-cover-subject option (also t4014 cleanup)
In reply to Denton LiuThanks. I think we are ready for 'next'.