Skip to content

Commit b8711f5

Browse files
committed
Merge branch 'jc/mailinfo-scissors'
* jc/mailinfo-scissors: mailinfo.scissors: new configuration am/mailinfo: Disable scissors processing by default Documentation: describe the scissors mark support of "git am" Teach mailinfo to ignore everything before -- >8 -- mark builtin-mailinfo.c: fix confusing internal API to mailinfo()
2 parents 2da9f8e + 43485d3 commit b8711f5

File tree

12 files changed

+395
-27
lines changed

12 files changed

+395
-27
lines changed

Documentation/git-am.txt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ SYNOPSIS
1313
[--3way] [--interactive] [--committer-date-is-author-date]
1414
[--ignore-date] [--ignore-space-change | --ignore-whitespace]
1515
[--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
16-
[--reject] [-q | --quiet]
16+
[--reject] [-q | --quiet] [--scissors]
1717
[<mbox> | <Maildir>...]
1818
'git am' (--skip | --resolved | --abort)
1919

@@ -39,6 +39,11 @@ OPTIONS
3939
--keep::
4040
Pass `-k` flag to 'git-mailinfo' (see linkgit:git-mailinfo[1]).
4141

42+
-c::
43+
--scissors::
44+
Remove everything in body before a scissors line (see
45+
linkgit:git-mailinfo[1]).
46+
4247
-q::
4348
--quiet::
4449
Be quiet. Only print error messages.
@@ -128,10 +133,8 @@ the commit, after stripping common prefix "[PATCH <anything>]".
128133
The "Subject: " line is supposed to concisely describe what the
129134
commit is about in one line of text.
130135

131-
"From: " and "Subject: " lines starting the body (the rest of the
132-
message after the blank line terminating the RFC2822 headers)
133-
override the respective commit author name and title values taken
134-
from the headers.
136+
"From: " and "Subject: " lines starting the body override the respective
137+
commit author name and title values taken from the headers.
135138

136139
The commit message is formed by the title taken from the
137140
"Subject: ", a blank line and the body of the message up to

Documentation/git-mailinfo.txt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ git-mailinfo - Extracts patch and authorship from a single e-mail message
88

99
SYNOPSIS
1010
--------
11-
'git mailinfo' [-k] [-u | --encoding=<encoding> | -n] <msg> <patch>
11+
'git mailinfo' [-k] [-u | --encoding=<encoding> | -n] [--scissors] <msg> <patch>
1212

1313

1414
DESCRIPTION
@@ -49,6 +49,20 @@ conversion, even with this flag.
4949
-n::
5050
Disable all charset re-coding of the metadata.
5151

52+
--scissors::
53+
Remove everything in body before a scissors line. A line that
54+
mainly consists of scissors (either ">8" or "8<") and perforation
55+
(dash "-") marks is called a scissors line, and is used to request
56+
the reader to cut the message at that line. If such a line
57+
appears in the body of the message before the patch, everything
58+
before it (including the scissors line itself) is ignored when
59+
this option is used.
60+
+
61+
This is useful if you want to begin your message in a discussion thread
62+
with comments and suggestions on the message you are responding to, and to
63+
conclude it with a patch submission, separating the discussion and the
64+
beginning of the proposed commit log message with a scissors line.
65+
5266
<msg>::
5367
The commit log message extracted from e-mail, usually
5468
except the title line which comes from e-mail Subject.

builtin-mailinfo.c

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ static enum {
2525
static struct strbuf charset = STRBUF_INIT;
2626
static int patch_lines;
2727
static struct strbuf **p_hdr_data, **s_hdr_data;
28+
static int use_scissors;
2829

2930
#define MAX_HDR_PARSED 10
3031
#define MAX_BOUNDARIES 5
@@ -712,6 +713,56 @@ static inline int patchbreak(const struct strbuf *line)
712713
return 0;
713714
}
714715

716+
static int is_scissors_line(const struct strbuf *line)
717+
{
718+
size_t i, len = line->len;
719+
int scissors = 0, gap = 0;
720+
int first_nonblank = -1;
721+
int last_nonblank = 0, visible, perforation = 0, in_perforation = 0;
722+
const char *buf = line->buf;
723+
724+
for (i = 0; i < len; i++) {
725+
if (isspace(buf[i])) {
726+
if (in_perforation) {
727+
perforation++;
728+
gap++;
729+
}
730+
continue;
731+
}
732+
last_nonblank = i;
733+
if (first_nonblank < 0)
734+
first_nonblank = i;
735+
if (buf[i] == '-') {
736+
in_perforation = 1;
737+
perforation++;
738+
continue;
739+
}
740+
if (i + 1 < len &&
741+
(!memcmp(buf + i, ">8", 2) || !memcmp(buf + i, "8<", 2))) {
742+
in_perforation = 1;
743+
perforation += 2;
744+
scissors += 2;
745+
i++;
746+
continue;
747+
}
748+
in_perforation = 0;
749+
}
750+
751+
/*
752+
* The mark must be at least 8 bytes long (e.g. "-- >8 --").
753+
* Even though there can be arbitrary cruft on the same line
754+
* (e.g. "cut here"), in order to avoid misidentification, the
755+
* perforation must occupy more than a third of the visible
756+
* width of the line, and dashes and scissors must occupy more
757+
* than half of the perforation.
758+
*/
759+
760+
visible = last_nonblank - first_nonblank + 1;
761+
return (scissors && 8 <= visible &&
762+
visible < perforation * 3 &&
763+
gap * 2 < perforation);
764+
}
765+
715766
static int handle_commit_msg(struct strbuf *line)
716767
{
717768
static int still_looking = 1;
@@ -723,14 +774,33 @@ static int handle_commit_msg(struct strbuf *line)
723774
strbuf_ltrim(line);
724775
if (!line->len)
725776
return 0;
726-
if ((still_looking = check_header(line, s_hdr_data, 0)) != 0)
777+
still_looking = check_header(line, s_hdr_data, 0);
778+
if (still_looking)
727779
return 0;
728780
}
729781

730782
/* normalize the log message to UTF-8. */
731783
if (metainfo_charset)
732784
convert_to_utf8(line, charset.buf);
733785

786+
if (use_scissors && is_scissors_line(line)) {
787+
int i;
788+
rewind(cmitmsg);
789+
ftruncate(fileno(cmitmsg), 0);
790+
still_looking = 1;
791+
792+
/*
793+
* We may have already read "secondary headers"; purge
794+
* them to give ourselves a clean restart.
795+
*/
796+
for (i = 0; header[i]; i++) {
797+
if (s_hdr_data[i])
798+
strbuf_release(s_hdr_data[i]);
799+
s_hdr_data[i] = NULL;
800+
}
801+
return 0;
802+
}
803+
734804
if (patchbreak(line)) {
735805
fclose(cmitmsg);
736806
cmitmsg = NULL;
@@ -885,12 +955,9 @@ static void handle_info(void)
885955
fprintf(fout, "\n");
886956
}
887957

888-
static int mailinfo(FILE *in, FILE *out, int ks, const char *encoding,
889-
const char *msg, const char *patch)
958+
static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)
890959
{
891960
int peek;
892-
keep_subject = ks;
893-
metainfo_charset = encoding;
894961
fin = in;
895962
fout = out;
896963

@@ -924,6 +991,18 @@ static int mailinfo(FILE *in, FILE *out, int ks, const char *encoding,
924991
return 0;
925992
}
926993

994+
static int git_mailinfo_config(const char *var, const char *value, void *unused)
995+
{
996+
if (prefixcmp(var, "mailinfo."))
997+
return git_default_config(var, value, unused);
998+
if (!strcmp(var, "mailinfo.scissors")) {
999+
use_scissors = git_config_bool(var, value);
1000+
return 0;
1001+
}
1002+
/* perhaps others here */
1003+
return 0;
1004+
}
1005+
9271006
static const char mailinfo_usage[] =
9281007
"git mailinfo [-k] [-u | --encoding=<encoding> | -n] msg patch <mail >info";
9291008

@@ -934,7 +1013,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
9341013
/* NEEDSWORK: might want to do the optional .git/ directory
9351014
* discovery
9361015
*/
937-
git_config(git_default_config, NULL);
1016+
git_config(git_mailinfo_config, NULL);
9381017

9391018
def_charset = (git_commit_encoding ? git_commit_encoding : "UTF-8");
9401019
metainfo_charset = def_charset;
@@ -948,6 +1027,10 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
9481027
metainfo_charset = NULL;
9491028
else if (!prefixcmp(argv[1], "--encoding="))
9501029
metainfo_charset = argv[1] + 11;
1030+
else if (!strcmp(argv[1], "--scissors"))
1031+
use_scissors = 1;
1032+
else if (!strcmp(argv[1], "--no-scissors"))
1033+
use_scissors = 0;
9511034
else
9521035
usage(mailinfo_usage);
9531036
argc--; argv++;
@@ -956,5 +1039,5 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
9561039
if (argc != 3)
9571040
usage(mailinfo_usage);
9581041

959-
return !!mailinfo(stdin, stdout, keep_subject, metainfo_charset, argv[1], argv[2]);
1042+
return !!mailinfo(stdin, stdout, argv[1], argv[2]);
9601043
}

