summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2014-07-31 21:16:40 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2014-07-31 21:16:40 +0200
commitb69256816f2ea27cfa99d906363fc292517b43a4 (patch)
tree8d2432dd34d2201286baeb194c6d3bb328ee25ba
parent28f087c8642ff9c8dd6964e101e6d8539db6281a (diff)
downloadlibgit2-b69256816f2ea27cfa99d906363fc292517b43a4.tar.gz
treebuilder: set the attributes before sorting and inserting
We need to set the attributes before we try to insert it into the vector, as the comparison function needs to know whether the entry is a tree or not.
-rw-r--r--src/tree.c9
-rw-r--r--tests/object/tree/write.c61
2 files changed, 67 insertions, 3 deletions
diff --git a/src/tree.c b/src/tree.c
index b64efe46..4ddb26b2 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -667,10 +667,16 @@ int git_treebuilder_insert(
entry->removed = 0;
bld->entrycount++;
}
+
+ entry->attr = filemode;
+ git_oid_cpy(&entry->oid, id);
} else {
entry = alloc_entry(filename);
GITERR_CHECK_ALLOC(entry);
+ entry->attr = filemode;
+ git_oid_cpy(&entry->oid, id);
+
if (git_vector_insert_sorted(&bld->entries, entry, NULL) < 0) {
git__free(entry);
return -1;
@@ -679,9 +685,6 @@ int git_treebuilder_insert(
bld->entrycount++;
}
- git_oid_cpy(&entry->oid, id);
- entry->attr = filemode;
-
if (entry_out)
*entry_out = entry;
diff --git a/tests/object/tree/write.c b/tests/object/tree/write.c
index 45356e80..ef7adaf2 100644
--- a/tests/object/tree/write.c
+++ b/tests/object/tree/write.c
@@ -396,3 +396,64 @@ void test_object_tree_write__cruel_paths(void)
git_tree_free(tree);
}
+
+void test_object_tree_write__from_tree_git_sorting(void)
+{
+ git_index *index;
+ git_odb *db;
+ git_treebuilder *bld;
+ git_oid first_tree = {{0}}, second_tree = {{0}}, subtree_id = {{0}}, second_tree_bld = {{0}};
+ git_tree *tree;
+ git_index_entry entry = {{0}};
+ const char *foo = "foo\n";
+ const char *bar = "bar\n";
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+ cl_git_pass(git_index_clear(index));
+ cl_git_pass(git_repository_odb(&db, g_repo));
+
+ cl_git_pass(git_odb_write(&entry.id, db, foo, strlen(foo), GIT_OBJ_BLOB));
+ entry.mode = GIT_FILEMODE_BLOB;
+ entry.path = "foo.txt";
+
+ cl_git_pass(git_index_add(index, &entry));
+ cl_git_pass(git_index_write_tree(&first_tree, index));
+
+ /* Clear the index and re-add so we don't use any tree caches */
+ cl_git_pass(git_index_clear(index));
+ cl_git_pass(git_index_add(index, &entry));
+
+ cl_git_pass(git_odb_write(&entry.id, db, bar, strlen(bar), GIT_OBJ_BLOB));
+ entry.mode = GIT_FILEMODE_BLOB;
+ entry.path = "foo/bar";
+
+ cl_git_pass(git_index_add(index, &entry));
+ cl_git_pass(git_index_write_tree(&second_tree, index));
+
+ /*
+ * The index has now written the tree from scratch. We will
+ * create a builder taking the first tree as a starting point
+ * and create the second tree.
+ */
+
+ cl_git_pass(git_treebuilder_create(&bld, NULL));
+
+ cl_git_pass(git_treebuilder_insert(NULL, bld, "bar", &entry.id, entry.mode));
+ cl_git_pass(git_treebuilder_write(&subtree_id, g_repo, bld));
+ git_treebuilder_free(bld);
+
+ /* assert subtree_id is the same as the one from the index */
+
+ cl_git_pass(git_tree_lookup(&tree, g_repo, &first_tree));
+ cl_git_pass(git_treebuilder_create(&bld, tree));
+
+ cl_git_pass(git_treebuilder_insert(NULL, bld, "foo", &subtree_id, GIT_FILEMODE_TREE));
+ cl_git_pass(git_treebuilder_write(&second_tree_bld, g_repo, bld));
+ git_treebuilder_free(bld);
+
+ cl_assert(!git_oid_cmp(&second_tree, &second_tree_bld));
+
+ git_tree_free(tree);
+ git_odb_free(db);
+ git_index_free(index);
+}