@@ -23,7 +23,8 @@ static const char *fast_export_usage[] = {
2323};
2424
2525static int progress ;
26- static enum { VERBATIM , WARN , STRIP , ABORT } signed_tag_mode = ABORT ;
26+ static enum { ABORT , VERBATIM , WARN , STRIP } signed_tag_mode = ABORT ;
27+ static enum { ERROR , DROP , REWRITE } tag_of_filtered_mode = ABORT ;
2728static int fake_missing_tagger ;
2829
2930static int parse_opt_signed_tag_mode (const struct option * opt ,
@@ -42,6 +43,20 @@ static int parse_opt_signed_tag_mode(const struct option *opt,
4243 return 0 ;
4344}
4445
46+ static int parse_opt_tag_of_filtered_mode (const struct option * opt ,
47+ const char * arg , int unset )
48+ {
49+ if (unset || !strcmp (arg , "abort" ))
50+ tag_of_filtered_mode = ABORT ;
51+ else if (!strcmp (arg , "drop" ))
52+ tag_of_filtered_mode = DROP ;
53+ else if (!strcmp (arg , "rewrite" ))
54+ tag_of_filtered_mode = REWRITE ;
55+ else
56+ return error ("Unknown tag-of-filtered mode: %s" , arg );
57+ return 0 ;
58+ }
59+
4560static struct decoration idnums ;
4661static uint32_t last_idnum ;
4762
@@ -289,6 +304,23 @@ static void handle_tag(const char *name, struct tag *tag)
289304 char * buf ;
290305 const char * tagger , * tagger_end , * message ;
291306 size_t message_size = 0 ;
307+ struct object * tagged ;
308+ int tagged_mark ;
309+ struct commit * p ;
310+
311+ /* Trees have no identifer in fast-export output, thus we have no way
312+ * to output tags of trees, tags of tags of trees, etc. Simply omit
313+ * such tags.
314+ */
315+ tagged = tag -> tagged ;
316+ while (tagged -> type == OBJ_TAG ) {
317+ tagged = ((struct tag * )tagged )-> tagged ;
318+ }
319+ if (tagged -> type == OBJ_TREE ) {
320+ warning ("Omitting tag %s,\nsince tags of trees (or tags of tags of trees, etc.) are not supported." ,
321+ sha1_to_hex (tag -> object .sha1 ));
322+ return ;
323+ }
292324
293325 buf = read_sha1_file (tag -> object .sha1 , & type , & size );
294326 if (!buf )
@@ -333,10 +365,45 @@ static void handle_tag(const char *name, struct tag *tag)
333365 }
334366 }
335367
368+ /* handle tag->tagged having been filtered out due to paths specified */
369+ tagged = tag -> tagged ;
370+ tagged_mark = get_object_mark (tagged );
371+ if (!tagged_mark ) {
372+ switch (tag_of_filtered_mode ) {
373+ case ABORT :
374+ die ("Tag %s tags unexported object; use "
375+ "--tag-of-filtered-object=<mode> to handle it." ,
376+ sha1_to_hex (tag -> object .sha1 ));
377+ case DROP :
378+ /* Ignore this tag altogether */
379+ return ;
380+ case REWRITE :
381+ if (tagged -> type != OBJ_COMMIT ) {
382+ die ("Tag %s tags unexported %s!" ,
383+ sha1_to_hex (tag -> object .sha1 ),
384+ typename (tagged -> type ));
385+ }
386+ p = (struct commit * )tagged ;
387+ for (;;) {
388+ if (p -> parents && p -> parents -> next )
389+ break ;
390+ if (p -> object .flags & UNINTERESTING )
391+ break ;
392+ if (!(p -> object .flags & TREESAME ))
393+ break ;
394+ if (!p -> parents )
395+ die ("Can't find replacement commit for tag %s\n" ,
396+ sha1_to_hex (tag -> object .sha1 ));
397+ p = p -> parents -> item ;
398+ }
399+ tagged_mark = get_object_mark (& p -> object );
400+ }
401+ }
402+
336403 if (!prefixcmp (name , "refs/tags/" ))
337404 name += 10 ;
338405 printf ("tag %s\nfrom :%d\n%.*s%sdata %d\n%.*s\n" ,
339- name , get_object_mark ( tag -> tagged ) ,
406+ name , tagged_mark ,
340407 (int )(tagger_end - tagger ), tagger ,
341408 tagger == tagger_end ? "" : "\n" ,
342409 (int )message_size , (int )message_size , message ? message : "" );
@@ -504,6 +571,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
504571 OPT_CALLBACK (0 , "signed-tags" , & signed_tag_mode , "mode" ,
505572 "select handling of signed tags" ,
506573 parse_opt_signed_tag_mode ),
574+ OPT_CALLBACK (0 , "tag-of-filtered-object" , & tag_of_filtered_mode , "mode" ,
575+ "select handling of tags that tag filtered objects" ,
576+ parse_opt_tag_of_filtered_mode ),
507577 OPT_STRING (0 , "export-marks" , & export_filename , "FILE" ,
508578 "Dump marks to this file" ),
509579 OPT_STRING (0 , "import-marks" , & import_filename , "FILE" ,
@@ -520,6 +590,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
520590 git_config (git_default_config , NULL );
521591
522592 init_revisions (& revs , prefix );
593+ revs .topo_order = 1 ;
594+ revs .show_source = 1 ;
595+ revs .rewrite_parents = 1 ;
523596 argc = setup_revisions (argc , argv , & revs , NULL );
524597 argc = parse_options (argc , argv , prefix , options , fast_export_usage , 0 );
525598 if (argc > 1 )
@@ -530,18 +603,13 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
530603
531604 get_tags_and_duplicates (& revs .pending , & extra_refs );
532605
533- revs .topo_order = 1 ;
534606 if (prepare_revision_walk (& revs ))
535607 die ("revision walk setup failed" );
536608 revs .diffopt .format_callback = show_filemodify ;
537609 DIFF_OPT_SET (& revs .diffopt , RECURSIVE );
538610 while ((commit = get_revision (& revs ))) {
539611 if (has_unshown_parent (commit )) {
540- struct commit_list * parent = commit -> parents ;
541612 add_object_array (& commit -> object , NULL , & commits );
542- for (; parent ; parent = parent -> next )
543- if (!parent -> item -> util )
544- parent -> item -> util = commit -> util ;
545613 }
546614 else {
547615 handle_commit (commit , & revs );
0 commit comments