Skip to content

Commit 30984ed

Browse files
trastgitster
authored andcommitted
format-patch: support deep threading
For deep threading mode, i.e., the mode that gives a thread structured like + [PATCH 0/n] Cover letter `-+ [PATCH 1/n] First patch `-+ [PATCH 2/n] Second patch `-+ ... we currently have to use 'git send-email --thread' (the default). On the other hand, format-patch also has a --thread option which gives shallow mode, i.e., + [PATCH 0/n] Cover letter |-+ [PATCH 1/n] First patch |-+ [PATCH 2/n] Second patch ... To reduce the confusion resulting from having two indentically named features in different tools giving different results, let format-patch take an optional argument '--thread=deep' that gives the same output as 'send-mail --thread'. With no argument, or 'shallow', behave as before. Also add a configuration variable format.thread with the same semantics. Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 2175c10 commit 30984ed

File tree

4 files changed

+170
-5
lines changed

4 files changed

+170
-5
lines changed

Documentation/config.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,16 @@ format.pretty::
677677
See linkgit:git-log[1], linkgit:git-show[1],
678678
linkgit:git-whatchanged[1].
679679

680+
format.thread::
681+
The default threading style for 'git-format-patch'. Can be
682+
either a boolean value, `shallow` or `deep`. 'Shallow'
683+
threading makes every mail a reply to the head of the series,
684+
where the head is chosen from the cover letter, the
685+
`\--in-reply-to`, and the first patch mail, in this order.
686+
'Deep' threading makes every mail a reply to the previous one.
687+
A true boolean value is the same as `shallow`, and a false
688+
value disables threading.
689+
680690
gc.aggressiveWindow::
681691
The window size parameter used in the delta compression
682692
algorithm used by 'git-gc --aggressive'. This defaults

Documentation/git-format-patch.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,18 @@ include::diff-options.txt[]
122122
which is the commit message and the patch itself in the
123123
second part, with "Content-Disposition: inline".
124124

125-
--thread::
125+
--thread[=<style>]::
126126
Add In-Reply-To and References headers to make the second and
127127
subsequent mails appear as replies to the first. Also generates
128128
the Message-Id header to reference.
129+
+
130+
The optional <style> argument can be either `shallow` or `deep`.
131+
'Shallow' threading makes every mail a reply to the head of the
132+
series, where the head is chosen from the cover letter, the
133+
`\--in-reply-to`, and the first patch mail, in this order. 'Deep'
134+
threading makes every mail a reply to the previous one. If not
135+
specified, defaults to the 'format.thread' configuration, or `shallow`
136+
if that is not set.
129137

130138
--in-reply-to=Message-Id::
131139
Make the first mail (or all the mails with --no-thread) appear as a

builtin-log.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,10 @@ static void add_header(const char *value)
460460
extra_hdr[extra_hdr_nr++] = xstrndup(value, len);
461461
}
462462

463+
#define THREAD_SHALLOW 1
464+
#define THREAD_DEEP 2
465+
static int thread = 0;
466+
463467
static int git_format_config(const char *var, const char *value, void *cb)
464468
{
465469
if (!strcmp(var, "format.headers")) {
@@ -489,6 +493,18 @@ static int git_format_config(const char *var, const char *value, void *cb)
489493
auto_number = auto_number && numbered;
490494
return 0;
491495
}
496+
if (!strcmp(var, "format.thread")) {
497+
if (value && !strcasecmp(value, "deep")) {
498+
thread = THREAD_DEEP;
499+
return 0;
500+
}
501+
if (value && !strcasecmp(value, "shallow")) {
502+
thread = THREAD_SHALLOW;
503+
return 0;
504+
}
505+
thread = git_config_bool(var, value) && THREAD_SHALLOW;
506+
return 0;
507+
}
492508

493509
return git_log_config(var, value, cb);
494510
}
@@ -767,7 +783,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
767783
int numbered_files = 0; /* _just_ numbers */
768784
int subject_prefix = 0;
769785
int ignore_if_in_upstream = 0;
770-
int thread = 0;
771786
int cover_letter = 0;
772787
int boundary_count = 0;
773788
int no_binary_diff = 0;
@@ -860,8 +875,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
860875
}
861876
else if (!strcmp(argv[i], "--ignore-if-in-upstream"))
862877
ignore_if_in_upstream = 1;
863-
else if (!strcmp(argv[i], "--thread"))
864-
thread = 1;
878+
else if (!strcmp(argv[i], "--thread")
879+
|| !strcmp(argv[i], "--thread=shallow"))
880+
thread = THREAD_SHALLOW;
881+
else if (!strcmp(argv[i], "--thread=deep"))
882+
thread = THREAD_DEEP;
883+
else if (!strcmp(argv[i], "--no-thread"))
884+
thread = 0;
865885
else if (!prefixcmp(argv[i], "--in-reply-to="))
866886
in_reply_to = argv[i] + 14;
867887
else if (!strcmp(argv[i], "--in-reply-to")) {
@@ -1036,6 +1056,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
10361056
/* Have we already had a message ID? */
10371057
if (rev.message_id) {
10381058
/*
1059+
* For deep threading: make every mail
1060+
* a reply to the previous one, no
1061+
* matter what other options are set.
1062+
*
1063+
* For shallow threading:
1064+
*
10391065
* Without --cover-letter and
10401066
* --in-reply-to, make every mail a
10411067
* reply to the one before.
@@ -1050,7 +1076,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
10501076
* letter is a reply to the
10511077
* --in-reply-to, if specified.
10521078
*/
1053-
if (rev.ref_message_ids->nr > 0
1079+
if (thread == THREAD_SHALLOW
1080+
&& rev.ref_message_ids->nr > 0
10541081
&& (!cover_letter || rev.nr > 1))
10551082
free(rev.message_id);
10561083
else

t/t4014-format-patch.sh

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,126 @@ test_expect_success 'thread cover-letter in-reply-to' '
257257
--in-reply-to="<test.message>" --thread master
258258
'
259259

260+
test_expect_success 'thread explicit shallow' '
261+
check_threading expect.cl-irt --cover-letter \
262+
--in-reply-to="<test.message>" --thread=shallow master
263+
'
264+
265+
cat > expect.deep <<EOF
266+
---
267+
Message-Id: <0>
268+
---
269+
Message-Id: <1>
270+
In-Reply-To: <0>
271+
References: <0>
272+
---
273+
Message-Id: <2>
274+
In-Reply-To: <1>
275+
References: <0>
276+
<1>
277+
EOF
278+
279+
test_expect_success 'thread deep' '
280+
check_threading expect.deep --thread=deep master
281+
'
282+
283+
cat > expect.deep-irt <<EOF
284+
---
285+
Message-Id: <0>
286+
In-Reply-To: <1>
287+
References: <1>
288+
---
289+
Message-Id: <2>
290+
In-Reply-To: <0>
291+
References: <1>
292+
<0>
293+
---
294+
Message-Id: <3>
295+
In-Reply-To: <2>
296+
References: <1>
297+
<0>
298+
<2>
299+
EOF
300+
301+
test_expect_success 'thread deep in-reply-to' '
302+
check_threading expect.deep-irt --thread=deep \
303+
--in-reply-to="<test.message>" master
304+
'
305+
306+
cat > expect.deep-cl <<EOF
307+
---
308+
Message-Id: <0>
309+
---
310+
Message-Id: <1>
311+
In-Reply-To: <0>
312+
References: <0>
313+
---
314+
Message-Id: <2>
315+
In-Reply-To: <1>
316+
References: <0>
317+
<1>
318+
---
319+
Message-Id: <3>
320+
In-Reply-To: <2>
321+
References: <0>
322+
<1>
323+
<2>
324+
EOF
325+
326+
test_expect_success 'thread deep cover-letter' '
327+
check_threading expect.deep-cl --cover-letter --thread=deep master
328+
'
329+
330+
cat > expect.deep-cl-irt <<EOF
331+
---
332+
Message-Id: <0>
333+
In-Reply-To: <1>
334+
References: <1>
335+
---
336+
Message-Id: <2>
337+
In-Reply-To: <0>
338+
References: <1>
339+
<0>
340+
---
341+
Message-Id: <3>
342+
In-Reply-To: <2>
343+
References: <1>
344+
<0>
345+
<2>
346+
---
347+
Message-Id: <4>
348+
In-Reply-To: <3>
349+
References: <1>
350+
<0>
351+
<2>
352+
<3>
353+
EOF
354+
355+
test_expect_success 'thread deep cover-letter in-reply-to' '
356+
check_threading expect.deep-cl-irt --cover-letter \
357+
--in-reply-to="<test.message>" --thread=deep master
358+
'
359+
360+
test_expect_success 'thread via config' '
361+
git config format.thread true &&
362+
check_threading expect.thread master
363+
'
364+
365+
test_expect_success 'thread deep via config' '
366+
git config format.thread deep &&
367+
check_threading expect.deep master
368+
'
369+
370+
test_expect_success 'thread config + override' '
371+
git config format.thread deep &&
372+
check_threading expect.thread --thread master
373+
'
374+
375+
test_expect_success 'thread config + --no-thread' '
376+
git config format.thread deep &&
377+
check_threading expect.no-threading --no-thread master
378+
'
379+
260380
test_expect_success 'excessive subject' '
261381
262382
rm -rf patches/ &&

0 commit comments

Comments
 (0)