commit bb51a5b4af467a42569e19cbeeeeccbb44d946f0 from: Stefan Sperling date: Mon Jan 13 10:28:58 2020 UTC add -E option to 'got checkout' allowing use of a non-empty work tree path needed by and ok kn@ commit - c5b7833452086e7e8e0866b16a5932430cfe9a79 commit + bb51a5b4af467a42569e19cbeeeeccbb44d946f0 blob - 4099167c32d0a15e7689e9a2b02ba26dcf17d90f blob + c37e7cad2084f68edcbdff9b1085facc2f646043 --- got/got.1 +++ got/got.1 @@ -136,8 +136,14 @@ follows the globbing rules documented in .It Cm im Short alias for .Cm import . -.It Cm checkout Oo Fl b Ar branch Oc Oo Fl c Ar commit Oc Oo Fl p Ar path-prefix Oc Ar repository-path Op Ar work-tree-path +.It Cm checkout Oo Fl E Oc Oo Fl b Ar branch Oc Oo Fl c Ar commit OcOo Fl p Ar path-prefix Oc Ar repository-path Op Ar work-tree-path Copy files from a repository into a new work tree. +Show the status of each affected file, using the following status codes: +.Bl -column YXZ description +.It A Ta new file was added +.It E Ta file already exists in work tree's meta-data +.El +.Pp If the .Ar work tree path is not specified, either use the last component of @@ -151,6 +157,11 @@ The options for .Cm got checkout are as follows: .Bl -tag -width Ds +.It Fl E +Proceed with the checkout operation even if the directory at +.Ar work-tree-path +is not empty. +Existing files will be left intact. .It Fl b Ar branch Check out files from a commit on the specified .Ar branch . blob - 5490ed3772d0e6daa9cd31a902f0f3129bb779f5 blob + 9949c5488d778cc0038d5ad03dc24986ac5f059b --- got/got.c +++ got/got.c @@ -799,7 +799,7 @@ done: __dead static void usage_checkout(void) { - fprintf(stderr, "usage: %s checkout [-b branch] [-c commit] " + fprintf(stderr, "usage: %s checkout [-E] [-b branch] [-c commit] " "[-p prefix] repository-path [worktree-path]\n", getprogname()); exit(1); } @@ -998,13 +998,13 @@ cmd_checkout(int argc, char *argv[]) const char *path_prefix = ""; const char *branch_name = GOT_REF_HEAD; char *commit_id_str = NULL; - int ch, same_path_prefix; + int ch, same_path_prefix, allow_nonempty = 0; struct got_pathlist_head paths; struct got_checkout_progress_arg cpa; TAILQ_INIT(&paths); - while ((ch = getopt(argc, argv, "b:c:p:")) != -1) { + while ((ch = getopt(argc, argv, "b:c:Ep:")) != -1) { switch (ch) { case 'b': branch_name = optarg; @@ -1013,6 +1013,9 @@ cmd_checkout(int argc, char *argv[]) commit_id_str = strdup(optarg); if (commit_id_str == NULL) return got_error_from_errno("strdup"); + break; + case 'E': + allow_nonempty = 1; break; case 'p': path_prefix = optarg; @@ -1100,7 +1103,8 @@ cmd_checkout(int argc, char *argv[]) if (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) && !(error->code == GOT_ERR_ERRNO && errno == EEXIST)) goto done; - if (!got_path_dir_is_empty(worktree_path)) { + if (!allow_nonempty && + !got_path_dir_is_empty(worktree_path)) { error = got_error_path(worktree_path, GOT_ERR_DIR_NOT_EMPTY); goto done; blob - 756faf8e9b273a128bad4efb6aedef83e1d5426c blob + 57b823a4f04403e0dfd1d1e79cc8fe80f6dbc79c --- include/got_path.h +++ include/got_path.h @@ -16,8 +16,10 @@ /* Utilities for dealing with filesystem paths. */ -#define GOT_DEFAULT_FILE_MODE (S_IRUSR|S_IWUSR | S_IRGRP | S_IROTH) -#define GOT_DEFAULT_DIR_MODE (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH) +#define GOT_DEFAULT_FILE_MODE (S_IFREG | \ + S_IRUSR|S_IWUSR | S_IRGRP | S_IROTH) +#define GOT_DEFAULT_DIR_MODE (S_IFDIR | \ + S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH) /* Determine whether a path is an absolute path. */ int got_path_is_absolute(const char *); blob - fcbeadbc09c83ae8ca419b0dd909c62dc50d4d99 blob + 3027c28911360bf6c9f6f2dcdc85e417cf77dc37 --- lib/worktree.c +++ lib/worktree.c @@ -937,7 +937,7 @@ get_ondisk_perms(int executable, mode_t st_mode) static const struct got_error * install_blob(struct got_worktree *worktree, const char *ondisk_path, - const char *path, uint16_t te_mode, uint16_t st_mode, + const char *path, mode_t te_mode, mode_t st_mode, struct got_blob_object *blob, int restoring_missing_file, int reverting_versioned_file, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg) blob - 34747be3c1c93a3c475b7e42583dca7f4ae844a4 blob + 6859b9bab3ac0176db628a98074b484d5b80364b --- regress/cmdline/checkout.sh +++ regress/cmdline/checkout.sh @@ -355,7 +355,147 @@ function test_checkout_read_only { chmod -R u+w $testroot/repo # make repo cleanup work test_done "$testroot" "$ret" } + +function test_checkout_into_nonempty_dir { + local testroot=`test_init checkout_into_nonempty_dir` + + mkdir -p $testroot/wt + make_test_tree $testroot/wt + + got checkout $testroot/repo $testroot/wt > $testroot/stdout \ + 2> $testroot/stderr + ret="$?" + if [ "$ret" == "0" ]; then + echo "checkout succeeded unexpectedly" >&2 + test_done "$testroot" "1" + 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 + + echo "got: $testroot/wt: directory exists and is not empty" \ + > $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 "U $testroot/wt/alpha" > $testroot/stdout.expected + echo "U $testroot/wt/beta" >> $testroot/stdout.expected + echo "U $testroot/wt/epsilon/zeta" >> $testroot/stdout.expected + echo "U $testroot/wt/gamma/delta" >> $testroot/stdout.expected + echo "Now shut up and hack" >> $testroot/stdout.expected + got checkout -E $testroot/repo $testroot/wt > $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + 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 "E $testroot/wt/alpha" > $testroot/stdout.expected + echo "E $testroot/wt/beta" >> $testroot/stdout.expected + echo "E $testroot/wt/epsilon/zeta" >> $testroot/stdout.expected + echo "E $testroot/wt/gamma/delta" >> $testroot/stdout.expected + echo "Now shut up and hack" >> $testroot/stdout.expected + + got checkout -E $testroot/repo $testroot/wt > $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + 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 "alpha" > $testroot/content.expected + echo "beta" >> $testroot/content.expected + echo "zeta" >> $testroot/content.expected + echo "delta" >> $testroot/content.expected + cat $testroot/wt/alpha $testroot/wt/beta $testroot/wt/epsilon/zeta \ + $testroot/wt/gamma/delta > $testroot/content + + cmp -s $testroot/content.expected $testroot/content + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/content.expected $testroot/content + test_done "$testroot" "$ret" + return 1 + fi + + echo "modified alpha" > $testroot/wt/alpha + + echo "E $testroot/wt/alpha" > $testroot/stdout.expected + echo "E $testroot/wt/beta" >> $testroot/stdout.expected + echo "E $testroot/wt/epsilon/zeta" >> $testroot/stdout.expected + echo "E $testroot/wt/gamma/delta" >> $testroot/stdout.expected + echo "Now shut up and hack" >> $testroot/stdout.expected + + got checkout -E $testroot/repo $testroot/wt > $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + 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 "modified alpha" > $testroot/content.expected + echo "beta" >> $testroot/content.expected + echo "zeta" >> $testroot/content.expected + echo "delta" >> $testroot/content.expected + cat $testroot/wt/alpha $testroot/wt/beta $testroot/wt/epsilon/zeta \ + $testroot/wt/gamma/delta > $testroot/content + + cmp -s $testroot/content.expected $testroot/content + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/content.expected $testroot/content + test_done "$testroot" "$ret" + return + fi + + echo 'M alpha' > $testroot/stdout.expected + (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 + fi + test_done "$testroot" "$ret" +} + run_test test_checkout_basic run_test test_checkout_dir_exists run_test test_checkout_dir_not_empty @@ -364,3 +504,4 @@ run_test test_checkout_commit_from_wrong_branch run_test test_checkout_tag run_test test_checkout_ignores_submodules run_test test_checkout_read_only +run_test test_checkout_into_nonempty_dir