commit - 6a5eff7c93868c5577c7d59c31aabc317824b34b
commit + 4e68cba3de6663791e40fa15f1eecbc4a2bf724c
blob - 9320a0971ee4f04fb9c3ff5cda31e6ceae91d2ea
blob + 9c0c3772a7c0a876c6e1fc5ae868fe928503cb90
--- got/got.1
+++ got/got.1
command may be used to delete a tag's reference.
This should only be done if the tag has not already been copied to
another repository.
-.It Cm add Ar file-path ...
+.It Cm add Oo Fl R Oc Ar path ...
Schedule unversioned files in a work tree for addition to the
repository in the next commit.
+.Pp
+The options for
+.Cm got add
+are as follows:
+.Bl -tag -width Ds
+.It Fl R
+Permit recursion into directories.
+If this option is not specified,
+.Cm got add
+will refuse to run if a specified
+.Ar path
+is a directory.
+.El
.It Cm remove Ar file-path ...
Remove versioned files from a work tree and schedule them for deletion
from the repository in the next commit.
blob - 3b8935895b310dbf4148cef5f6f4b5722e0369ba
blob + 776fb4c2ed06b1f5eaa6573a02ff26a086f3701b
--- got/got.c
+++ got/got.c
}
static const struct got_error *
+add_progress(void *arg, unsigned char status, const char *path)
+{
+ while (path[0] == '/')
+ path++;
+ printf("%c %s\n", status, path);
+ return NULL;
+}
+
+static const struct got_error *
cmd_add(int argc, char *argv[])
{
const struct got_error *error = NULL;
char *cwd = NULL;
struct got_pathlist_head paths;
struct got_pathlist_entry *pe;
- int ch;
+ int ch, can_recurse = 0;
TAILQ_INIT(&paths);
- while ((ch = getopt(argc, argv, "")) != -1) {
+ while ((ch = getopt(argc, argv, "R")) != -1) {
switch (ch) {
+ case 'R':
+ can_recurse = 1;
+ break;
default:
usage_add();
/* NOTREACHED */
if (error)
goto done;
- error = got_worktree_schedule_add(worktree, &paths, print_status,
+ if (!can_recurse) {
+ char *ondisk_path;
+ struct stat sb;
+ TAILQ_FOREACH(pe, &paths, entry) {
+ if (asprintf(&ondisk_path, "%s/%s",
+ got_worktree_get_root_path(worktree),
+ pe->path) == -1) {
+ error = got_error_from_errno("asprintf");
+ goto done;
+ }
+ if (lstat(ondisk_path, &sb) == -1) {
+ if (errno == ENOENT) {
+ free(ondisk_path);
+ continue;
+ }
+ error = got_error_from_errno2("lstat",
+ ondisk_path);
+ free(ondisk_path);
+ goto done;
+ }
+ free(ondisk_path);
+ if (S_ISDIR(sb.st_mode)) {
+ error = got_error_msg(GOT_ERR_BAD_PATH,
+ "adding directories requires -R option");
+ goto done;
+ }
+ }
+ }
+ error = got_worktree_schedule_add(worktree, &paths, add_progress,
NULL, repo);
done:
if (repo)
blob - 336553780903efcf81551b9db8c4a76a0ab2f148
blob + a18fc5a59d6c2c165d6f449c5accb262eb450485
--- include/got_worktree.h
+++ include/got_worktree.h
/* Schedule files at on-disk paths for addition in the next commit. */
const struct got_error *got_worktree_schedule_add(struct got_worktree *,
- struct got_pathlist_head *, got_worktree_status_cb, void *,
+ struct got_pathlist_head *, got_worktree_checkout_cb, void *,
struct got_repository *);
/*
blob - e841520c6fbc877de575ee04d69018206ea0391f
blob + 69f0ca5bcbdcdd0f823c7d47d32883b26350c9ad
--- lib/worktree.c
+++ lib/worktree.c
err = read_ignores(ignores, path, ignoresfile);
if (ignoresfile && fclose(ignoresfile) == EOF && err == NULL)
- err = got_error_from_errno2("flose", path);
+ err = got_error_from_errno2("fclose", path);
free(ignorespath);
return err;
}
return err;
}
-static const struct got_error *
-schedule_addition(const char *ondisk_path, struct got_fileindex *fileindex,
- const char *relpath, got_worktree_status_cb status_cb, void *status_arg,
- struct got_repository *repo)
+struct schedule_addition_args {
+ struct got_worktree *worktree;
+ struct got_fileindex *fileindex;
+ const char *ondisk_path;
+ got_worktree_checkout_cb progress_cb;
+ void *progress_arg;
+ struct got_repository *repo;
+};
+
+static const struct got_error *
+schedule_addition(void *arg, unsigned char status, unsigned char staged_status,
+ const char *relpath, struct got_object_id *blob_id,
+ struct got_object_id *staged_blob_id, struct got_object_id *commit_id)
{
+ struct schedule_addition_args *a = arg;
const struct got_error *err = NULL;
struct got_fileindex_entry *ie;
- unsigned char status;
struct stat sb;
+ char *path = NULL;
- ie = got_fileindex_entry_get(fileindex, relpath, strlen(relpath));
+ ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
if (ie) {
- err = get_file_status(&status, &sb, ie, ondisk_path, repo);
+ err = get_file_status(&status, &sb, ie, a->ondisk_path,
+ a->repo);
if (err)
return err;
/* Re-adding an existing entry is a no-op. */
return got_error_path(relpath, GOT_ERR_FILE_STATUS);
}
- err = got_fileindex_entry_alloc(&ie, ondisk_path, relpath, NULL, NULL);
- if (err)
- return err;
+ if (status == GOT_STATUS_UNVERSIONED) {
+ if (lstat(a->ondisk_path, &sb) != 0) {
+ err = got_error_from_errno2("lstat", a->ondisk_path);
+ return err;
+ }
+ if (S_ISDIR(sb.st_mode)) {
+ if (asprintf(&path, "%s/%s",
+ got_worktree_get_root_path(a->worktree),
+ relpath) == -1) {
+ err = got_error_from_errno("asprintf");
+ return err;
+ }
+ } else
+ path = strdup(a->ondisk_path);
+ }
- err = got_fileindex_entry_add(fileindex, ie);
+ err = got_fileindex_entry_alloc(&ie, path, relpath, NULL, NULL);
+ if (err)
+ goto done;
+
+ err = got_fileindex_entry_add(a->fileindex, ie);
if (err) {
got_fileindex_entry_free(ie);
- return err;
+ goto done;
}
- return report_file_status(ie, ondisk_path, status_cb, status_arg, repo);
+ free(path);
+ return (*a->progress_cb)(a->progress_arg,
+ GOT_STATUS_ADD, relpath);
+done:
+ free(path);
+ return err;
}
const struct got_error *
got_worktree_schedule_add(struct got_worktree *worktree,
struct got_pathlist_head *paths,
- got_worktree_status_cb status_cb, void *status_arg,
+ got_worktree_checkout_cb progress_cb, void *progress_arg,
struct got_repository *repo)
{
struct got_fileindex *fileindex = NULL;
char *fileindex_path = NULL;
const struct got_error *err = NULL, *sync_err, *unlockerr;
struct got_pathlist_entry *pe;
+ struct schedule_addition_args saa;
err = lock_worktree(worktree, LOCK_EX);
if (err)
if (err)
goto done;
+ saa.worktree = worktree;
+ saa.fileindex = fileindex;
+ saa.progress_cb = progress_cb;
+ saa.progress_arg = progress_arg;
+ saa.repo = repo;
+
TAILQ_FOREACH(pe, paths, entry) {
char *ondisk_path;
if (asprintf(&ondisk_path, "%s/%s", worktree->root_path,
pe->path) == -1)
return got_error_from_errno("asprintf");
- err = schedule_addition(ondisk_path, fileindex, pe->path,
- status_cb, status_arg, repo);
+ saa.ondisk_path = ondisk_path;
+ err = worktree_status(worktree, pe->path, fileindex, repo,
+ schedule_addition, &saa, NULL, NULL);
free(ondisk_path);
if (err)
break;
blob - 0634eee1bd0a59644a8f17047cc75df2160d3023
blob + 9260016060fa594ef14a31a90e815737bb487ca1
--- regress/cmdline/add.sh
+++ regress/cmdline/add.sh
test_done "$testroot" "$ret"
}
+function test_add_directory {
+ local testroot=`test_init add_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 add . > $testroot/stdout 2> $testroot/stderr)
+ ret="$?"
+ if [ "$ret" == "0" ]; then
+ echo "got add command succeeded unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+ echo "got: adding 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
+
+ (touch $testroot/wt/epsilon/zeta1 && touch $testroot/wt/epsilon/zeta2)
+
+ (cd $testroot/wt && got add -R . > $testroot/stdout)
+
+ echo 'A epsilon/zeta1' > $testroot/stdout.expected
+ echo 'A epsilon/zeta2' >> $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
+
+ echo "zeta" > $testroot/content.expected
+ cat $testroot/wt/epsilon/zeta > $testroot/content
+
+ cmp -s $testroot/content.expected $testroot/content
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/content.expected $testroot/content
+ fi
+ test_done "$testroot" "$ret"
+}
+
run_test test_add_basic
run_test test_double_add
run_test test_add_multiple
run_test test_add_file_in_new_subdir
run_test test_add_deleted
+run_test test_add_directory