Merge branch 'jk/clone-detached'
authorJunio C Hamano <gitster@pobox.com>
Mon, 1 Aug 2011 22:00:35 +0000 (15:00 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 1 Aug 2011 22:00:35 +0000 (15:00 -0700)
* jk/clone-detached:
clone: always fetch remote HEAD
make copy_ref globally available
consider only branches in guess_remote_head
t: add tests for cloning remotes with detached HEAD

1  2 
builtin/clone.c
diff --combined builtin/clone.c
index a15784a7b8406be3ead20839aab0f8de2cc52f3d,20496bdad051f3e2cf545d7b3e4aed00c17cb332..7663bc22c9a3cb35b803815762791fec44d4c477
@@@ -8,7 -8,7 +8,7 @@@
   * Clone a repository into a different directory that does not yet exist.
   */
  
 -#include "cache.h"
 +#include "builtin.h"
  #include "parse-options.h"
  #include "fetch-pack.h"
  #include "refs.h"
@@@ -42,11 -42,9 +42,11 @@@ static int option_local, option_no_hard
  static char *option_template, *option_reference, *option_depth;
  static char *option_origin = NULL;
  static char *option_branch = NULL;
 +static const char *real_git_dir;
  static char *option_upload_pack = "git-upload-pack";
  static int option_verbosity;
  static int option_progress;
 +static struct string_list option_config;
  
  static struct option builtin_clone_options[] = {
        OPT__VERBOSITY(&option_verbosity),
                   "path to git-upload-pack on the remote"),
        OPT_STRING(0, "depth", &option_depth, "depth",
                    "create a shallow clone of that depth"),
 -
 +      OPT_STRING(0, "separate-git-dir", &real_git_dir, "gitdir",
 +                 "separate git dir from working tree"),
 +      OPT_STRING_LIST('c', "config", &option_config, "key=value",
 +                      "set config inside the new repository"),
        OPT_END()
  };
  
@@@ -105,7 -100,7 +105,7 @@@ static char *get_repo_path(const char *
                path = mkpath("%s%s", repo, suffix[i]);
                if (is_directory(path)) {
                        *is_bundle = 0;
 -                      return xstrdup(make_nonrelative_path(path));
 +                      return xstrdup(absolute_path(path));
                }
        }
  
                path = mkpath("%s%s", repo, bundle_suffix[i]);
                if (!stat(path, &st) && S_ISREG(st.st_mode)) {
                        *is_bundle = 1;
 -                      return xstrdup(make_nonrelative_path(path));
 +                      return xstrdup(absolute_path(path));
                }
        }
  
