Commit Diff


commit - 25a102ed18cbd4e83888ece62f235f98117e0425
commit + f8836425010d0756365e9d64f63e3dfb517b1c6b
blob - bbeefdbe310df9fd0d9081fee286a6a2755f8201
blob + b7547794d998714acf55500591e26289b431c87e
--- lib/worktree.c
+++ lib/worktree.c
@@ -3881,8 +3881,75 @@ add_ignores_from_parent_paths(struct got_pathlist_head
 	free(next_parent_path);
 	return err;
 }
+
+struct find_missing_children_args {
+	const char *parent_path;
+	size_t parent_len;
+	struct got_pathlist_head *children;
+	got_cancel_cb cancel_cb;
+	void *cancel_arg;
 
+};
+
 static const struct got_error *
+find_missing_children(void *arg, struct got_fileindex_entry *ie)
+{
+	const struct got_error *err = NULL;
+	struct find_missing_children_args *a = arg;
+
+	if (a->cancel_cb) {
+		err = a->cancel_cb(a->cancel_arg);
+		if (err)
+			return err;
+	}
+
+	if (got_path_is_child(ie->path, a->parent_path, a->parent_len))
+		err = got_pathlist_append(a->children, ie->path, NULL);
+
+	return err;
+}
+
+static const struct got_error *
+report_children(struct got_pathlist_head *children,
+    struct got_worktree *worktree, struct got_fileindex *fileindex,
+    struct got_repository *repo, int is_root_dir, int report_unchanged,
+    struct got_pathlist_head *ignores, int no_ignores, 
+    got_worktree_status_cb status_cb, void *status_arg,
+    got_cancel_cb cancel_cb, void *cancel_arg)
+{
+	const struct got_error *err = NULL;
+	struct got_pathlist_entry *pe;
+	char *ondisk_path = NULL;
+
+	TAILQ_FOREACH(pe, children, entry) {
+		if (cancel_cb) {
+			err = cancel_cb(cancel_arg);
+			if (err)
+				break;
+		}
+
+		if (asprintf(&ondisk_path, "%s%s%s", worktree->root_path,
+		    !is_root_dir ? "/" : "", pe->path) == -1) {
+			err = got_error_from_errno("asprintf");
+			ondisk_path = NULL;
+			break;
+		}
+
+		err = report_single_file_status(pe->path, ondisk_path,
+		    fileindex, status_cb, status_arg, repo, report_unchanged,
+		    ignores, no_ignores);
+		if (err)
+			break;
+
+		free(ondisk_path);
+		ondisk_path = NULL;
+	}
+
+	free(ondisk_path);
+	return err;
+}
+
+static const struct got_error *
 worktree_status(struct got_worktree *worktree, const char *path,
     struct got_fileindex *fileindex, struct got_repository *repo,
     got_worktree_status_cb status_cb, void *status_arg,
@@ -3894,10 +3961,11 @@ worktree_status(struct got_worktree *worktree, const c
 	struct got_fileindex_diff_dir_cb fdiff_cb;
 	struct diff_dir_cb_arg arg;
 	char *ondisk_path = NULL;
-	struct got_pathlist_head ignores;
+	struct got_pathlist_head ignores, missing_children;
 	struct got_fileindex_entry *ie;
 
 	TAILQ_INIT(&ignores);
+	TAILQ_INIT(&missing_children);
 
 	if (asprintf(&ondisk_path, "%s%s%s",
 	    worktree->root_path, path[0] ? "/" : "", path) == -1)
@@ -3909,6 +3977,17 @@ worktree_status(struct got_worktree *worktree, const c
 		    fileindex, status_cb, status_arg, repo,
 		    report_unchanged, &ignores, no_ignores);
 		goto done;
+	} else {
+		struct find_missing_children_args fmca;
+		fmca.parent_path = path;
+		fmca.parent_len = strlen(path);
+		fmca.children = &missing_children;
+		fmca.cancel_cb = cancel_cb;
+		fmca.cancel_arg = cancel_arg;
+		err = got_fileindex_for_each_entry_safe(fileindex,
+		    find_missing_children, &fmca);
+		if (err)
+			goto done;
 	}
 
 	fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
@@ -3923,9 +4002,21 @@ worktree_status(struct got_worktree *worktree, const c
 				if (err)
 					goto done;
 			}
-			err = report_single_file_status(path, ondisk_path,
-			    fileindex, status_cb, status_arg, repo,
-			    report_unchanged, &ignores, no_ignores);
+			if (TAILQ_EMPTY(&missing_children)) {
+				err = report_single_file_status(path,
+				    ondisk_path, fileindex,
+				    status_cb, status_arg, repo,
+				    report_unchanged, &ignores, no_ignores);
+				if (err)
+					goto done;
+			} else {
+				err = report_children(&missing_children,
+				    worktree, fileindex, repo,
+				    (path[0] == '\0'), report_unchanged,
+				    &ignores, no_ignores,
+				    status_cb, status_arg,
+				    cancel_cb, cancel_arg);
+			}
 		}
 	} else {
 		fdiff_cb.diff_old_new = status_old_new;
blob - 3ae6b968f8817e9efb7b1abb879557fe19622e08
blob + dcea98961cf673717907f69c3761b59218c16e1a
--- regress/cmdline/revert.sh
+++ regress/cmdline/revert.sh
@@ -348,15 +348,50 @@ test_revert_directory_unknown() {
 
 	echo "new untracked file" > $testroot/content.expected
 	cat $testroot/wt/epsilon/new_file > $testroot/content
+
+	cmp -s $testroot/content.expected $testroot/content
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u $testroot/content.expected $testroot/content
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo "zeta" > $testroot/content.expected
+	cat $testroot/wt/epsilon/zeta > $testroot/content
 
 	cmp -s $testroot/content.expected $testroot/content
 	ret=$?
 	if [ $ret -ne 0 ]; then
 		diff -u $testroot/content.expected $testroot/content
+	fi
+
+	test_done "$testroot" "$ret"
+}
+
+test_revert_missing_directory() {
+	local testroot=`test_init revert_missing_directory`
+
+	got checkout $testroot/repo $testroot/wt > /dev/null
+	ret=$?
+	if [ $ret -ne 0 ]; then
 		test_done "$testroot" "$ret"
 		return 1
 	fi
 
+	rm -r $testroot/wt/epsilon
+
+	(cd $testroot/wt && got revert -R epsilon > $testroot/stdout)
+
+	echo 'R  epsilon/zeta' >> $testroot/stdout.expected
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
 	echo "zeta" > $testroot/content.expected
 	cat $testroot/wt/epsilon/zeta > $testroot/content
 
@@ -1533,6 +1568,7 @@ run_test test_revert_file_in_new_subdir
 run_test test_revert_no_arguments
 run_test test_revert_directory
 run_test test_revert_directory_unknown
+run_test test_revert_missing_directory
 run_test test_revert_patch
 run_test test_revert_patch_added
 run_test test_revert_patch_removed
blob - b48ce4011c7e953f442dffb07e92ceeb2fc2a62b
blob + 6d656a615120185ccc425dcf94d85399757b7de5
--- regress/cmdline/rm.sh
+++ regress/cmdline/rm.sh
@@ -648,7 +648,7 @@ test_rm_nonexistent_directory() {
 		return 1
 	fi
 
-	echo "got: epsilon: No such file or directory" \
+	echo "got: epsilon/zeta: No such file or directory" \
 		> $testroot/stderr.expected
 	cmp -s $testroot/stderr.expected $testroot/stderr
 	ret=$?
@@ -668,7 +668,7 @@ test_rm_nonexistent_directory() {
 		return 1
 	fi
 
-	echo -n '' > $testroot/stdout.expected
+	echo 'D  epsilon/zeta' > $testroot/stdout.expected
 	cmp -s $testroot/stdout.expected $testroot/stdout
 	ret=$?
 	if [ $ret -ne 0 ]; then