mirror of
https://github.com/git/git.git
synced 2026-02-25 17:33:34 +00:00
Merge branch 'bc/append-signed-off-by'
Consolidate codepaths that inspect log-message-to-be and decide to add a new Signed-off-by line in various commands. * bc/append-signed-off-by: git-commit: populate the edit buffer with 2 blank lines before s-o-b Unify appending signoff in format-patch, commit and sequencer format-patch: update append_signoff prototype t4014: more tests about appending s-o-b lines sequencer.c: teach append_signoff to avoid adding a duplicate newline sequencer.c: teach append_signoff how to detect duplicate s-o-b sequencer.c: always separate "(cherry picked from" from commit body sequencer.c: require a conforming footer to be preceded by a blank line sequencer.c: recognize "(cherry picked from ..." as part of s-o-b footer t/t3511: add some tests of 'cherry-pick -s' functionality t/test-lib-functions.sh: allow to specify the tag name to test_commit commit, cherry-pick -s: remove broken support for multiline rfc2822 fields sequencer.c: rework search for start of footer to improve clarity
This commit is contained in:
219
t/t3511-cherry-pick-x.sh
Executable file
219
t/t3511-cherry-pick-x.sh
Executable file
@@ -0,0 +1,219 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='Test cherry-pick -x and -s'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
pristine_detach () {
|
||||
git cherry-pick --quit &&
|
||||
git checkout -f "$1^0" &&
|
||||
git read-tree -u --reset HEAD &&
|
||||
git clean -d -f -f -q -x
|
||||
}
|
||||
|
||||
mesg_one_line='base: commit message'
|
||||
|
||||
mesg_no_footer="$mesg_one_line
|
||||
|
||||
OneWordBodyThatsNotA-S-o-B"
|
||||
|
||||
mesg_with_footer="$mesg_no_footer
|
||||
|
||||
Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
|
||||
Signed-off-by: A.U. Thor <author@example.com>
|
||||
Signed-off-by: B.U. Thor <buthor@example.com>"
|
||||
|
||||
mesg_broken_footer="$mesg_no_footer
|
||||
|
||||
The signed-off-by string should begin with the words Signed-off-by followed
|
||||
by a colon and space, and then the signers name and email address. e.g.
|
||||
Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
|
||||
|
||||
mesg_with_footer_sob="$mesg_with_footer
|
||||
Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
|
||||
|
||||
mesg_with_cherry_footer="$mesg_with_footer_sob
|
||||
(cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709)
|
||||
Tested-by: C.U. Thor <cuthor@example.com>"
|
||||
|
||||
|
||||
test_expect_success setup '
|
||||
git config advice.detachedhead false &&
|
||||
echo unrelated >unrelated &&
|
||||
git add unrelated &&
|
||||
test_commit initial foo a &&
|
||||
test_commit "$mesg_one_line" foo b mesg-one-line &&
|
||||
git reset --hard initial &&
|
||||
test_commit "$mesg_no_footer" foo b mesg-no-footer &&
|
||||
git reset --hard initial &&
|
||||
test_commit "$mesg_broken_footer" foo b mesg-broken-footer &&
|
||||
git reset --hard initial &&
|
||||
test_commit "$mesg_with_footer" foo b mesg-with-footer &&
|
||||
git reset --hard initial &&
|
||||
test_commit "$mesg_with_footer_sob" foo b mesg-with-footer-sob &&
|
||||
git reset --hard initial &&
|
||||
test_commit "$mesg_with_cherry_footer" foo b mesg-with-cherry-footer &&
|
||||
pristine_detach initial &&
|
||||
test_commit conflicting unrelated
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick -x inserts blank line after one line subject' '
|
||||
pristine_detach initial &&
|
||||
sha1=`git rev-parse mesg-one-line^0` &&
|
||||
git cherry-pick -x mesg-one-line &&
|
||||
cat <<-EOF >expect &&
|
||||
$mesg_one_line
|
||||
|
||||
(cherry picked from commit $sha1)
|
||||
EOF
|
||||
git log -1 --pretty=format:%B >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick -s inserts blank line after one line subject' '
|
||||
pristine_detach initial &&
|
||||
git cherry-pick -s mesg-one-line &&
|
||||
cat <<-EOF >expect &&
|
||||
$mesg_one_line
|
||||
|
||||
Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
|
||||
EOF
|
||||
git log -1 --pretty=format:%B >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick -s inserts blank line after non-conforming footer' '
|
||||
pristine_detach initial &&
|
||||
git cherry-pick -s mesg-broken-footer &&
|
||||
cat <<-EOF >expect &&
|
||||
$mesg_broken_footer
|
||||
|
||||
Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
|
||||
EOF
|
||||
git log -1 --pretty=format:%B >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick -x inserts blank line when conforming footer not found' '
|
||||
pristine_detach initial &&
|
||||
sha1=`git rev-parse mesg-no-footer^0` &&
|
||||
git cherry-pick -x mesg-no-footer &&
|
||||
cat <<-EOF >expect &&
|
||||
$mesg_no_footer
|
||||
|
||||
(cherry picked from commit $sha1)
|
||||
EOF
|
||||
git log -1 --pretty=format:%B >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick -s inserts blank line when conforming footer not found' '
|
||||
pristine_detach initial &&
|
||||
git cherry-pick -s mesg-no-footer &&
|
||||
cat <<-EOF >expect &&
|
||||
$mesg_no_footer
|
||||
|
||||
Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
|
||||
EOF
|
||||
git log -1 --pretty=format:%B >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick -x -s inserts blank line when conforming footer not found' '
|
||||
pristine_detach initial &&
|
||||
sha1=`git rev-parse mesg-no-footer^0` &&
|
||||
git cherry-pick -x -s mesg-no-footer &&
|
||||
cat <<-EOF >expect &&
|
||||
$mesg_no_footer
|
||||
|
||||
(cherry picked from commit $sha1)
|
||||
Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
|
||||
EOF
|
||||
git log -1 --pretty=format:%B >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick -s adds sob when last sob doesnt match committer' '
|
||||
pristine_detach initial &&
|
||||
git cherry-pick -s mesg-with-footer &&
|
||||
cat <<-EOF >expect &&
|
||||
$mesg_with_footer
|
||||
Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
|
||||
EOF
|
||||
git log -1 --pretty=format:%B >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick -x -s adds sob when last sob doesnt match committer' '
|
||||
pristine_detach initial &&
|
||||
sha1=`git rev-parse mesg-with-footer^0` &&
|
||||
git cherry-pick -x -s mesg-with-footer &&
|
||||
cat <<-EOF >expect &&
|
||||
$mesg_with_footer
|
||||
(cherry picked from commit $sha1)
|
||||
Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
|
||||
EOF
|
||||
git log -1 --pretty=format:%B >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick -s refrains from adding duplicate trailing sob' '
|
||||
pristine_detach initial &&
|
||||
git cherry-pick -s mesg-with-footer-sob &&
|
||||
cat <<-EOF >expect &&
|
||||
$mesg_with_footer_sob
|
||||
EOF
|
||||
git log -1 --pretty=format:%B >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick -x -s adds sob even when trailing sob exists for committer' '
|
||||
pristine_detach initial &&
|
||||
sha1=`git rev-parse mesg-with-footer-sob^0` &&
|
||||
git cherry-pick -x -s mesg-with-footer-sob &&
|
||||
cat <<-EOF >expect &&
|
||||
$mesg_with_footer_sob
|
||||
(cherry picked from commit $sha1)
|
||||
Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
|
||||
EOF
|
||||
git log -1 --pretty=format:%B >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick -x treats "(cherry picked from..." line as part of footer' '
|
||||
pristine_detach initial &&
|
||||
sha1=`git rev-parse mesg-with-cherry-footer^0` &&
|
||||
git cherry-pick -x mesg-with-cherry-footer &&
|
||||
cat <<-EOF >expect &&
|
||||
$mesg_with_cherry_footer
|
||||
(cherry picked from commit $sha1)
|
||||
EOF
|
||||
git log -1 --pretty=format:%B >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick -s treats "(cherry picked from..." line as part of footer' '
|
||||
pristine_detach initial &&
|
||||
git cherry-pick -s mesg-with-cherry-footer &&
|
||||
cat <<-EOF >expect &&
|
||||
$mesg_with_cherry_footer
|
||||
Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
|
||||
EOF
|
||||
git log -1 --pretty=format:%B >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick -x -s treats "(cherry picked from..." line as part of footer' '
|
||||
pristine_detach initial &&
|
||||
sha1=`git rev-parse mesg-with-cherry-footer^0` &&
|
||||
git cherry-pick -x -s mesg-with-cherry-footer &&
|
||||
cat <<-EOF >expect &&
|
||||
$mesg_with_cherry_footer
|
||||
(cherry picked from commit $sha1)
|
||||
Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
|
||||
EOF
|
||||
git log -1 --pretty=format:%B >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -972,6 +972,268 @@ test_expect_success 'empty subject prefix does not have extra space' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
append_signoff()
|
||||
{
|
||||
C=$(git commit-tree HEAD^^{tree} -p HEAD) &&
|
||||
git format-patch --stdout --signoff $C^..$C >append_signoff.patch &&
|
||||
sed -n -e "1,/^---$/p" append_signoff.patch |
|
||||
egrep -n "^Subject|Sign|^$"
|
||||
}
|
||||
|
||||
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 <committer@example.com>
|
||||
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 <committer@example.com>
|
||||
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 <committer@example.com>
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'signoff: no existing signoffs' '
|
||||
append_signoff <<\EOF >actual &&
|
||||
subject
|
||||
|
||||
body
|
||||
EOF
|
||||
cat >expected <<\EOF &&
|
||||
4:Subject: [PATCH] subject
|
||||
8:
|
||||
10:
|
||||
11:Signed-off-by: C O Mitter <committer@example.com>
|
||||
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 <committer@example.com>
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'signoff: some random signoff' '
|
||||
append_signoff <<\EOF >actual &&
|
||||
subject
|
||||
|
||||
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 <committer@example.com>
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'signoff: misc conforming footer elements' '
|
||||
append_signoff <<\EOF >actual &&
|
||||
subject
|
||||
|
||||
body
|
||||
|
||||
Signed-off-by: my@house
|
||||
(cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709)
|
||||
Tested-by: Some One <someone@example.com>
|
||||
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 <committer@example.com>
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'signoff: some random signoff-alike' '
|
||||
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 <committer@example.com>
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'signoff: not really a signoff' '
|
||||
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 <committer@example.com>
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'signoff: not really a signoff (2)' '
|
||||
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:
|
||||
12:Signed-off-by: C O Mitter <committer@example.com>
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'signoff: valid S-o-b paragraph in the middle' '
|
||||
append_signoff <<\EOF >actual &&
|
||||
subject
|
||||
|
||||
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 <committer@example.com>
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'signoff: the same signoff at the end' '
|
||||
append_signoff <<\EOF >actual &&
|
||||
subject
|
||||
|
||||
body
|
||||
|
||||
Signed-off-by: C O Mitter <committer@example.com>
|
||||
EOF
|
||||
cat >expected <<\EOF &&
|
||||
4:Subject: [PATCH] subject
|
||||
8:
|
||||
10:
|
||||
11:Signed-off-by: C O Mitter <committer@example.com>
|
||||
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 <committer@example.com>" |
|
||||
append_signoff >actual &&
|
||||
cat >expected <<\EOF &&
|
||||
4:Subject: [PATCH] subject
|
||||
8:
|
||||
9:Signed-off-by: C O Mitter <committer@example.com>
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'signoff: the same signoff NOT at the end' '
|
||||
append_signoff <<\EOF >actual &&
|
||||
subject
|
||||
|
||||
body
|
||||
|
||||
Signed-off-by: C O Mitter <committer@example.com>
|
||||
Signed-off-by: my@house
|
||||
EOF
|
||||
cat >expected <<\EOF &&
|
||||
4:Subject: [PATCH] subject
|
||||
8:
|
||||
10:
|
||||
11:Signed-off-by: C O Mitter <committer@example.com>
|
||||
12:Signed-off-by: my@house
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'signoff: detect garbage in non-conforming footer' '
|
||||
append_signoff <<\EOF >actual &&
|
||||
subject
|
||||
|
||||
body
|
||||
|
||||
Tested-by: my@house
|
||||
Some Trash
|
||||
Signed-off-by: C O Mitter <committer@example.com>
|
||||
EOF
|
||||
cat >expected <<\EOF &&
|
||||
4:Subject: [PATCH] subject
|
||||
8:
|
||||
10:
|
||||
13:Signed-off-by: C O Mitter <committer@example.com>
|
||||
14:
|
||||
15:Signed-off-by: C O Mitter <committer@example.com>
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'signoff: footer begins with non-signoff without @ sign' '
|
||||
append_signoff <<\EOF >actual &&
|
||||
subject
|
||||
|
||||
body
|
||||
|
||||
Reviewed-id: Noone
|
||||
Tested-by: my@house
|
||||
Change-id: Ideadbeef
|
||||
Signed-off-by: C O Mitter <committer@example.com>
|
||||
Bug: 1234
|
||||
EOF
|
||||
cat >expected <<\EOF &&
|
||||
4:Subject: [PATCH] subject
|
||||
8:
|
||||
10:
|
||||
14:Signed-off-by: C O Mitter <committer@example.com>
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'format patch ignores color.ui' '
|
||||
test_unconfig color.ui &&
|
||||
git format-patch --stdout -1 >expect &&
|
||||
|
||||
@@ -424,6 +424,18 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'commit -s places sob on third line after two empty lines' '
|
||||
git commit -s --allow-empty --allow-empty-message &&
|
||||
cat <<-EOF >expect &&
|
||||
|
||||
|
||||
Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
|
||||
|
||||
EOF
|
||||
sed -e "/^#/d" -e "s/^:.*//" .git/COMMIT_EDITMSG >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
write_script .git/FAKE_EDITOR <<\EOF
|
||||
mv "$1" "$1.orig"
|
||||
(
|
||||
|
||||
@@ -135,12 +135,12 @@ test_pause () {
|
||||
fi
|
||||
}
|
||||
|
||||
# Call test_commit with the arguments "<message> [<file> [<contents>]]"
|
||||
# Call test_commit with the arguments "<message> [<file> [<contents> [<tag>]]]"
|
||||
#
|
||||
# This will commit a file with the given contents and the given commit
|
||||
# message. It will also add a tag with <message> as name.
|
||||
# message, and tag the resulting commit with the given tag name.
|
||||
#
|
||||
# Both <file> and <contents> default to <message>.
|
||||
# <file>, <contents>, and <tag> all default to <message>.
|
||||
|
||||
test_commit () {
|
||||
notick= &&
|
||||
@@ -168,7 +168,7 @@ test_commit () {
|
||||
test_tick
|
||||
fi &&
|
||||
git commit $signoff -m "$1" &&
|
||||
git tag "$1"
|
||||
git tag "${4:-$1}"
|
||||
}
|
||||
|
||||
# Call test_merge with the arguments "<message> <commit>", where <commit>
|
||||
|
||||
Reference in New Issue
Block a user