3131#include "progress.h"
3232#include "commit-slab.h"
3333#include "repository.h"
34+ #include "interdiff.h"
3435
3536#define MAIL_DEFAULT_WRAP 72
3637
@@ -998,6 +999,26 @@ static char *find_branch_name(struct rev_info *rev)
998999 return branch ;
9991000}
10001001
1002+ static void show_diffstat (struct rev_info * rev ,
1003+ struct commit * origin , struct commit * head )
1004+ {
1005+ struct diff_options opts ;
1006+
1007+ memcpy (& opts , & rev -> diffopt , sizeof (opts ));
1008+ opts .output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT ;
1009+ opts .stat_width = MAIL_DEFAULT_WRAP ;
1010+
1011+ diff_setup_done (& opts );
1012+
1013+ diff_tree_oid (get_commit_tree_oid (origin ),
1014+ get_commit_tree_oid (head ),
1015+ "" , & opts );
1016+ diffcore_std (& opts );
1017+ diff_flush (& opts );
1018+
1019+ fprintf (rev -> diffopt .file , "\n" );
1020+ }
1021+
10011022static void make_cover_letter (struct rev_info * rev , int use_stdout ,
10021023 struct commit * origin ,
10031024 int nr , struct commit * * list ,
@@ -1011,7 +1032,6 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
10111032 struct strbuf sb = STRBUF_INIT ;
10121033 int i ;
10131034 const char * encoding = "UTF-8" ;
1014- struct diff_options opts ;
10151035 int need_8bit_cte = 0 ;
10161036 struct pretty_print_context pp = {0 };
10171037 struct commit * head = list [0 ];
@@ -1061,25 +1081,14 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
10611081
10621082 shortlog_output (& log );
10631083
1064- /*
1065- * We can only do diffstat with a unique reference point
1066- */
1067- if (!origin )
1068- return ;
1084+ /* We can only do diffstat with a unique reference point */
1085+ if (origin )
1086+ show_diffstat (rev , origin , head );
10691087
1070- memcpy (& opts , & rev -> diffopt , sizeof (opts ));
1071- opts .output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT ;
1072- opts .stat_width = MAIL_DEFAULT_WRAP ;
1073-
1074- diff_setup_done (& opts );
1075-
1076- diff_tree_oid (get_commit_tree_oid (origin ),
1077- get_commit_tree_oid (head ),
1078- "" , & opts );
1079- diffcore_std (& opts );
1080- diff_flush (& opts );
1081-
1082- fprintf (rev -> diffopt .file , "\n" );
1088+ if (rev -> idiff_oid1 ) {
1089+ fprintf_ln (rev -> diffopt .file , "%s" , rev -> idiff_title );
1090+ show_interdiff (rev , 0 );
1091+ }
10831092}
10841093
10851094static const char * clean_message_id (const char * msg_id )
@@ -1419,6 +1428,16 @@ static void print_bases(struct base_tree_info *bases, FILE *file)
14191428 oidclr (& bases -> base_commit );
14201429}
14211430
1431+ static const char * diff_title (struct strbuf * sb , int reroll_count ,
1432+ const char * generic , const char * rerolled )
1433+ {
1434+ if (reroll_count <= 0 )
1435+ strbuf_addstr (sb , generic );
1436+ else /* RFC may be v0, so allow -v1 to diff against v0 */
1437+ strbuf_addf (sb , rerolled , reroll_count - 1 );
1438+ return sb -> buf ;
1439+ }
1440+
14221441int cmd_format_patch (int argc , const char * * argv , const char * prefix )
14231442{
14241443 struct commit * commit ;
@@ -1446,6 +1465,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
14461465 struct base_tree_info bases ;
14471466 int show_progress = 0 ;
14481467 struct progress * progress = NULL ;
1468+ struct oid_array idiff_prev = OID_ARRAY_INIT ;
1469+ struct strbuf idiff_title = STRBUF_INIT ;
14491470
14501471 const struct option builtin_format_patch_options [] = {
14511472 { OPTION_CALLBACK , 'n' , "numbered" , & numbered , NULL ,
@@ -1519,6 +1540,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
15191540 OPT__QUIET (& quiet , N_ ("don't print the patch filenames" )),
15201541 OPT_BOOL (0 , "progress" , & show_progress ,
15211542 N_ ("show progress while generating patches" )),
1543+ OPT_CALLBACK (0 , "interdiff" , & idiff_prev , N_ ("rev" ),
1544+ N_ ("show changes against <rev> in cover letter or single patch" ),
1545+ parse_opt_object_name ),
15221546 OPT_END ()
15231547 };
15241548
@@ -1704,7 +1728,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
17041728 if (rev .pending .nr == 2 ) {
17051729 struct object_array_entry * o = rev .pending .objects ;
17061730 if (oidcmp (& o [0 ].item -> oid , & o [1 ].item -> oid ) == 0 )
1707- return 0 ;
1731+ goto done ;
17081732 }
17091733 get_patch_ids (& rev , & ids );
17101734 }
@@ -1728,7 +1752,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
17281752 }
17291753 if (nr == 0 )
17301754 /* nothing to do */
1731- return 0 ;
1755+ goto done ;
17321756 total = nr ;
17331757 if (cover_letter == -1 ) {
17341758 if (config_cover_letter == COVER_AUTO )
@@ -1741,6 +1765,16 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
17411765 if (numbered )
17421766 rev .total = total + start_number - 1 ;
17431767
1768+ if (idiff_prev .nr ) {
1769+ if (!cover_letter && total != 1 )
1770+ die (_ ("--interdiff requires --cover-letter or single patch" ));
1771+ rev .idiff_oid1 = & idiff_prev .oid [idiff_prev .nr - 1 ];
1772+ rev .idiff_oid2 = get_commit_tree_oid (list [0 ]);
1773+ rev .idiff_title = diff_title (& idiff_title , reroll_count ,
1774+ _ ("Interdiff:" ),
1775+ _ ("Interdiff against v%d:" ));
1776+ }
1777+
17441778 if (!signature ) {
17451779 ; /* --no-signature inhibits all signatures */
17461780 } else if (signature && signature != git_version_string ) {
@@ -1778,6 +1812,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
17781812 print_signature (rev .diffopt .file );
17791813 total ++ ;
17801814 start_number -- ;
1815+ /* interdiff in cover-letter; omit from patches */
1816+ rev .idiff_oid1 = NULL ;
17811817 }
17821818 rev .add_signoff = do_signoff ;
17831819
@@ -1858,6 +1894,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
18581894 string_list_clear (& extra_hdr , 0 );
18591895 if (ignore_if_in_upstream )
18601896 free_patch_ids (& ids );
1897+
1898+ done :
1899+ oid_array_clear (& idiff_prev );
1900+ strbuf_release (& idiff_title );
18611901 return 0 ;
18621902}
18631903
0 commit comments