@@@ -208,12 -203,12 +208,12 @@@ static void setup_reference(const char 
        struct transport *transport;
        const struct ref *extra;
  
 -      ref_git = make_absolute_path(option_reference);
 +      ref_git = real_path(option_reference);
  
        if (is_directory(mkpath("%s/.git/objects", ref_git)))
                ref_git = mkpath("%s/.git", ref_git);
        else if (!is_directory(mkpath("%s/objects", ref_git)))
 -              die("reference repository '%s' is not a local directory.",
 +              die(_("reference repository '%s' is not a local directory."),
                    option_reference);
  
        ref_git_copy = xstrdup(ref_git);
@@@ -240,15 -235,15 +240,15 @@@ static void copy_or_link_directory(stru
  
        dir = opendir(src->buf);
        if (!dir)
 -              die_errno("failed to open '%s'", src->buf);
 +              die_errno(_("failed to open '%s'"), src->buf);
  
        if (mkdir(dest->buf, 0777)) {
                if (errno != EEXIST)
 -                      die_errno("failed to create directory '%s'", dest->buf);
 +                      die_errno(_("failed to create directory '%s'"), dest->buf);
                else if (stat(dest->buf, &buf))
 -                      die_errno("failed to stat '%s'", dest->buf);
 +                      die_errno(_("failed to stat '%s'"), dest->buf);
                else if (!S_ISDIR(buf.st_mode))
 -                      die("%s exists and is not a directory", dest->buf);
 +                      die(_("%s exists and is not a directory"), dest->buf);
        }
  
        strbuf_addch(src, '/');
                strbuf_setlen(dest, dest_len);
                strbuf_addstr(dest, de->d_name);
                if (stat(src->buf, &buf)) {
 -                      warning ("failed to stat %s\n", src->buf);
 +                      warning (_("failed to stat %s\n"), src->buf);
                        continue;
                }
                if (S_ISDIR(buf.st_mode)) {
                }
  
                if (unlink(dest->buf) && errno != ENOENT)
 -                      die_errno("failed to unlink '%s'", dest->buf);
 +                      die_errno(_("failed to unlink '%s'"), dest->buf);
                if (!option_no_hardlinks) {
                        if (!link(src->buf, dest->buf))
                                continue;
                        if (option_local)
 -                              die_errno("failed to create link '%s'", dest->buf);
 +                              die_errno(_("failed to create link '%s'"), dest->buf);
                        option_no_hardlinks = 1;
                }
                if (copy_file_with_time(dest->buf, src->buf, 0666))
 -                      die_errno("failed to copy file to '%s'", dest->buf);
 +                      die_errno(_("failed to copy file to '%s'"), dest->buf);
        }
        closedir(dir);
  }
@@@ -310,7 -305,7 +310,7 @@@ static const struct ref *clone_local(co
        ret = transport_get_remote_refs(transport);
        transport_disconnect(transport);
        if (0 <= option_verbosity)
 -              printf("done.\n");
 +              printf(_("done.\n"));
        return ret;
  }
  
@@@ -345,8 -340,9 +345,9 @@@ static void remove_junk_on_signal(int s
  static struct ref *wanted_peer_refs(const struct ref *refs,
                struct refspec *refspec)
  {
-       struct ref *local_refs = NULL;
-       struct ref **tail = &local_refs;
+       struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD"));
+       struct ref *local_refs = head;
+       struct ref **tail = head ? &head->next : &local_refs;
  
        get_fetch_map(refs, refspec, &tail, 0);
        if (!option_mirror)
@@@ -359,29 -355,16 +360,32 @@@ static void write_remote_refs(const str
  {
        const struct ref *r;
  
-       for (r = local_refs; r; r = r->next)
+       for (r = local_refs; r; r = r->next) {
+               if (!r->peer_ref)
+                       continue;
                add_extra_ref(r->peer_ref->name, r->old_sha1, 0);
+       }
  
        pack_refs(PACK_REFS_ALL);
        clear_extra_refs();
  }
  
 +static int write_one_config(const char *key, const char *value, void *data)
 +{
 +      return git_config_set_multivar(key, value ? value : "true", "^$", 0);
 +}
 +
 +static void write_config(struct string_list *config)
 +{
 +      int i;
 +
 +      for (i = 0; i < config->nr; i++) {
 +              if (git_config_parse_parameter(config->items[i].string,
 +                                             write_one_config, NULL) < 0)
 +                      die("unable to write parameters to config file");
 +      }
 +}
 +
  int cmd_clone(int argc, const char **argv, const char *prefix)
  {
        int is_bundle = 0, is_local;
  
        junk_pid = getpid();
  
 +      packet_trace_identity("clone");
        argc = parse_options(argc, argv, prefix, builtin_clone_options,
                             builtin_clone_usage, 0);
  
        if (argc > 2)
 -              usage_msg_opt("Too many arguments.",
 +              usage_msg_opt(_("Too many arguments."),
                        builtin_clone_usage, builtin_clone_options);
  
        if (argc == 0)
 -              usage_msg_opt("You must specify a repository to clone.",
 +              usage_msg_opt(_("You must specify a repository to clone."),
                        builtin_clone_usage, builtin_clone_options);
  
        if (option_mirror)
  
        if (option_bare) {
                if (option_origin)
 -                      die("--bare and --origin %s options are incompatible.",
 +                      die(_("--bare and --origin %s options are incompatible."),
                            option_origin);
                option_no_checkout = 1;
        }
  
        path = get_repo_path(repo_name, &is_bundle);
        if (path)
 -              repo = xstrdup(make_nonrelative_path(repo_name));
 +              repo = xstrdup(absolute_path(repo_name));
        else if (!strchr(repo_name, ':'))
 -              die("repository '%s' does not exist", repo_name);
 +              die(_("repository '%s' does not exist"), repo_name);
        else
                repo = repo_name;
        is_local = path && !is_bundle;
        if (is_local && option_depth)
 -              warning("--depth is ignored in local clones; use file:// instead.");
 +              warning(_("--depth is ignored in local clones; use file:// instead."));
  
        if (argc == 2)
                dir = xstrdup(argv[1]);
  
        dest_exists = !stat(dir, &buf);
        if (dest_exists && !is_empty_dir(dir))
 -              die("destination path '%s' already exists and is not "
 -                      "an empty directory.", dir);
 +              die(_("destination path '%s' already exists and is not "
 +                      "an empty directory."), dir);
  
        strbuf_addf(&reflog_msg, "clone: from %s", repo);
  
        else {
                work_tree = getenv("GIT_WORK_TREE");
                if (work_tree && !stat(work_tree, &buf))
 -                      die("working tree '%s' already exists.", work_tree);
 +                      die(_("working tree '%s' already exists."), work_tree);
        }
  
        if (option_bare || work_tree)
        if (!option_bare) {
                junk_work_tree = work_tree;
                if (safe_create_leading_directories_const(work_tree) < 0)
 -                      die_errno("could not create leading directories of '%s'",
 +                      die_errno(_("could not create leading directories of '%s'"),
                                  work_tree);
                if (!dest_exists && mkdir(work_tree, 0755))
 -                      die_errno("could not create work tree dir '%s'.",
 +                      die_errno(_("could not create work tree dir '%s'."),
                                  work_tree);
                set_git_work_tree(work_tree);
        }
        setenv(CONFIG_ENVIRONMENT, mkpath("%s/config", git_dir), 1);
  
        if (safe_create_leading_directories_const(git_dir) < 0)
 -              die("could not create leading directories of '%s'", git_dir);
 -      set_git_dir(make_absolute_path(git_dir));
 +              die(_("could not create leading directories of '%s'"), git_dir);
  
 -      if (0 <= option_verbosity)
 -              printf("Cloning into %s%s...\n",
 -                     option_bare ? "bare repository " : "", dir);
 +      set_git_dir_init(git_dir, real_git_dir, 0);
 +      if (real_git_dir)
 +              git_dir = real_git_dir;
 +
 +      if (0 <= option_verbosity) {
 +              if (option_bare)
 +                      printf(_("Cloning into bare repository %s...\n"), dir);
 +              else
 +                      printf(_("Cloning into %s...\n"), dir);
 +      }
        init_db(option_template, INIT_DB_QUIET);
 +      write_config(&option_config);
  
        /*
         * At this point, the config exists, so we do not need the
                transport = transport_get(remote, remote->url[0]);
  
                if (!transport->get_refs_list || !transport->fetch)
 -                      die("Don't know how to clone %s", transport->url);
 +                      die(_("Don't know how to clone %s"), transport->url);
  
                transport_set_option(transport, TRANS_OPT_KEEP, "yes");
  
                        strbuf_release(&head);
  
                        if (!our_head_points_at) {
 -                              warning("Remote branch %s not found in "
 -                                      "upstream %s, using HEAD instead",
 +                              warning(_("Remote branch %s not found in "
 +                                      "upstream %s, using HEAD instead"),
                                        option_branch, option_origin);
                                our_head_points_at = remote_head_points_at;
                        }
                        our_head_points_at = remote_head_points_at;
        }
        else {
 -              warning("You appear to have cloned an empty repository.");
 +              warning(_("You appear to have cloned an empty repository."));
                our_head_points_at = NULL;
                remote_head_points_at = NULL;
                remote_head = NULL;
        } else {
                /* Nothing to checkout out */
                if (!option_no_checkout)
 -                      warning("remote HEAD refers to nonexistent ref, "
 -                              "unable to checkout.\n");
 +                      warning(_("remote HEAD refers to nonexistent ref, "
 +                              "unable to checkout.\n"));
                option_no_checkout = 1;
        }
  
  
                if (write_cache(fd, active_cache, active_nr) ||
                    commit_locked_index(lock_file))
 -                      die("unable to write new index file");
 +                      die(_("unable to write new index file"));
  
                err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1),
                                sha1_to_hex(our_head_points_at->old_sha1), "1",