git-am.sh

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ q,quiet be quiet
1515
s,signoff add a Signed-off-by line to the commit message
1616
u,utf8 recode into utf8 (default)
1717
k,keep pass -k flag to git-mailinfo
18+
c,scissors strip everything before a scissors line
1819
whitespace= pass it through git-apply
1920
ignore-space-change pass it through git-apply
2021
ignore-whitespace pass it through git-apply
@@ -288,7 +289,7 @@ split_patches () {
288289
prec=4
289290
dotest="$GIT_DIR/rebase-apply"
290291
sign= utf8=t keep= skip= interactive= resolved= rebasing= abort=
291-
resolvemsg= resume=
292+
resolvemsg= resume= scissors=
292293
git_apply_opt=
293294
committer_date_is_author_date=
294295
ignore_date=
@@ -310,14 +311,18 @@ do
310311
utf8= ;;
311312
-k|--keep)
312313
keep=t ;;
314+
-c|--scissors)
315+
scissors=t ;;
316+
--no-scissors)
317+
scissors=f ;;
313318
-r|--resolved)
314319
resolved=t ;;
315320
--skip)
316321
skip=t ;;
317322
--abort)
318323
abort=t ;;
319324
--rebasing)
320-
rebasing=t threeway=t keep=t ;;
325+
rebasing=t threeway=t keep=t scissors=f ;;
321326
-d|--dotest)
322327
die "-d option is no longer supported. Do not use."
323328
;;
@@ -435,14 +440,14 @@ else
435440

