Commit 85eb2cb67611483cc13c9d16589b88a6cb9dd19d

Edward Thomson 2018-08-26T11:33:42

Merge pull request #4727 from libgit2/cmn/null-oid-existing-tree tree: accept null ids in existing trees when updating

diff --git a/src/tree.c b/src/tree.c
index 8233857..e4a0547 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -460,15 +460,16 @@ static int append_entry(
 	git_treebuilder *bld,
 	const char *filename,
 	const git_oid *id,
-	git_filemode_t filemode)
+	git_filemode_t filemode,
+	bool validate)
 {
 	git_tree_entry *entry;
 	int error = 0;
 
-	if (!valid_entry_name(bld->repo, filename))
+	if (validate && !valid_entry_name(bld->repo, filename))
 		return tree_error("failed to insert entry: invalid name for a tree entry", filename);
 
-	if (git_oid_iszero(id))
+	if (validate && git_oid_iszero(id))
 		return tree_error("failed to insert entry: invalid null OID for a tree entry", filename);
 
 	entry = alloc_entry(filename, strlen(filename), id);
@@ -566,12 +567,12 @@ static int write_tree(
 				last_comp = subdir;
 			}
 
-			error = append_entry(bld, last_comp, &sub_oid, S_IFDIR);
+			error = append_entry(bld, last_comp, &sub_oid, S_IFDIR, true);
 			git__free(subdir);
 			if (error < 0)
 				goto on_error;
 		} else {
-			error = append_entry(bld, filename, &entry->id, entry->mode);
+			error = append_entry(bld, filename, &entry->id, entry->mode, true);
 			if (error < 0)
 				goto on_error;
 		}
@@ -669,7 +670,8 @@ int git_treebuilder_new(
 			if (append_entry(
 				bld, entry_src->filename,
 				entry_src->oid,
-				entry_src->attr) < 0)
+				entry_src->attr,
+				false) < 0)
 				goto on_error;
 		}
 	}
diff --git a/tests/object/tree/update.c b/tests/object/tree/update.c
index b76e861..41b50f3 100644
--- a/tests/object/tree/update.c
+++ b/tests/object/tree/update.c
@@ -284,3 +284,19 @@ void test_object_tree_update__add_conflict2(void)
 
 	cl_git_fail(git_tree_create_updated(&tree_updater_id, g_repo, NULL, 2, updates));
 }
+
+void test_object_tree_update__remove_invalid_submodule(void)
+{
+	git_tree *baseline;
+	git_oid updated_tree_id, baseline_id;
+	git_tree_update updates[] = {
+		{GIT_TREE_UPDATE_REMOVE, {{0}}, GIT_FILEMODE_BLOB, "submodule"},
+	};
+
+	/* This tree contains a submodule with an all-zero commit for a submodule named 'submodule' */
+	cl_git_pass(git_oid_fromstr(&baseline_id, "396c7f1adb7925f51ba13a75f48252f44c5a14a2"));
+	cl_git_pass(git_tree_lookup(&baseline, g_repo, &baseline_id));
+	cl_git_pass(git_tree_create_updated(&updated_tree_id, g_repo, baseline, 1, updates));
+
+	git_tree_free(baseline);
+}
diff --git a/tests/resources/testrepo2/.gitted/objects/39/6c7f1adb7925f51ba13a75f48252f44c5a14a2 b/tests/resources/testrepo2/.gitted/objects/39/6c7f1adb7925f51ba13a75f48252f44c5a14a2
new file mode 100644
index 0000000..667704b
Binary files /dev/null and b/tests/resources/testrepo2/.gitted/objects/39/6c7f1adb7925f51ba13a75f48252f44c5a14a2 differ