Merge branch 'maint'
[gitweb.git] / builtin / fast-export.c
index 8c7760279d3022b7a47390435ce0d2d407e6ce1d..a9bbf8653d1a8fa704a38c06102ec3ace4a59a28 100644 (file)
@@ -148,10 +148,39 @@ static void handle_object(const unsigned char *sha1)
        free(buf);
 }
 
+static int depth_first(const void *a_, const void *b_)
+{
+       const struct diff_filepair *a = *((const struct diff_filepair **)a_);
+       const struct diff_filepair *b = *((const struct diff_filepair **)b_);
+       const char *name_a, *name_b;
+       int len_a, len_b, len;
+       int cmp;
+
+       name_a = a->one ? a->one->path : a->two->path;
+       name_b = b->one ? b->one->path : b->two->path;
+
+       len_a = strlen(name_a);
+       len_b = strlen(name_b);
+       len = (len_a < len_b) ? len_a : len_b;
+
+       /* strcmp will sort 'd' before 'd/e', we want 'd/e' before 'd' */
+       cmp = memcmp(name_a, name_b, len);
+       if (cmp)
+               return cmp;
+       return (len_b - len_a);
+}
+
 static void show_filemodify(struct diff_queue_struct *q,
                            struct diff_options *options, void *data)
 {
        int i;
+
+       /*
+        * Handle files below a directory first, in case they are all deleted
+        * and the directory changes to a file or symlink.
+        */
+       qsort(q->queue, q->nr, sizeof(q->queue[0]), depth_first);
+
        for (i = 0; i < q->nr; i++) {
                struct diff_filespec *ospec = q->queue[i]->one;
                struct diff_filespec *spec = q->queue[i]->two;
@@ -442,7 +471,7 @@ static void get_tags_and_duplicates(struct object_array *pending,
                        /* handle nested tags */
                        while (tag && tag->object.type == OBJ_TAG) {
                                parse_object(tag->object.sha1);
-                               string_list_append(full_name, extra_refs)->util = tag;
+                               string_list_append(extra_refs, full_name)->util = tag;
                                tag = (struct tag *)tag->tagged;
                        }
                        if (!tag)
@@ -468,7 +497,7 @@ static void get_tags_and_duplicates(struct object_array *pending,
                }
                if (commit->util)
                        /* more than one name for the same object */
-                       string_list_append(full_name, extra_refs)->util = commit;
+                       string_list_append(extra_refs, full_name)->util = commit;
                else
                        commit->util = full_name;
        }
@@ -569,8 +598,8 @@ static void import_marks(char *input_file)
 int cmd_fast_export(int argc, const char **argv, const char *prefix)
 {
        struct rev_info revs;
-       struct object_array commits = { 0, 0, NULL };
-       struct string_list extra_refs = { NULL, 0, 0, 0 };
+       struct object_array commits = OBJECT_ARRAY_INIT;
+       struct string_list extra_refs = STRING_LIST_INIT_NODUP;
        struct commit *commit;
        char *export_filename = NULL, *import_filename = NULL;
        struct option options[] = {