436441
split_patches "$@"
437442

438-
# -s, -u, -k, --whitespace, -3, -C, -q and -p flags are kept
439-
# for the resuming session after a patch failure.
440-
# -i can and must be given when resuming.
443+
# -i can and must be given when resuming; everything
444+
# else is kept
441445
echo " $git_apply_opt" >"$dotest/apply-opt"
442446
echo "$threeway" >"$dotest/threeway"
443447
echo "$sign" >"$dotest/sign"
444448
echo "$utf8" >"$dotest/utf8"
445449
echo "$keep" >"$dotest/keep"
450+
echo "$scissors" >"$dotest/scissors"
446451
echo "$GIT_QUIET" >"$dotest/quiet"
447452
echo 1 >"$dotest/next"
448453
if test -n "$rebasing"
@@ -484,6 +489,12 @@ if test "$(cat "$dotest/keep")" = t
484489
then
485490
keep=-k
486491
fi
492+
case "$(cat "$dotest/scissors")" in
493+
t)
494+
scissors=--scissors ;;
495+
f)
496+
scissors=--no-scissors ;;
497+
esac
487498
if test "$(cat "$dotest/quiet")" = t
488499
then
489500
GIT_QUIET=t
@@ -538,7 +549,7 @@ do
538549
# by the user, or the user can tell us to do so by --resolved flag.
539550
case "$resume" in
540551
'')
541-
git mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \
552+
git mailinfo $keep $scissors $utf8 "$dotest/msg" "$dotest/patch" \
542553
<"$dotest/$msgnum" >"$dotest/info" ||
543554
stop_here $this
544555

