Commit 70e3e7f5a129106c0c31204233b35dfdf0d6a990

Tracey Emery 2019-12-13T20:05:57

add -k option to 'got remove' to keep files on disk ok stsp

diff --git a/got/got.1 b/got/got.1
index 42403d1..891a15a 100644
--- a/got/got.1
+++ b/got/got.1
@@ -645,7 +645,7 @@ With -R, add files even if they match a
 .Cm got status
 ignore pattern.
 .El
-.It Cm remove Oo Fl R Oc Ar file-path ...
+.It Cm remove Oo Fl f Oc Oo Fl k Oc Oo Fl R Oc Ar file-path ...
 Remove versioned files from a work tree and schedule them for deletion
 from the repository in the next commit.
 .Pp
@@ -655,6 +655,8 @@ are as follows:
 .Bl -tag -width Ds
 .It Fl f
 Perform the operation even if a file contains uncommitted modifications.
+.It Fl k
+Keep affected files on disk.
 .It Fl R
 Permit recursion into directories.
 If this option is not specified,
diff --git a/got/got.c b/got/got.c
index 8c969b3..a79e458 100644
--- a/got/got.c
+++ b/got/got.c
@@ -4296,7 +4296,7 @@ done:
 __dead static void
 usage_remove(void)
 {
-	fprintf(stderr, "usage: %s remove [-f] [-R] file-path ...\n",
+	fprintf(stderr, "usage: %s remove [-f] [-k] [-R] file-path ...\n",
 	    getprogname());
 	exit(1);
 }
@@ -4324,15 +4324,18 @@ cmd_remove(int argc, char *argv[])
 	char *cwd = NULL;
 	struct got_pathlist_head paths;
 	struct got_pathlist_entry *pe;
-	int ch, delete_local_mods = 0, can_recurse = 0;
+	int ch, delete_local_mods = 0, can_recurse = 0, keep_on_disk = 0;
 
 	TAILQ_INIT(&paths);
 
-	while ((ch = getopt(argc, argv, "fR")) != -1) {
+	while ((ch = getopt(argc, argv, "fkR")) != -1) {
 		switch (ch) {
 		case 'f':
 			delete_local_mods = 1;
 			break;
+		case 'k':
+			keep_on_disk = 1;
+			break;
 		case 'R':
 			can_recurse = 1;
 			break;
@@ -4406,7 +4409,7 @@ cmd_remove(int argc, char *argv[])
 	}
 
 	error = got_worktree_schedule_delete(worktree, &paths,
-	    delete_local_mods, print_remove_status, NULL, repo);
+	    delete_local_mods, print_remove_status, NULL, repo, keep_on_disk);
 	if (error)
 		goto done;
 done:
diff --git a/include/got_worktree.h b/include/got_worktree.h
index 336d163..09b7625 100644
--- a/include/got_worktree.h
+++ b/include/got_worktree.h
@@ -180,7 +180,7 @@ const struct got_error *got_worktree_schedule_add(struct got_worktree *,
 const struct got_error *
 got_worktree_schedule_delete(struct got_worktree *,
     struct got_pathlist_head *, int, got_worktree_delete_cb, void *,
-    struct got_repository *);
+    struct got_repository *, int);
 
 /* A callback function which is used to select or reject a patch. */
 typedef const struct got_error *(*got_worktree_patch_cb)(int *, void *,
diff --git a/lib/worktree.c b/lib/worktree.c
index 2e614c8..1c03382 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -2929,6 +2929,7 @@ struct schedule_deletion_args {
 	void *progress_arg;
 	struct got_repository *repo;
 	int delete_local_mods;
+	int keep_on_disk;
 };
 
 static const struct got_error *
@@ -2977,7 +2978,7 @@ schedule_for_deletion(void *arg, unsigned char status,
 		}
 	}
 
-	if (status != GOT_STATUS_MISSING) {
+	if (!a->keep_on_disk && status != GOT_STATUS_MISSING) {
 		if (dirfd != -1) {
 			if (unlinkat(dirfd, de_name, 0) != 0) {
 				err = got_error_from_errno2("unlinkat",
@@ -3005,7 +3006,7 @@ const struct got_error *
 got_worktree_schedule_delete(struct got_worktree *worktree,
     struct got_pathlist_head *paths, int delete_local_mods,
     got_worktree_delete_cb progress_cb, void *progress_arg,
-    struct got_repository *repo)
+    struct got_repository *repo, int keep_on_disk)
 {
 	struct got_fileindex *fileindex = NULL;
 	char *fileindex_path = NULL;
@@ -3027,6 +3028,7 @@ got_worktree_schedule_delete(struct got_worktree *worktree,
 	sda.progress_arg = progress_arg;
 	sda.repo = repo;
 	sda.delete_local_mods = delete_local_mods;
+	sda.keep_on_disk = keep_on_disk;
 
 	TAILQ_FOREACH(pe, paths, entry) {
 		err = worktree_status(worktree, pe->path, fileindex, repo,
diff --git a/regress/cmdline/rm.sh b/regress/cmdline/rm.sh
index 551feb1..9ea8be8 100755
--- a/regress/cmdline/rm.sh
+++ b/regress/cmdline/rm.sh
@@ -242,8 +242,89 @@ function test_rm_directory {
 	test_done "$testroot" "$ret"
 }
 
+function test_rm_directory_keep_files {
+	local testroot=`test_init rm_directory`
+
+	got checkout $testroot/repo $testroot/wt > /dev/null
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	(cd $testroot/wt && got rm . > $testroot/stdout 2> $testroot/stderr)
+	ret="$?"
+	echo "got: removing directories requires -R option" \
+		> $testroot/stderr.expected
+	cmp -s $testroot/stderr.expected $testroot/stderr
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stderr.expected $testroot/stderr
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo -n > $testroot/stdout.expected
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	(cd $testroot/wt && got rm -k -R . > $testroot/stdout)
+
+	echo 'D  alpha' > $testroot/stdout.expected
+	echo 'D  beta' >> $testroot/stdout.expected
+	echo 'D  epsilon/zeta' >> $testroot/stdout.expected
+	echo 'D  gamma/delta' >> $testroot/stdout.expected
+
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	(cd $testroot/wt && got st . > $testroot/stdout)
+
+	echo 'D  alpha' > $testroot/stdout.expected
+	echo 'D  beta' >> $testroot/stdout.expected
+	echo 'D  epsilon/zeta' >> $testroot/stdout.expected
+	echo 'D  gamma/delta' >> $testroot/stdout.expected
+
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	(cd $testroot/wt && got commit -m "keep" > /dev/null)
+	(cd $testroot/wt && got st . > $testroot/stdout)
+
+	echo '?  alpha' > $testroot/stdout.expected
+	echo '?  beta' >> $testroot/stdout.expected
+	echo '?  epsilon/zeta' >> $testroot/stdout.expected
+	echo '?  gamma/delta' >> $testroot/stdout.expected
+
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	test_done "$testroot" "$ret"
+}
+
 run_test test_rm_basic
 run_test test_rm_with_local_mods
 run_test test_double_rm
 run_test test_rm_and_add_elsewhere
 run_test test_rm_directory
+run_test test_rm_directory_keep_files