commit - 92228c38cdd5d16ccd0505c2580c3a6dc7e3c10b
commit + 17ed46186c2a79ae984817ddcdab9f803f23636a
blob - 8f54d73de965624d4580dfe1b34497c3bbc299ee
blob + aca7b79e0e5080b9d461a192939085492d710c60
--- TODO
+++ TODO
lib:
- handle checkout of trees which contain submodules by identifying and
ignoring such tree entries; requires a .ini config parser (from isakmpd?)
-- allow removing multiple paths at once for 'got rm'
- allow adding directory paths with 'got add'
- recursive addition: got add -R
- recursive removal: got rm -R
blob - 524d8eee79bef0ea730e3b19bbcda19891667168
blob + 4790d3daa456337e94fc78e750586101b308afa2
--- got/got.1
+++ got/got.1
.It Cm add Ar file-path ...
Schedule unversioned files in a work tree for addition to the
repository in the next commit.
-.It Cm rm Ar file-path
-Remove a versioned file from a work tree and schedule it for deletion
+.It Cm rm Ar file-path ...
+Remove versioned files from a work tree and schedule them for deletion
from the repository in the next commit.
.Pp
The options for
are as follows:
.Bl -tag -width Ds
.It Fl f
-Perform the operation even if the file contains uncommitted modifications.
+Perform the operation even if a file contains uncommitted modifications.
.El
.It Cm revert Ar file-path
Revert any uncommited changes in the file at the specified path.
blob - fd6712a8a82ee0d50d4a511136d1704b36783aa5
blob + 5b82d9b91538794dff2694713b051107efd74e9e
--- got/got.c
+++ got/got.c
const struct got_error *error = NULL;
struct got_worktree *worktree = NULL;
struct got_repository *repo = NULL;
- char *cwd = NULL, *path = NULL;
- int ch, delete_local_mods = 0;
+ char *cwd = NULL;
+ struct got_pathlist_head paths;
+ struct got_pathlist_entry *pe;
+ int ch, i, delete_local_mods = 0;
+ TAILQ_INIT(&paths);
+
while ((ch = getopt(argc, argv, "f")) != -1) {
switch (ch) {
case 'f':
argc -= optind;
argv += optind;
- if (argc != 1)
+ if (argc < 1)
usage_rm();
- path = realpath(argv[0], NULL);
- if (path == NULL) {
- error = got_error_from_errno2("realpath", argv[0]);
- goto done;
+ /* make sure each file exists before doing anything halfway */
+ for (i = 0; i < argc; i++) {
+ char *path = realpath(argv[i], NULL);
+ if (path == NULL) {
+ error = got_error_from_errno2("realpath", argv[i]);
+ goto done;
+ }
+ free(path);
}
- got_path_strip_trailing_slashes(path);
cwd = getcwd(NULL, 0);
if (cwd == NULL) {
if (error)
goto done;
- error = got_worktree_schedule_delete(worktree, path, delete_local_mods,
- print_status, NULL, repo);
+ for (i = 0; i < argc; i++) {
+ char *path = realpath(argv[i], NULL);
+ if (path == NULL) {
+ error = got_error_from_errno2("realpath", argv[i]);
+ goto done;
+ }
+
+ got_path_strip_trailing_slashes(path);
+ error = got_pathlist_insert(&pe, &paths, path, NULL);
+ if (error) {
+ free(path);
+ goto done;
+ }
+ }
+ error = got_worktree_schedule_delete(worktree, &paths,
+ delete_local_mods, print_status, NULL, repo);
if (error)
goto done;
done:
got_repo_close(repo);
if (worktree)
got_worktree_close(worktree);
- free(path);
+ TAILQ_FOREACH(pe, &paths, entry)
+ free((char *)pe->path);
+ got_pathlist_free(&paths);
free(cwd);
return error;
}
blob - 5dbd06969f53eeda039f83786a72a2a24d10e5bf
blob + 91899731f8655f5772579fe3e40e0e2716cb82e3
--- include/got_worktree.h
+++ include/got_worktree.h
struct got_repository *);
/*
- * Remove a file from disk and schedule it to be deleted in the next commit.
+ * Remove files from disk and schedule them to be deleted in the next commit.
* Don't allow deleting files with uncommitted modifications, unless the
* parameter 'delete_local_mods' is set.
*/
const struct got_error *
-got_worktree_schedule_delete(struct got_worktree *, const char *, int,
- got_worktree_status_cb, void *, struct got_repository *);
+got_worktree_schedule_delete(struct got_worktree *,
+ struct got_pathlist_head *, int, got_worktree_status_cb, void *,
+ struct got_repository *);
/*
* Revert a file at the specified path such that it matches its
blob - ca87d48087173582492bf1fbb809c2e55b333e27
blob + 39f7d97dd22baa55d4d1314bf1fb2f3a1875a135
--- lib/worktree.c
+++ lib/worktree.c
err = unlockerr;
return err;
}
+
+static const struct got_error *
+schedule_for_deletion(const char *ondisk_path, struct got_fileindex *fileindex,
+ const char *relpath, int delete_local_mods,
+ got_worktree_status_cb status_cb, void *status_arg,
+ struct got_repository *repo)
+{
+ const struct got_error *err = NULL;
+ struct got_fileindex_entry *ie = NULL;
+ unsigned char status;
+ struct stat sb;
+
+ ie = got_fileindex_entry_get(fileindex, relpath);
+ if (ie == NULL)
+ return got_error(GOT_ERR_BAD_PATH);
+ err = get_file_status(&status, &sb, ie, ondisk_path, repo);
+ if (err)
+ return err;
+
+ if (status != GOT_STATUS_NO_CHANGE) {
+ if (status == GOT_STATUS_DELETE)
+ return got_error_set_errno(ENOENT, ondisk_path);
+ if (status != GOT_STATUS_MODIFY)
+ return got_error(GOT_ERR_FILE_STATUS);
+ if (!delete_local_mods)
+ return got_error(GOT_ERR_FILE_MODIFIED);
+ }
+
+ if (unlink(ondisk_path) != 0)
+ return got_error_from_errno2("unlink", ondisk_path);
+
+ got_fileindex_entry_mark_deleted_from_disk(ie);
+ return report_file_status(ie, ondisk_path, status_cb, status_arg, repo);
+}
+
const struct got_error *
got_worktree_schedule_delete(struct got_worktree *worktree,
- const char *ondisk_path, int delete_local_mods,
+ struct got_pathlist_head *ondisk_paths, int delete_local_mods,
got_worktree_status_cb status_cb, void *status_arg,
struct got_repository *repo)
{
struct got_fileindex *fileindex = NULL;
- struct got_fileindex_entry *ie = NULL;
- char *relpath, *fileindex_path ;
+ char *fileindex_path = NULL;
FILE *index = NULL;
const struct got_error *err = NULL, *unlockerr = NULL;
- unsigned char status;
- struct stat sb;
+ struct got_pathlist_entry *pe;
err = lock_worktree(worktree, LOCK_EX);
if (err)
return err;
-
- err = got_path_skip_common_ancestor(&relpath,
- got_worktree_get_root_path(worktree), ondisk_path);
- if (err)
- goto done;
fileindex = got_fileindex_alloc();
if (fileindex == NULL) {
if (err)
goto done;
- ie = got_fileindex_entry_get(fileindex, relpath);
- if (ie == NULL) {
- err = got_error(GOT_ERR_BAD_PATH);
- goto done;
- }
-
- err = get_file_status(&status, &sb, ie, ondisk_path, repo);
- if (err)
- goto done;
-
- if (status != GOT_STATUS_NO_CHANGE) {
- if (status == GOT_STATUS_DELETE) {
- err = got_error_set_errno(ENOENT, ondisk_path);
- goto done;
- }
- if (status != GOT_STATUS_MODIFY) {
- err = got_error(GOT_ERR_FILE_STATUS);
+ TAILQ_FOREACH(pe, ondisk_paths, entry) {
+ char *relpath;
+ err = got_path_skip_common_ancestor(&relpath,
+ got_worktree_get_root_path(worktree), pe->path);
+ if (err)
goto done;
- }
- if (!delete_local_mods) {
- err = got_error(GOT_ERR_FILE_MODIFIED);
+ err = schedule_for_deletion(pe->path, fileindex, relpath,
+ delete_local_mods, status_cb, status_arg, repo);
+ free(relpath);
+ if (err)
goto done;
- }
- }
-
- if (unlink(ondisk_path) != 0) {
- err = got_error_from_errno2("unlink", ondisk_path);
- goto done;
}
- got_fileindex_entry_mark_deleted_from_disk(ie);
-
err = sync_fileindex(fileindex, fileindex_path);
if (err)
goto done;
-
- err = report_file_status(ie, ondisk_path, status_cb, status_arg, repo);
done:
- free(relpath);
if (index) {
if (fclose(index) != 0 && err == NULL)
err = got_error_from_errno("fclose");
blob - bb717cac07e1b3f367f8a6d63f607e748587f356
blob + 34059af1fb4817e58dffc51d50920a50a7eb7522
--- regress/cmdline/rm.sh
+++ regress/cmdline/rm.sh
return 1
fi
- echo 'D beta' > $testroot/stdout.expected
- (cd $testroot/wt && got rm beta > $testroot/stdout)
+ echo 'D alpha' > $testroot/stdout.expected
+ echo 'D beta' >> $testroot/stdout.expected
+ (cd $testroot/wt && got rm alpha beta > $testroot/stdout)
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
- if [ -e $testroot/wt/beta ]; then
- echo "removed file beta still exists on disk" >&2
- test_done "$testroot" "1"
+ (cd $testroot/wt && got status > $testroot/stdout)
+
+ 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"
+ for f in alpha beta; do
+ if [ -e $testroot/wt/$f ]; then
+ echo "removed file $f still exists on disk" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+ done
+
+ test_done "$testroot" "0"
}
function test_rm_with_local_mods {