Commit Diff


commit - 4866d0842a2b34812818685aaa31d3e0a966412d
commit + 2b496619daecc1f25b1bc0c53e01685030dc2c74
blob - c68ca743bd5ba681fe40b097c08f23d275540824
blob + 6c06691116548c4c4bf246510416f6568ebfdb71
--- lib/worktree.c
+++ lib/worktree.c
@@ -2870,7 +2870,46 @@ match_deleted_or_modified_ct(struct got_commitable **c
 		*ctp = ct;
 		break;
 	}
+
+	return err;
+}
+
+static const struct got_error *
+make_subtree_for_added_blob(struct got_tree_entry **new_tep,
+    const char *child_path, const char *path_base_tree,
+    struct got_pathlist_head *commitable_paths,
+    got_worktree_status_cb status_cb, void *status_arg,
+    struct got_repository *repo)
+{
+	const struct got_error *err = NULL;
+	struct got_tree_entry *new_te;
+	char *subtree_path;
+
+	*new_tep = NULL;
+
+	if (asprintf(&subtree_path, "%s%s%s", path_base_tree,
+	    got_path_is_root_dir(path_base_tree) ? "" : "/",
+	    child_path) == -1)
+		return got_error_from_errno("asprintf");
 
+	new_te = calloc(1, sizeof(*new_te));
+	new_te->mode = S_IFDIR;
+	new_te->name = strdup(child_path);
+	if (new_te->name == NULL) {
+		err = got_error_from_errno("strdup");
+		got_object_tree_entry_close(new_te);
+		goto done;
+	}
+	err = write_tree(&new_te->id, NULL, subtree_path,
+	    commitable_paths, status_cb, status_arg, repo);
+	if (err) {
+		got_object_tree_entry_close(new_te);
+		goto done;
+	}
+done:
+	free(subtree_path);
+	if (err == NULL)
+		*new_tep = new_te;
 	return err;
 }
 
@@ -2919,38 +2958,25 @@ write_tree(struct got_object_id **new_tree_id,
 			if (err)
 				goto done;
 			ct->flags |= GOT_COMMITABLE_ADDED;
-		} else {
-			char *subtree_path;
-
-			*slash = '\0'; /* trim trailing path components */
-			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("asprintf");
+			err = insert_tree_entry(new_te, &paths);
+			if (err)
 				goto done;
-			}
-
-			new_te = calloc(1, sizeof(*new_te));
-			new_te->mode = S_IFDIR;
-			new_te->name = strdup(child_path);
-			if (new_te->name == NULL) {
-				err = got_error_from_errno("strdup");
-				got_object_tree_entry_close(new_te);
-				new_te = NULL;
-				goto done;
-			}
-			err = write_tree(&new_te->id, NULL, subtree_path,
-			    commitable_paths, status_cb, status_arg, repo);
-			free(subtree_path);
-			if (err) {
-				got_object_tree_entry_close(new_te);
-				new_te = NULL;
-				goto done;
+		} else {
+			*slash = '\0'; /* trim trailing path components */
+			if (base_tree == NULL ||
+			    got_object_tree_find_entry(base_tree, child_path)
+			    == NULL) {
+				err = make_subtree_for_added_blob(&new_te,
+				    child_path, path_base_tree,
+				    commitable_paths, status_cb, status_arg,
+				    repo);
+				if (err)
+					goto done;
+				err = insert_tree_entry(new_te, &paths);
+				if (err)
+					goto done;
 			}
 		}
-		err = insert_tree_entry(new_te, &paths);
-		if (err)
-			goto done;
 	}
 
 	if (base_tree) {
blob - 3a97ed55c77d90d9576fa91da49828518da37c33
blob + fa62e4aace284747229f3636273843d3bf884f9a
--- regress/cmdline/commit.sh
+++ regress/cmdline/commit.sh
@@ -301,8 +301,6 @@ function test_commit_single_file_multiple {
 	test_done "$testroot" "0"
 }
 
-# This test currently fails because the writing trees during commit does
-# not properly account for trees which contain both added and modified files.
 function test_commit_added_and_modified_in_same_dir {
 	local testroot=`test_init commit_added_and_modified_in_same_dir`
 
@@ -329,8 +327,7 @@ function test_commit_added_and_modified_in_same_dir {
 	cmp -s $testroot/stdout.expected $testroot/stdout
 	ret="$?"
 	if [ "$ret" != "0" ]; then
-		#diff -u $testroot/stdout.expected $testroot/stdout
-		ret="xfail ($(head -n 1 $testroot/stderr))"
+		diff -u $testroot/stdout.expected $testroot/stdout
 	fi
 	test_done "$testroot" "$ret"
 }