t/t5100-mailinfo.sh

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,26 @@ test_expect_success 'split sample box' \
1111
'git mailsplit -o. "$TEST_DIRECTORY"/t5100/sample.mbox >last &&
1212
last=`cat last` &&
1313
echo total is $last &&
14-
test `cat last` = 13'
14+
test `cat last` = 14'
15+
16+
check_mailinfo () {
17+
mail=$1 opt=$2
18+
mo="$mail$opt"
19+
git mailinfo -u $opt msg$mo patch$mo <$mail >info$mo &&
20+
test_cmp "$TEST_DIRECTORY"/t5100/msg$mo msg$mo &&
21+
test_cmp "$TEST_DIRECTORY"/t5100/patch$mo patch$mo &&
22+
test_cmp "$TEST_DIRECTORY"/t5100/info$mo info$mo
23+
}
24+
1525

1626
for mail in `echo 00*`
1727
do
1828
test_expect_success "mailinfo $mail" '
19-
git mailinfo -u msg$mail patch$mail <$mail >info$mail &&
20-
echo msg &&
21-
test_cmp "$TEST_DIRECTORY"/t5100/msg$mail msg$mail &&
22-
echo patch &&
23-
test_cmp "$TEST_DIRECTORY"/t5100/patch$mail patch$mail &&
24-
echo info &&
25-
test_cmp "$TEST_DIRECTORY"/t5100/info$mail info$mail
29+
check_mailinfo $mail "" &&
30+
if test -f "$TEST_DIRECTORY"/t5100/msg$mail--scissors
31+
then
32+
check_mailinfo $mail --scissors
33+
fi
2634
'
2735
done
2836

t/t5100/info0014

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Author: Junio Hamano
2+
3+
Subject: BLAH ONE
4+
Date: Thu, 20 Aug 2009 17:18:22 -0700
5+

t/t5100/info0014--scissors

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Author: Junio C Hamano
2+
3+
Subject: Teach mailinfo to ignore everything before -- >8 -- mark
4+
Date: Thu, 20 Aug 2009 17:18:22 -0700
5+

t/t5100/msg0014

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
In real life, we will see a discussion that inspired this patch
2+
discussing related and unrelated things around >8 scissors mark
3+
in this part of the message.
4+
5+
Subject: [PATCH] BLAH TWO
6+
7+
And then we will see the scissors.
8+
9+
This line is not a scissors mark -- >8 -- but talks about it.
10+
- - >8 - - please remove everything above this line - - >8 - -
11+
12+
Subject: [PATCH] Teach mailinfo to ignore everything before -- >8 -- mark
13+
From: Junio C Hamano <[email protected]>
14+
15+
This teaches mailinfo the scissors -- >8 -- mark; the command ignores
16+
everything before it in the message body.
17+
18+
Signed-off-by: Junio C Hamano <[email protected]>

t/t5100/msg0014--scissors

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
This teaches mailinfo the scissors -- >8 -- mark; the command ignores
2+
everything before it in the message body.
3+
4+
Signed-off-by: Junio C Hamano <[email protected]>

0 commit comments

Comments
 (0)