Commit baa7dcfad48fd8812ab361d99e8a4de476f107ec

Stefan Sperling 2019-05-08T20:00:37

don't visit added subtrees reundantly

diff --git a/lib/worktree.c b/lib/worktree.c
index bcc5c7a..3672855 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -2205,7 +2205,6 @@ struct commitable {
 	unsigned char status;
 	struct got_object_id *id;
 	struct got_object_id *base_id;
-	struct got_object_id *tree_id;
 };
 
 static void
@@ -2214,7 +2213,6 @@ free_commitable(struct commitable *ct)
 	free(ct->path);
 	free(ct->id);
 	free(ct->base_id);
-	free(ct->tree_id);
 	free(ct);
 }
 
@@ -2270,10 +2268,6 @@ collect_commitables(void *arg, unsigned char status, const char *relpath,
 			goto done;
 		}
 	}
-	err = got_object_id_by_path(&ct->tree_id, a->repo,
-	    a->worktree->base_commit_id, parent_path);
-	if (err)
-		goto done;
 	ct->path = strdup(path);
 	if (ct->path == NULL) {
 		err = got_error_from_errno();
@@ -2305,7 +2299,7 @@ write_subtree(struct got_object_id **new_subtree_id,
 	char *subpath;
 
 	if (asprintf(&subpath, "%s%s%s", parent_path,
-	    parent_path[0] == '\0' ? "" : "/", te->name) == -1)
+	    got_path_is_root_dir(parent_path) ? "" : "/", te->name) == -1)
 		return got_error_from_errno();
 
 	err = got_object_open_as_tree(&subtree, repo, te->id);
@@ -2523,6 +2517,8 @@ write_tree(struct got_object_id **new_tree_id,
 				goto done;
 		} else {
 			char *subtree_path;
+			struct got_pathlist_entry *pe2;
+			int visited = 0;
 
 			*slash = '\0'; /* trim trailing path components */
 
@@ -2534,18 +2530,27 @@ write_tree(struct got_object_id **new_tree_id,
 				err = got_error_from_errno();
 				goto done;
 			}
-			if (asprintf(&subtree_path, "%s/%s", path_base_tree,
+			if (asprintf(&subtree_path, "%s%s%s", path_base_tree,
+			    got_path_is_root_dir(path_base_tree) ? "" : "/",
 			    child_path) == -1) {
 				err = got_error_from_errno();
 				goto done;
 			}
-			err = write_subtree(&new_te->id, NULL, subtree_path,
+			TAILQ_FOREACH(pe2, &paths, entry) {
+				if (got_path_cmp(subtree_path, pe2->path) != 0)
+					continue;
+				visited = 1;
+				break;
+			}
+			if (visited)
+				continue;
+
+			err = write_tree(&new_te->id, NULL, subtree_path,
 			    commitable_paths, status_cb, status_arg, repo);
 			free(subtree_path);
 			if (err)
 				goto done;
 		}
-
 		err = insert_tree_entry(new_te, &paths);
 		if (err)
 			goto done;
diff --git a/regress/cmdline/commit.sh b/regress/cmdline/commit.sh
index 54f8171..3d14f78 100755
--- a/regress/cmdline/commit.sh
+++ b/regress/cmdline/commit.sh
@@ -50,4 +50,37 @@ function test_commit_basic {
 	test_done "$testroot" "$ret"
 }
 
+function test_commit_new_subdir {
+	local testroot=`test_init commit_new_subdir`
+
+	got checkout $testroot/repo $testroot/wt > /dev/null
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	mkdir -p $testroot/wt/d
+	echo "new file" > $testroot/wt/d/new
+	echo "another new file" > $testroot/wt/d/new2
+	(cd $testroot/wt && got add d/new >/dev/null)
+	(cd $testroot/wt && got add d/new2 >/dev/null)
+
+	(cd $testroot/wt && \
+		got commit -m 'test commit_new_subdir' > $testroot/stdout)
+
+	local head_rev=`git_show_head $testroot/repo`
+	echo "A  d/new" > $testroot/stdout.expected
+	echo "A  d/new2" >> $testroot/stdout.expected
+	echo "created commit $head_rev" >> $testroot/stdout.expected
+
+	cmp $testroot/stdout.expected $testroot/stdout
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+	fi
+	test_done "$testroot" "$ret"
+}
+
 run_test test_commit_basic
+run_test test_commit_new_subdir