Merge branch 'en/fast-export'
authorJunio C Hamano <gitster@pobox.com>
Sun, 26 Jul 2009 18:23:52 +0000 (11:23 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 26 Jul 2009 18:23:52 +0000 (11:23 -0700)
* en/fast-export:
fast-export: Document the fact that git-rev-list arguments are accepted
Add new fast-export testcases
fast-export: Add a --tag-of-filtered-object option for newly dangling tags
fast-export: Do parent rewriting to avoid dropping relevant commits
fast-export: Make sure we show actual ref names instead of "(null)"
fast-export: Omit tags that tag trees
fast-export: Set revs.topo_order before calling setup_revisions

1  2 
builtin-fast-export.c
diff --combined builtin-fast-export.c
index ca198250c3082be82cdca09954198d6617b95bf8,dc2c6ab173972f408641f4376e0817c29b3321ef..c48c18d0c89d1050a531d0521135c2bed9e3b77d
@@@ -23,7 -23,8 +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,
        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;
  
@@@ -119,7 -134,7 +134,7 @@@ static void handle_object(const unsigne
  
        printf("blob\nmark :%"PRIu32"\ndata %lu\n", last_idnum, size);
        if (size && fwrite(buf, size, 1, stdout) != 1)
 -              die ("Could not write blob %s", sha1_to_hex(sha1));
 +              die_errno ("Could not write blob '%s'", sha1_to_hex(sha1));
        printf("\n");
  
        show_progress();
@@@ -289,6 -304,23 +304,23 @@@ static void handle_tag(const char *name
        char *buf;
        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
+        * 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)
                        }
        }
  
+       /* 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=<mode> 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 : "");
@@@ -428,27 -495,21 +495,27 @@@ static void export_marks(char *file
        uint32_t mark;
        struct object_decoration *deco = idnums.hash;
        FILE *f;
 +      int e = 0;
  
        f = fopen(file, "w");
        if (!f)
 -              error("Unable to open marks file %s for writing", file);
 +              error("Unable to open marks file %s for writing.", file);
  
        for (i = 0; i < idnums.size; i++) {
                if (deco->base && deco->base->type == 1) {
                        mark = ptr_to_mark(deco->decoration);
 -                      fprintf(f, ":%"PRIu32" %s\n", mark,
 -                              sha1_to_hex(deco->base->sha1));
 +                      if (fprintf(f, ":%"PRIu32" %s\n", mark,
 +                              sha1_to_hex(deco->base->sha1)) < 0) {
 +                          e = 1;
 +                          break;
 +                      }
                }
                deco++;
        }
  
 -      if (ferror(f) || fclose(f))
 +      e |= ferror(f);
 +      e |= fclose(f);
 +      if (e)
                error("Unable to write marks file %s.", file);
  }
  
@@@ -457,7 -518,7 +524,7 @@@ static void import_marks(char *input_fi
        char line[512];
        FILE *f = fopen(input_file, "r");
        if (!f)
 -              die("cannot read %s: %s", input_file, strerror(errno));
 +              die_errno("cannot read '%s'", input_file);
  
        while (fgets(line, sizeof(line), f)) {
                uint32_t mark;
@@@ -504,6 -565,9 +571,9 @@@ int cmd_fast_export(int argc, const cha
                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",
        git_config(git_default_config, NULL);
  
        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)
  
        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;
        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);