Skip to content

Commit 2d8ad46

Browse files
newrengitster
authored andcommitted
fast-export: Add a --tag-of-filtered-object option for newly dangling tags
When providing a list of paths to limit what is exported, the object that a tag points to can be filtered out entirely. This new switch allows the user to specify what should happen to the tag in such a case. The default action, 'abort' will exit with an error message. With 'drop', the tag will simply be omitted from the output. With 'rewrite', if the object tagged was a commit, the tag will be modified to tag an alternate commit. The alternate commit is determined by treating the original commit as the "parent" of the tag and then using the parent rewriting algorithm of the revision traversal machinery (related to the "--parents" option of "git rev-list") Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 3216413 commit 2d8ad46

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

Documentation/git-fast-export.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ when encountering a signed tag. With 'strip', the tags will be made
3636
unsigned, with 'verbatim', they will be silently exported
3737
and with 'warn', they will be exported, but you will see a warning.
3838

39+
--tag-of-filtered-object=(abort|drop|rewrite)::
40+
Specify how to handle tags whose tagged objectis filtered out.
41+
Since revisions and files to export can be limited by path,
42+
tagged objects may be filtered completely.
43+
+
44+
When asking to 'abort' (which is the default), this program will die
45+
when encountering such a tag. With 'drop' it will omit such tags from
46+
the output. With 'rewrite', if the tagged object is a commit, it will
47+
rewrite the tag to tag an ancestor commit (via parent rewriting; see
48+
linkgit:git-rev-list[1])
49+
3950
-M::
4051
-C::
4152
Perform move and/or copy detection, as described in the

builtin-fast-export.c

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ static const char *fast_export_usage[] = {
2323
};
2424

2525
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;
2728
static int fake_missing_tagger;
2829

2930
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,
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+
4560
static struct decoration idnums;
4661
static uint32_t last_idnum;
4762

@@ -290,6 +305,8 @@ static void handle_tag(const char *name, struct tag *tag)
290305
const char *tagger, *tagger_end, *message;
291306
size_t message_size = 0;
292307
struct object *tagged;
308+
int tagged_mark;
309+
struct commit *p;
293310

294311
/* Trees have no identifer in fast-export output, thus we have no way
295312
* to output tags of trees, tags of tags of trees, etc. Simply omit
@@ -348,10 +365,45 @@ static void handle_tag(const char *name, struct tag *tag)
348365
}
349366
}
350367

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+
351403
if (!prefixcmp(name, "refs/tags/"))
352404
name += 10;
353405
printf("tag %s\nfrom :%d\n%.*s%sdata %d\n%.*s\n",
354-
name, get_object_mark(tag->tagged),
406+
name, tagged_mark,
355407
(int)(tagger_end - tagger), tagger,
356408
tagger == tagger_end ? "" : "\n",
357409
(int)message_size, (int)message_size, message ? message : "");
@@ -513,6 +565,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
513565
OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, "mode",
514566
"select handling of signed tags",
515567
parse_opt_signed_tag_mode),
568+
OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, "mode",
569+
"select handling of tags that tag filtered objects",
570+
parse_opt_tag_of_filtered_mode),
516571
OPT_STRING(0, "export-marks", &export_filename, "FILE",
517572
"Dump marks to this file"),
518573
OPT_STRING(0, "import-marks", &import_filename, "FILE",

0 commit comments

Comments
 (0)