summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 5a2580d)
raw | patch | inline | side by side (parent: 5a2580d)
author | Elijah Newren <newren@gmail.com> | |
Fri, 9 Jul 2010 13:10:55 +0000 (07:10 -0600) | ||
committer | Junio C Hamano <gitster@pobox.com> | |
Fri, 9 Jul 2010 23:16:29 +0000 (16:16 -0700) |
The fast-import stream format requires incremental changes which take place
immediately, meaning that for D->F conversions all files below the relevant
directory must be deleted before the resulting file of the same name is
created. Reversing the order can result in fast-import silently deleting
the file right after creating it, resulting in the file missing from the
resulting repository.
We correct this by first sorting the diff_queue_struct in depth-first
order.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
immediately, meaning that for D->F conversions all files below the relevant
directory must be deleted before the resulting file of the same name is
created. Reversing the order can result in fast-import silently deleting
the file right after creating it, resulting in the file missing from the
resulting repository.
We correct this by first sorting the diff_queue_struct in depth-first
order.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/fast-export.c | patch | blob | history | |
t/t9350-fast-export.sh | patch | blob | history |
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index c6dd71a7bcd0dfcb4691c9ca66a0c3a7bd4dcaae..965e90e5e8c78ce6b9587234fa251c509e6fbdd5 100644 (file)
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
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;
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 69179c61247bf05bc287c2a4b16ce2762dc4ac47..1ee1461c9bb38750b45e11ff9e5c72b1a6acf1db 100755 (executable)
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
test_expect_success 'tag-obj_tag' 'git fast-export tag-obj_tag'
test_expect_success 'tag-obj_tag-obj' 'git fast-export tag-obj_tag-obj'
-test_expect_failure 'directory becomes symlink' '
+test_expect_success 'directory becomes symlink' '
git init dirtosymlink &&
git init result &&
(