@@ -23,7 +23,8 @@ static const char *fast_export_usage[] = {
23
23
};
24
24
25
25
static 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 ;
27
28
static int fake_missing_tagger ;
28
29
29
30
static 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,
42
43
return 0 ;
43
44
}
44
45
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
+
45
60
static struct decoration idnums ;
46
61
static uint32_t last_idnum ;
47
62
@@ -289,6 +304,23 @@ static void handle_tag(const char *name, struct tag *tag)
289
304
char * buf ;
290
305
const char * tagger , * tagger_end , * message ;
291
306
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
+ }
292
324
293
325
buf = read_sha1_file (tag -> object .sha1 , & type , & size );
294
326
if (!buf )
@@ -333,10 +365,45 @@ static void handle_tag(const char *name, struct tag *tag)
333
365
}
334
366
}
335
367
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
+
336
403
if (!prefixcmp (name , "refs/tags/" ))
337
404
name += 10 ;
338
405
printf ("tag %s\nfrom :%d\n%.*s%sdata %d\n%.*s\n" ,
339
- name , get_object_mark ( tag -> tagged ) ,
406
+ name , tagged_mark ,
340
407
(int )(tagger_end - tagger ), tagger ,
341
408
tagger == tagger_end ? "" : "\n" ,
342
409
(int )message_size , (int )message_size , message ? message : "" );
@@ -504,6 +571,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
504
571
OPT_CALLBACK (0 , "signed-tags" , & signed_tag_mode , "mode" ,
505
572
"select handling of signed tags" ,
506
573
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 ),
507
577
OPT_STRING (0 , "export-marks" , & export_filename , "FILE" ,
508
578
"Dump marks to this file" ),
509
579
OPT_STRING (0 , "import-marks" , & import_filename , "FILE" ,
@@ -520,6 +590,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
520
590
git_config (git_default_config , NULL );
521
591
522
592
init_revisions (& revs , prefix );
593
+ revs .topo_order = 1 ;
594
+ revs .show_source = 1 ;
595
+ revs .rewrite_parents = 1 ;
523
596
argc = setup_revisions (argc , argv , & revs , NULL );
524
597
argc = parse_options (argc , argv , prefix , options , fast_export_usage , 0 );
525
598
if (argc > 1 )
@@ -530,18 +603,13 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
530
603
531
604
get_tags_and_duplicates (& revs .pending , & extra_refs );
532
605
533
- revs .topo_order = 1 ;
534
606
if (prepare_revision_walk (& revs ))
535
607
die ("revision walk setup failed" );
536
608
revs .diffopt .format_callback = show_filemodify ;
537
609
DIFF_OPT_SET (& revs .diffopt , RECURSIVE );
538
610
while ((commit = get_revision (& revs ))) {
539
611
if (has_unshown_parent (commit )) {
540
- struct commit_list * parent = commit -> parents ;
541
612
add_object_array (& commit -> object , NULL , & commits );
542
- for (; parent ; parent = parent -> next )
543
- if (!parent -> item -> util )
544
- parent -> item -> util = commit -> util ;
545
613
}
546
614
else {
547
615
handle_commit (commit , & revs );
0 commit comments