@@ -702,6 +702,7 @@ static void add_header(const char *value)
702702#define THREAD_DEEP 2
703703static int thread ;
704704static int do_signoff ;
705+ static int base_auto ;
705706static const char * signature = git_version_string ;
706707static const char * signature_file ;
707708static int config_cover_letter ;
@@ -786,6 +787,10 @@ static int git_format_config(const char *var, const char *value, void *cb)
786787 }
787788 if (!strcmp (var , "format.outputdirectory" ))
788789 return git_config_string (& config_output_directory , var , value );
790+ if (!strcmp (var , "format.useautobase" )) {
791+ base_auto = git_config_bool (var , value );
792+ return 0 ;
793+ }
789794
790795 return git_log_config (var , value , cb );
791796}
@@ -1191,6 +1196,155 @@ static int from_callback(const struct option *opt, const char *arg, int unset)
11911196 return 0 ;
11921197}
11931198
1199+ struct base_tree_info {
1200+ struct object_id base_commit ;
1201+ int nr_patch_id , alloc_patch_id ;
1202+ struct object_id * patch_id ;
1203+ };
1204+
1205+ static struct commit * get_base_commit (const char * base_commit ,
1206+ struct commit * * list ,
1207+ int total )
1208+ {
1209+ struct commit * base = NULL ;
1210+ struct commit * * rev ;
1211+ int i = 0 , rev_nr = 0 ;
1212+
1213+ if (base_commit && strcmp (base_commit , "auto" )) {
1214+ base = lookup_commit_reference_by_name (base_commit );
1215+ if (!base )
1216+ die (_ ("Unknown commit %s" ), base_commit );
1217+ } else if ((base_commit && !strcmp (base_commit , "auto" )) || base_auto ) {
1218+ struct branch * curr_branch = branch_get (NULL );
1219+ const char * upstream = branch_get_upstream (curr_branch , NULL );
1220+ if (upstream ) {
1221+ struct commit_list * base_list ;
1222+ struct commit * commit ;
1223+ unsigned char sha1 [20 ];
1224+
1225+ if (get_sha1 (upstream , sha1 ))
1226+ die (_ ("Failed to resolve '%s' as a valid ref." ), upstream );
1227+ commit = lookup_commit_or_die (sha1 , "upstream base" );
1228+ base_list = get_merge_bases_many (commit , total , list );
1229+ /* There should be one and only one merge base. */
1230+ if (!base_list || base_list -> next )
1231+ die (_ ("Could not find exact merge base." ));
1232+ base = base_list -> item ;
1233+ free_commit_list (base_list );
1234+ } else {
1235+ die (_ ("Failed to get upstream, if you want to record base commit automatically,\n"
1236+ "please use git branch --set-upstream-to to track a remote branch.\n"
1237+ "Or you could specify base commit by --base=<base-commit-id> manually." ));
1238+ }
1239+ }
1240+
1241+ ALLOC_ARRAY (rev , total );
1242+ for (i = 0 ; i < total ; i ++ )
1243+ rev [i ] = list [i ];
1244+
1245+ rev_nr = total ;
1246+ /*
1247+ * Get merge base through pair-wise computations
1248+ * and store it in rev[0].
1249+ */
1250+ while (rev_nr > 1 ) {
1251+ for (i = 0 ; i < rev_nr / 2 ; i ++ ) {
1252+ struct commit_list * merge_base ;
1253+ merge_base = get_merge_bases (rev [2 * i ], rev [2 * i + 1 ]);
1254+ if (!merge_base || merge_base -> next )
1255+ die (_ ("Failed to find exact merge base" ));
1256+
1257+ rev [i ] = merge_base -> item ;
1258+ }
1259+
1260+ if (rev_nr % 2 )
1261+ rev [i ] = rev [2 * i ];
1262+ rev_nr = (rev_nr + 1 ) / 2 ;
1263+ }
1264+
1265+ if (!in_merge_bases (base , rev [0 ]))
1266+ die (_ ("base commit should be the ancestor of revision list" ));
1267+
1268+ for (i = 0 ; i < total ; i ++ ) {
1269+ if (base == list [i ])
1270+ die (_ ("base commit shouldn't be in revision list" ));
1271+ }
1272+
1273+ free (rev );
1274+ return base ;
1275+ }
1276+
1277+ static void prepare_bases (struct base_tree_info * bases ,
1278+ struct commit * base ,
1279+ struct commit * * list ,
1280+ int total )
1281+ {
1282+ struct commit * commit ;
1283+ struct rev_info revs ;
1284+ struct diff_options diffopt ;
1285+ int i ;
1286+
1287+ if (!base )
1288+ return ;
1289+
1290+ diff_setup (& diffopt );
1291+ DIFF_OPT_SET (& diffopt , RECURSIVE );
1292+ diff_setup_done (& diffopt );
1293+
1294+ oidcpy (& bases -> base_commit , & base -> object .oid );
1295+
1296+ init_revisions (& revs , NULL );
1297+ revs .max_parents = 1 ;
1298+ revs .topo_order = 1 ;
1299+ for (i = 0 ; i < total ; i ++ ) {
1300+ list [i ]-> object .flags &= ~UNINTERESTING ;
1301+ add_pending_object (& revs , & list [i ]-> object , "rev_list" );
1302+ list [i ]-> util = (void * )1 ;
1303+ }
1304+ base -> object .flags |= UNINTERESTING ;
1305+ add_pending_object (& revs , & base -> object , "base" );
1306+
1307+ if (prepare_revision_walk (& revs ))
1308+ die (_ ("revision walk setup failed" ));
1309+ /*
1310+ * Traverse the commits list, get prerequisite patch ids
1311+ * and stuff them in bases structure.
1312+ */
1313+ while ((commit = get_revision (& revs )) != NULL ) {
1314+ unsigned char sha1 [20 ];
1315+ struct object_id * patch_id ;
1316+ if (commit -> util )
1317+ continue ;
1318+ if (commit_patch_id (commit , & diffopt , sha1 ))
1319+ die (_ ("cannot get patch id" ));
1320+ ALLOC_GROW (bases -> patch_id , bases -> nr_patch_id + 1 , bases -> alloc_patch_id );
1321+ patch_id = bases -> patch_id + bases -> nr_patch_id ;
1322+ hashcpy (patch_id -> hash , sha1 );
1323+ bases -> nr_patch_id ++ ;
1324+ }
1325+ }
1326+
1327+ static void print_bases (struct base_tree_info * bases )
1328+ {
1329+ int i ;
1330+
1331+ /* Only do this once, either for the cover or for the first one */
1332+ if (is_null_oid (& bases -> base_commit ))
1333+ return ;
1334+
1335+ /* Show the base commit */
1336+ printf ("base-commit: %s\n" , oid_to_hex (& bases -> base_commit ));
1337+
1338+ /* Show the prerequisite patches */
1339+ for (i = bases -> nr_patch_id - 1 ; i >= 0 ; i -- )
1340+ printf ("prerequisite-patch-id: %s\n" , oid_to_hex (& bases -> patch_id [i ]));
1341+
1342+ free (bases -> patch_id );
1343+ bases -> nr_patch_id = 0 ;
1344+ bases -> alloc_patch_id = 0 ;
1345+ oidclr (& bases -> base_commit );
1346+ }
1347+
11941348int cmd_format_patch (int argc , const char * * argv , const char * prefix )
11951349{
11961350 struct commit * commit ;
@@ -1215,6 +1369,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
12151369 int reroll_count = -1 ;
12161370 char * branch_name = NULL ;
12171371 char * from = NULL ;
1372+ char * base_commit = NULL ;
1373+ struct base_tree_info bases ;
1374+
12181375 const struct option builtin_format_patch_options [] = {
12191376 { OPTION_CALLBACK , 'n' , "numbered" , & numbered , NULL ,
12201377 N_ ("use [PATCH n/m] even with a single patch" ),
@@ -1277,6 +1434,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
12771434 PARSE_OPT_OPTARG , thread_callback },
12781435 OPT_STRING (0 , "signature" , & signature , N_ ("signature" ),
12791436 N_ ("add a signature" )),
1437+ OPT_STRING (0 , "base" , & base_commit , N_ ("base-commit" ),
1438+ N_ ("add prerequisite tree info to the patch series" )),
12801439 OPT_FILENAME (0 , "signature-file" , & signature_file ,
12811440 N_ ("add a signature from a file" )),
12821441 OPT__QUIET (& quiet , N_ ("don't print the patch filenames" )),
@@ -1514,6 +1673,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
15141673 signature = strbuf_detach (& buf , NULL );
15151674 }
15161675
1676+ memset (& bases , 0 , sizeof (bases ));
1677+ if (base_commit || base_auto ) {
1678+ struct commit * base = get_base_commit (base_commit , list , nr );
1679+ reset_revision_walk ();
1680+ prepare_bases (& bases , base , list , nr );
1681+ }
1682+
15171683 if (in_reply_to || thread || cover_letter )
15181684 rev .ref_message_ids = xcalloc (1 , sizeof (struct string_list ));
15191685 if (in_reply_to ) {
@@ -1527,6 +1693,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
15271693 gen_message_id (& rev , "cover" );
15281694 make_cover_letter (& rev , use_stdout ,
15291695 origin , nr , list , branch_name , quiet );
1696+ print_bases (& bases );
15301697 total ++ ;
15311698 start_number -- ;
15321699 }
@@ -1592,6 +1759,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
15921759 rev .mime_boundary );
15931760 else
15941761 print_signature ();
1762+ print_bases (& bases );
15951763 }
15961764 if (!use_stdout )
15971765 fclose (stdout );
0 commit comments