Commit 583833879463d520ccfbdfbf12d4dd69343c01bb

Vicent Marti 2014-08-01T15:21:13

Merge pull request #2494 from libgit2/cmn/treebuilder-set-attribute treebuilder: set the attributes before sorting and inserting

diff --git a/src/tree.c b/src/tree.c
index b64efe4..4ddb26b 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 45356e8..ef7adaf 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);
+}