From 668f3aa776bcd293de08413bf1b25b91c15f1b01 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Thu, 25 Jun 2009 22:48:27 -0600 Subject: fast-export: Set revs.topo_order before calling setup_revisions setup_revisions sets a variety of flags based on the setting of other flags, such as setting the limited flag when topo_order is set. To avoid circumventing any invariants created by setup_revisions, we set revs.topo_order before calling it rather than after. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin-fast-export.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-fast-export.c') diff --git a/builtin-fast-export.c b/builtin-fast-export.c index 6cef81031..e0cfa606d 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -514,6 +514,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) git_config(git_default_config, NULL); init_revisions(&revs, prefix); + revs.topo_order = 1; argc = setup_revisions(argc, argv, &revs, NULL); argc = parse_options(argc, argv, prefix, options, fast_export_usage, 0); if (argc > 1) @@ -524,7 +525,6 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) get_tags_and_duplicates(&revs.pending, &extra_refs); - revs.topo_order = 1; if (prepare_revision_walk(&revs)) die("revision walk setup failed"); revs.diffopt.format_callback = show_filemodify; -- cgit v1.2.1 From 02c48cd69b3ebfac3867f0f9ceb1503a5af118fc Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Thu, 25 Jun 2009 22:48:28 -0600 Subject: fast-export: Omit tags that tag trees Commit c0582c53bcf4e83bba70e1ad23abbad31f96ebc8 introduced logic to just omit tags that point to tree objects. However, these objects were still being output and were pointing at "mark :0", which caused fast-import to crash. This patch makes sure such tags (including deeper nestings such as tags of tags of trees), are omitted. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin-fast-export.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'builtin-fast-export.c') diff --git a/builtin-fast-export.c b/builtin-fast-export.c index e0cfa606d..8c90a2df6 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -289,6 +289,21 @@ static void handle_tag(const char *name, struct tag *tag) char *buf; const char *tagger, *tagger_end, *message; size_t message_size = 0; + struct object *tagged; + + /* Trees have no identifer in fast-export output, thus we have no way + * to output tags of trees, tags of tags of trees, etc. Simply omit + * such tags. + */ + tagged = tag->tagged; + while (tagged->type == OBJ_TAG) { + tagged = ((struct tag *)tagged)->tagged; + } + if (tagged->type == OBJ_TREE) { + warning("Omitting tag %s,\nsince tags of trees (or tags of tags of trees, etc.) are not supported.", + sha1_to_hex(tag->object.sha1)); + return; + } buf = read_sha1_file(tag->object.sha1, &type, &size); if (!buf) -- cgit v1.2.1 From 2374502c6ca1c8007cb35682f13fb5db044df9ea Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Thu, 25 Jun 2009 22:48:29 -0600 Subject: fast-export: Make sure we show actual ref names instead of "(null)" The code expects a ref name to be provided in commit->util. While there was some code to set commit->util, it only worked in cases where there was an unbroken chain of revisions from a ref to the relevant commit. In cases such as running git fast-export --parents master -- COPYING commit->util would fail to be set. The old method of setting commit->util has been removed in favor of requesting show_source from the revision traversal machinery (related to the "--source" option of "git log" family of commands.) However, this change does not fix cases like git fast export master~1 or git fast export :/arguments since in such cases commit->util will be "master~1" or ":/arguments" while we need the actual ref (e.g. "refs/heads/master") Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin-fast-export.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'builtin-fast-export.c') diff --git a/builtin-fast-export.c b/builtin-fast-export.c index 8c90a2df6..43a7e17d3 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -530,6 +530,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) init_revisions(&revs, prefix); revs.topo_order = 1; + revs.show_source = 1; argc = setup_revisions(argc, argv, &revs, NULL); argc = parse_options(argc, argv, prefix, options, fast_export_usage, 0); if (argc > 1) @@ -546,11 +547,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) DIFF_OPT_SET(&revs.diffopt, RECURSIVE); while ((commit = get_revision(&revs))) { if (has_unshown_parent(commit)) { - struct commit_list *parent = commit->parents; add_object_array(&commit->object, NULL, &commits); - for (; parent; parent = parent->next) - if (!parent->item->util) - parent->item->util = commit->util; } else { handle_commit(commit, &revs); -- cgit v1.2.1 From 32164131db0984544b222ac515f95f917fa01441 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Thu, 25 Jun 2009 22:48:30 -0600 Subject: fast-export: Do parent rewriting to avoid dropping relevant commits When specifying paths to export, parent rewriting must be turned on for fast-export to output anything at all. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin-fast-export.c | 1 + 1 file changed, 1 insertion(+) (limited to 'builtin-fast-export.c') diff --git a/builtin-fast-export.c b/builtin-fast-export.c index 43a7e17d3..9b8bd3729 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -531,6 +531,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) init_revisions(&revs, prefix); revs.topo_order = 1; revs.show_source = 1; + revs.rewrite_parents = 1; argc = setup_revisions(argc, argv, &revs, NULL); argc = parse_options(argc, argv, prefix, options, fast_export_usage, 0); if (argc > 1) -- cgit v1.2.1 From 2d8ad46919213ebbd7bb72eb5b56cca8cc3ae07f Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Thu, 25 Jun 2009 22:48:31 -0600 Subject: 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 Signed-off-by: Junio C Hamano --- builtin-fast-export.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) (limited to 'builtin-fast-export.c') diff --git a/builtin-fast-export.c b/builtin-fast-export.c index 9b8bd3729..dc2c6ab17 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -23,7 +23,8 @@ static const char *fast_export_usage[] = { }; static int progress; -static enum { VERBATIM, WARN, STRIP, ABORT } signed_tag_mode = ABORT; +static enum { ABORT, VERBATIM, WARN, STRIP } signed_tag_mode = ABORT; +static enum { ERROR, DROP, REWRITE } tag_of_filtered_mode = ABORT; static int fake_missing_tagger; 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, return 0; } +static int parse_opt_tag_of_filtered_mode(const struct option *opt, + const char *arg, int unset) +{ + if (unset || !strcmp(arg, "abort")) + tag_of_filtered_mode = ABORT; + else if (!strcmp(arg, "drop")) + tag_of_filtered_mode = DROP; + else if (!strcmp(arg, "rewrite")) + tag_of_filtered_mode = REWRITE; + else + return error("Unknown tag-of-filtered mode: %s", arg); + return 0; +} + static struct decoration idnums; static uint32_t last_idnum; @@ -290,6 +305,8 @@ static void handle_tag(const char *name, struct tag *tag) const char *tagger, *tagger_end, *message; size_t message_size = 0; struct object *tagged; + int tagged_mark; + struct commit *p; /* Trees have no identifer in fast-export output, thus we have no way * 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) } } + /* handle tag->tagged having been filtered out due to paths specified */ + tagged = tag->tagged; + tagged_mark = get_object_mark(tagged); + if (!tagged_mark) { + switch(tag_of_filtered_mode) { + case ABORT: + die ("Tag %s tags unexported object; use " + "--tag-of-filtered-object= to handle it.", + sha1_to_hex(tag->object.sha1)); + case DROP: + /* Ignore this tag altogether */ + return; + case REWRITE: + if (tagged->type != OBJ_COMMIT) { + die ("Tag %s tags unexported %s!", + sha1_to_hex(tag->object.sha1), + typename(tagged->type)); + } + p = (struct commit *)tagged; + for (;;) { + if (p->parents && p->parents->next) + break; + if (p->object.flags & UNINTERESTING) + break; + if (!(p->object.flags & TREESAME)) + break; + if (!p->parents) + die ("Can't find replacement commit for tag %s\n", + sha1_to_hex(tag->object.sha1)); + p = p->parents->item; + } + tagged_mark = get_object_mark(&p->object); + } + } + if (!prefixcmp(name, "refs/tags/")) name += 10; printf("tag %s\nfrom :%d\n%.*s%sdata %d\n%.*s\n", - name, get_object_mark(tag->tagged), + name, tagged_mark, (int)(tagger_end - tagger), tagger, tagger == tagger_end ? "" : "\n", (int)message_size, (int)message_size, message ? message : ""); @@ -513,6 +565,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, "mode", "select handling of signed tags", parse_opt_signed_tag_mode), + OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, "mode", + "select handling of tags that tag filtered objects", + parse_opt_tag_of_filtered_mode), OPT_STRING(0, "export-marks", &export_filename, "FILE", "Dump marks to this file"), OPT_STRING(0, "import-marks", &import_filename, "FILE", -- cgit v1.2.1