Merge branch 'jk/abort-clone-with-existing-dest' into maint
authorJunio C Hamano <gitster@pobox.com>
Thu, 15 Feb 2018 23:18:12 +0000 (15:18 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 15 Feb 2018 23:18:13 +0000 (15:18 -0800)
"git clone $there $here" is allowed even when here directory exists
as long as it is an empty directory, but the command incorrectly
removed it upon a failure of the operation.

* jk/abort-clone-with-existing-dest:
clone: do not clean up directories we didn't create
clone: factor out dir_exists() helper
t5600: modernize style
t5600: fix outdated comment about unborn HEAD

1  2 
builtin/clone.c
diff --combined builtin/clone.c
index 2da71db10752bf95647052dcd5b7c4b28e7a50ac,d9b3d1a164970e04fad140df81e9d6fab0125139..284651797e5402c9f7ef85003d7d1c4ea944e2d7
@@@ -452,8 -452,7 +452,8 @@@ static void clone_local(const char *src
  {
        if (option_shared) {
                struct strbuf alt = STRBUF_INIT;
 -              strbuf_addf(&alt, "%s/objects", src_repo);
 +              get_common_dir(&alt, src_repo);
 +              strbuf_addstr(&alt, "/objects");
                add_to_alternates_file(alt.buf);
                strbuf_release(&alt);
        } else {
  }
  
  static const char *junk_work_tree;
+ static int junk_work_tree_flags;
  static const char *junk_git_dir;
+ static int junk_git_dir_flags;
  static enum {
        JUNK_LEAVE_NONE,
        JUNK_LEAVE_REPO,
@@@ -502,12 -503,12 +504,12 @@@ static void remove_junk(void
  
        if (junk_git_dir) {
                strbuf_addstr(&sb, junk_git_dir);
-               remove_dir_recursively(&sb, 0);
+               remove_dir_recursively(&sb, junk_git_dir_flags);
                strbuf_reset(&sb);
        }
        if (junk_work_tree) {
                strbuf_addstr(&sb, junk_work_tree);
-               remove_dir_recursively(&sb, 0);
+               remove_dir_recursively(&sb, junk_work_tree_flags);
        }
        strbuf_release(&sb);
  }
@@@ -589,7 -590,7 +591,7 @@@ static void write_remote_refs(const str
        for (r = local_refs; r; r = r->next) {
                if (!r->peer_ref)
                        continue;
 -              if (ref_transaction_create(t, r->peer_ref->name, r->old_oid.hash,
 +              if (ref_transaction_create(t, r->peer_ref->name, &r->old_oid,
                                           0, NULL, &err))
                        die("%s", err.buf);
        }
@@@ -611,12 -612,12 +613,12 @@@ static void write_followtags(const stru
                        continue;
                if (!has_object_file(&ref->old_oid))
                        continue;
 -              update_ref(msg, ref->name, ref->old_oid.hash,
 -                         NULL, 0, UPDATE_REFS_DIE_ON_ERR);
 +              update_ref(msg, ref->name, &ref->old_oid, NULL, 0,
 +                         UPDATE_REFS_DIE_ON_ERR);
        }
  }
  
 -static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
 +static int iterate_ref_map(void *cb_data, struct object_id *oid)
  {
        struct ref **rm = cb_data;
        struct ref *ref = *rm;
        if (!ref)
                return -1;
  
 -      hashcpy(sha1, ref->old_oid.hash);
 +      oidcpy(oid, &ref->old_oid);
        *rm = ref->next;
        return 0;
  }
@@@ -683,23 -684,23 +685,23 @@@ static void update_head(const struct re
                if (create_symref("HEAD", our->name, NULL) < 0)
                        die(_("unable to update HEAD"));
                if (!option_bare) {
 -                      update_ref(msg, "HEAD", our->old_oid.hash, NULL, 0,
 +                      update_ref(msg, "HEAD", &our->old_oid, NULL, 0,
                                   UPDATE_REFS_DIE_ON_ERR);
                        install_branch_config(0, head, option_origin, our->name);
                }
        } else if (our) {
                struct commit *c = lookup_commit_reference(&our->old_oid);
                /* --branch specifies a non-branch (i.e. tags), detach HEAD */
 -              update_ref(msg, "HEAD", c->object.oid.hash,
 -                         NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
 +              update_ref(msg, "HEAD", &c->object.oid, NULL, REF_NO_DEREF,
 +                         UPDATE_REFS_DIE_ON_ERR);
        } else if (remote) {
                /*
                 * We know remote HEAD points to a non-branch, or
                 * HEAD points to a branch but we don't know which one.
                 * Detach HEAD in all these cases.
                 */
 -              update_ref(msg, "HEAD", remote->old_oid.hash,
 -                         NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
 +              update_ref(msg, "HEAD", &remote->old_oid, NULL, REF_NO_DEREF,
 +                         UPDATE_REFS_DIE_ON_ERR);
        }
  }
  
@@@ -707,7 -708,7 +709,7 @@@ static int checkout(int submodule_progr
  {
        struct object_id oid;
        char *head;
 -      struct lock_file *lock_file;
 +      struct lock_file lock_file = LOCK_INIT;
        struct unpack_trees_options opts;
        struct tree *tree;
        struct tree_desc t;
        if (option_no_checkout)
                return 0;
  
 -      head = resolve_refdup("HEAD", RESOLVE_REF_READING, oid.hash, NULL);
 +      head = resolve_refdup("HEAD", RESOLVE_REF_READING, &oid, NULL);
        if (!head) {
                warning(_("remote HEAD refers to nonexistent ref, "
                          "unable to checkout.\n"));
        /* We need to be in the new work tree for the checkout */
        setup_work_tree();
  
 -      lock_file = xcalloc(1, sizeof(struct lock_file));
 -      hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
 +      hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
  
        memset(&opts, 0, sizeof opts);
        opts.update = 1;
        if (unpack_trees(1, &t, &opts) < 0)
                die(_("unable to checkout working tree"));
  
 -      if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
 +      if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
  
        err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1),
@@@ -863,10 -865,15 +865,15 @@@ static void dissociate_from_references(
        free(alternates);
  }
  
+ static int dir_exists(const char *path)
+ {
+       struct stat sb;
+       return !stat(path, &sb);
+ }
  int cmd_clone(int argc, const char **argv, const char *prefix)
  {
        int is_bundle = 0, is_local;
-       struct stat buf;
        const char *repo_name, *repo, *work_tree, *git_dir;
        char *path, *dir;
        int dest_exists;
                dir = guess_dir_name(repo_name, is_bundle, option_bare);
        strip_trailing_slashes(dir);
  
-       dest_exists = !stat(dir, &buf);
+       dest_exists = dir_exists(dir);
        if (dest_exists && !is_empty_dir(dir))
                die(_("destination path '%s' already exists and is not "
                        "an empty directory."), dir);
                work_tree = NULL;
        else {
                work_tree = getenv("GIT_WORK_TREE");
-               if (work_tree && !stat(work_tree, &buf))
+               if (work_tree && dir_exists(work_tree))
                        die(_("working tree '%s' already exists."), work_tree);
        }
  
                if (safe_create_leading_directories_const(work_tree) < 0)
                        die_errno(_("could not create leading directories of '%s'"),
                                  work_tree);
-               if (!dest_exists && mkdir(work_tree, 0777))
+               if (dest_exists)
+                       junk_work_tree_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
+               else if (mkdir(work_tree, 0777))
                        die_errno(_("could not create work tree dir '%s'"),
                                  work_tree);
                junk_work_tree = work_tree;
                set_git_work_tree(work_tree);
        }
  
-       junk_git_dir = real_git_dir ? real_git_dir : git_dir;
+       if (real_git_dir) {
+               if (dir_exists(real_git_dir))
+                       junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
+               junk_git_dir = real_git_dir;
+       } else {
+               if (dest_exists)
+                       junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
+               junk_git_dir = git_dir;
+       }
        if (safe_create_leading_directories_const(git_dir) < 0)
                die(_("could not create leading directories of '%s'"), git_dir);
  
                warning(_("--local is ignored"));
        transport->cloning = 1;
  
 -      if (!transport->get_refs_list || (!is_local && !transport->fetch))
 -              die(_("Don't know how to clone %s"), transport->url);
 -
        transport_set_option(transport, TRANS_OPT_KEEP, "yes");
  
        if (option_depth)