{"thread":{"id":"13166","subject":"[PATCH 8/8] Build in clone","startedAt":"2008-04-17T23:32:43Z","lastAt":"2008-04-17T23:32:43Z","messageCount":1,"participants":["Daniel Barkalow"],"isPatch":true,"patchVersion":1,"patchTotal":8},"messages":[{"id":"74698","messageId":"alpine.LNX.1.00.0804171932080.19665@iabervon.org","threadId":"13166","inReplyTo":null,"subject":"[PATCH 8/8] Build in clone","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2008-04-17T23:32:43Z","receivedAt":"2008-04-17T23:32:43Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"This version is still a mess, but it passes all of the tests. I'm\nsomewhat unconvinced by the test coverage for clone, however; the\nlast failure I found was actually for which heads get created in a\nbare repository, and it was only failing when there was an extra one\nin a non-bare clone in a test for something entirely different.\n\nThanks to Johannes Schindelin for various comments and improvements,\nincluding supporting cloning full bundles.\n---\n Makefile                      |    2 +-\n builtin-clone.c               |  546 +++++++++++++++++++++++++++++++++++++++++\n builtin.h                     |    1 +\n contrib/examples/git-clone.sh |  522 +++++++++++++++++++++++++++++++++++++++\n git-clone.sh                  |  522 ---------------------------------------\n git.c                         |    1 +\n 6 files changed, 1071 insertions(+), 523 deletions(-)\n create mode 100644 builtin-clone.c\n create mode 100755 contrib/examples/git-clone.sh\n delete mode 100755 git-clone.sh\n\ndiff --git a/Makefile b/Makefile\nindex 78b7738..be9113f 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -235,7 +235,6 @@ BASIC_LDFLAGS =\n \n SCRIPT_SH += git-am.sh\n SCRIPT_SH += git-bisect.sh\n-SCRIPT_SH += git-clone.sh\n SCRIPT_SH += git-filter-branch.sh\n SCRIPT_SH += git-lost-found.sh\n SCRIPT_SH += git-merge-octopus.sh\n@@ -479,6 +478,7 @@ BUILTIN_OBJS += builtin-check-ref-format.o\n BUILTIN_OBJS += builtin-checkout-index.o\n BUILTIN_OBJS += builtin-checkout.o\n BUILTIN_OBJS += builtin-clean.o\n+BUILTIN_OBJS += builtin-clone.o\n BUILTIN_OBJS += builtin-commit-tree.o\n BUILTIN_OBJS += builtin-commit.o\n BUILTIN_OBJS += builtin-config.o\ndiff --git a/builtin-clone.c b/builtin-clone.c\nnew file mode 100644\nindex 0000000..17d10b1\n--- /dev/null\n+++ b/builtin-clone.c\n@@ -0,0 +1,546 @@\n+/*\n+ * Builtin \"git clone\"\n+ *\n+ * Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>,\n+ *\t\t 2008 Daniel Barkalow <barkalow@iabervon.org>\n+ * Based on git-commit.sh by Junio C Hamano and Linus Torvalds\n+ *\n+ * Clone a repository into a different directory that does not yet exist.\n+ */\n+\n+#include \"cache.h\"\n+#include \"parse-options.h\"\n+#include \"fetch-pack.h\"\n+#include \"refs.h\"\n+#include \"tree.h\"\n+#include \"tree-walk.h\"\n+#include \"unpack-trees.h\"\n+#include \"transport.h\"\n+#include \"strbuf.h\"\n+#include \"dir.h\"\n+\n+/*\n+ * Overall FIXMEs:\n+ *  - respect DB_ENVIRONMENT for .git/objects.\n+ *\n+ * Implementation notes:\n+ *  - dropping use-separate-remote and no-separate-remote compatibility\n+ *\n+ */\n+static const char * const builtin_clone_usage[] = {\n+\t\"git-clone [options] [--] <repo> [<dir>]\",\n+\tNULL\n+};\n+\n+static int option_quiet, option_no_checkout, option_bare;\n+static int option_local, option_no_hardlinks, option_shared;\n+static char *option_template, *option_reference, *option_depth;\n+static char *option_origin = NULL;\n+static char *option_upload_pack = \"git-upload-pack\";\n+\n+static struct option builtin_clone_options[] = {\n+\tOPT__QUIET(&option_quiet),\n+\tOPT_BOOLEAN('n', \"no-checkout\", &option_no_checkout,\n+\t\t    \"don't create a checkout\"),\n+\tOPT_BOOLEAN(0, \"bare\", &option_bare, \"create a bare repository\"),\n+\tOPT_BOOLEAN(0, \"naked\", &option_bare, \"create a bare repository\"),\n+\tOPT_BOOLEAN('l', \"local\", &option_local,\n+\t\t    \"to clone from a local repository\"),\n+\tOPT_BOOLEAN(0, \"no-hardlinks\", &option_no_hardlinks,\n+\t\t    \"don't use local hardlinks, always copy\"),\n+\tOPT_BOOLEAN('s', \"shared\", &option_shared,\n+\t\t    \"setup as shared repository\"),\n+\tOPT_STRING(0, \"template\", &option_template, \"path\",\n+\t\t   \"path the template repository\"),\n+\tOPT_STRING(0, \"reference\", &option_reference, \"repo\",\n+\t\t   \"reference repository\"),\n+\tOPT_STRING('o', \"origin\", &option_origin, \"branch\",\n+\t\t   \"use <branch> instead or 'origin' to track upstream\"),\n+\tOPT_STRING('u', \"upload-pack\", &option_upload_pack, \"path\",\n+\t\t   \"path to git-upload-pack on the remote\"),\n+\tOPT_STRING(0, \"depth\", &option_depth, \"depth\",\n+\t\t    \"create a shallow clone of that depth\"),\n+\n+\tOPT_END()\n+};\n+\n+static char *get_repo_path(const char *repo, int *is_bundle)\n+{\n+\tstatic char *suffix[] = { \"/.git\", \".git\", \"\" };\n+\tstatic char *bundle_suffix[] = { \".bundle\", \"\" };\n+\tstruct stat st;\n+\tint i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(suffix); i++) {\n+\t\tconst char *path;\n+\t\tpath = mkpath(\"%s%s\", repo, suffix[i]);\n+\t\tif (!stat(path, &st) && S_ISDIR(st.st_mode)) {\n+\t\t\t*is_bundle = 0;\n+\t\t\treturn xstrdup(make_absolute_path(path));\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < ARRAY_SIZE(bundle_suffix); i++) {\n+\t\tconst char *path;\n+\t\tpath = mkpath(\"%s%s\", repo, bundle_suffix[i]);\n+\t\tif (!stat(path, &st) && S_ISREG(st.st_mode)) {\n+\t\t\t*is_bundle = 1;\n+\t\t\treturn xstrdup(make_absolute_path(path));\n+\t\t}\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+static char *guess_dir_name(const char *repo, int is_bundle)\n+{\n+\tconst char *p, *start, *end, *limit;\n+\tint after_slash_or_colon;\n+\n+\t/* Guess dir name from repository: strip trailing '/',\n+\t * strip trailing '[:/]*.{git,bundle}', strip leading '.*[/:]'. */\n+\n+\tafter_slash_or_colon = 1;\n+\tlimit = repo + strlen(repo);\n+\tstart = repo;\n+\tend = limit;\n+\tfor (p = repo; p < limit; p++) {\n+\t\tconst char *prefix = is_bundle ? \".bundle\" : \".git\";\n+\t\tif (!prefixcmp(p, prefix)) {\n+\t\t\tif (!after_slash_or_colon)\n+\t\t\t\tend = p;\n+\t\t\tp += strlen(prefix) - 1;\n+\t\t} else if (!prefixcmp(p, \".bundle\")) {\n+\t\t\tif (!after_slash_or_colon)\n+\t\t\t\tend = p;\n+\t\t\tp += 7;\n+\t\t} else if (*p == '/' || *p == ':') {\n+\t\t\tif (end == limit)\n+\t\t\t\tend = p;\n+\t\t\tafter_slash_or_colon = 1;\n+\t\t} else if (after_slash_or_colon) {\n+\t\t\tstart = p;\n+\t\t\tend = limit;\n+\t\t\tafter_slash_or_colon = 0;\n+\t\t}\n+\t}\n+\n+\treturn xstrndup(start, end - start);\n+}\n+\n+static int is_directory(const char *path)\n+{\n+\tstruct stat buf;\n+\n+\treturn !stat(path, &buf) && S_ISDIR(buf.st_mode);\n+}\n+\n+static void setup_reference(const char *repo)\n+{\n+\tconst char *ref_git;\n+\tchar *ref_git_copy;\n+\n+\tstruct remote *remote;\n+\tstruct transport *transport;\n+\tconst struct ref *extra;\n+\n+\tref_git = make_absolute_path(option_reference);\n+\n+\tif (is_directory(mkpath(\"%s/.git/objects\", ref_git)))\n+\t\tref_git = mkpath(\"%s/.git\", ref_git);\n+\telse if (!is_directory(mkpath(\"%s/objects\", ref_git)))\n+\t\tdie(\"reference repository '%s' is not a local directory.\",\n+\t\t    option_reference);\n+\n+\tref_git_copy = xstrdup(ref_git);\n+\n+\tadd_to_alternates_file(ref_git_copy);\n+\n+\tremote = remote_get(ref_git_copy);\n+\ttransport = transport_get(remote, ref_git_copy);\n+\tfor (extra = transport_get_remote_refs(transport); extra;\n+\t     extra = extra->next)\n+\t\tadd_extra_ref(extra->name, extra->old_sha1, 0);\n+\n+\ttransport_disconnect(transport);\n+\n+\tfree(ref_git_copy);\n+}\n+\n+static void copy_or_link_directory(char *src, char *dest)\n+{\n+\tstruct dirent *de;\n+\tstruct stat buf;\n+\tint src_len, dest_len;\n+\tDIR *dir;\n+\n+\tdir = opendir(src);\n+\tif (!dir)\n+\t\tdie(\"failed to open %s\\n\", src);\n+\n+\tif (mkdir(dest, 0777)) {\n+\t\tif (errno != EEXIST)\n+\t\t\tdie(\"failed to create directory %s\\n\", dest);\n+\t\telse if (stat(dest, &buf))\n+\t\t\tdie(\"failed to stat %s\\n\", dest);\n+\t\telse if (!S_ISDIR(buf.st_mode))\n+\t\t\tdie(\"%s exists and is not a directory\\n\", dest);\n+\t}\n+\n+\tsrc_len = strlen(src);\n+\tsrc[src_len] = '/';\n+\tdest_len = strlen(dest);\n+\tdest[dest_len] = '/';\n+\n+\twhile ((de = readdir(dir)) != NULL) {\n+\t\tstrcpy(src + src_len + 1, de->d_name);\n+\t\tstrcpy(dest + dest_len + 1, de->d_name);\n+\t\tif (stat(src, &buf)) {\n+\t\t\twarning (\"failed to stat %s\\n\", src);\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (S_ISDIR(buf.st_mode)) {\n+\t\t\tif (de->d_name[0] != '.')\n+\t\t\t\tcopy_or_link_directory(src, dest);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (unlink(dest) && errno != ENOENT)\n+\t\t\tdie(\"failed to unlink %s\\n\", dest);\n+\t\tif (option_no_hardlinks) {\n+\t\t\tif (copy_file(dest, src, 0666))\n+\t\t\t\tdie(\"failed to copy file to %s\\n\", dest);\n+\t\t} else {\n+\t\t\tif (link(src, dest))\n+\t\t\t\tdie(\"failed to create link %s\\n\", dest);\n+\t\t}\n+\t}\n+}\n+\n+static const struct ref * clone_local(const char *src_repo,\n+\t\tconst char *dest_repo)\n+{\n+\tconst struct ref *ret;\n+\tchar src[PATH_MAX];\n+\tchar dest[PATH_MAX];\n+\tstruct remote *remote;\n+\tstruct transport *transport;\n+\n+\tif (option_shared)\n+\t\tadd_to_alternates_file(src_repo);\n+\telse {\n+\t\tsnprintf(src, PATH_MAX, \"%s/objects\", src_repo);\n+\t\tsnprintf(dest, PATH_MAX, \"%s/objects\", dest_repo);\n+\t\tcopy_or_link_directory(src, dest);\n+\t}\n+\n+\tremote = remote_get(src_repo);\n+\ttransport = transport_get(remote, src_repo);\n+\tret = transport_get_remote_refs(transport);\n+\ttransport_disconnect(transport);\n+\treturn ret;\n+}\n+\n+static const char *junk_work_tree;\n+static const char *junk_git_dir;\n+pid_t junk_pid;\n+\n+static void remove_junk(void)\n+{\n+\tstruct strbuf sb;\n+\tif (getpid() != junk_pid)\n+\t\treturn;\n+\tstrbuf_init(&sb, 0);\n+\tif (junk_git_dir) {\n+\t\tstrbuf_addstr(&sb, junk_git_dir);\n+\t\tremove_dir_recursively(&sb, 0);\n+\t\tstrbuf_reset(&sb);\n+\t}\n+\tif (junk_work_tree) {\n+\t\tstrbuf_addstr(&sb, junk_work_tree);\n+\t\tremove_dir_recursively(&sb, 0);\n+\t\tstrbuf_reset(&sb);\n+\t}\n+}\n+\n+static void remove_junk_on_signal(int signo)\n+{\n+\tremove_junk();\n+\tsignal(SIGINT, SIG_DFL);\n+\traise(signo);\n+}\n+\n+static const struct ref *locate_head(const struct ref *refs,\n+\t\t\t\t     const struct ref *mapped_refs,\n+\t\t\t\t     const struct ref **remote_head_p)\n+{\n+\tconst struct ref *remote_head = NULL;\n+\tconst struct ref *remote_master = NULL;\n+\tconst struct ref *r;\n+\tfor (r = refs; r; r = r->next)\n+\t\tif (!strcmp(r->name, \"HEAD\"))\n+\t\t\tremote_head = r;\n+\n+\tfor (r = mapped_refs; r; r = r->next)\n+\t\tif (!strcmp(r->name, \"refs/heads/master\"))\n+\t\t\tremote_master = r;\n+\n+\tif (remote_head_p)\n+\t\t*remote_head_p = remote_head;\n+\n+\t/* If there's no HEAD value at all, never mind. */\n+\tif (!remote_head)\n+\t\treturn NULL;\n+\n+\t/* If refs/heads/master could be right, it is. */\n+\tif (remote_master && !hashcmp(remote_master->old_sha1,\n+\t\t\t\t      remote_head->old_sha1))\n+\t\treturn remote_master;\n+\n+\t/* Look for another ref that points there */\n+\tfor (r = mapped_refs; r; r = r->next)\n+\t\tif (r != remote_head &&\n+\t\t    !hashcmp(r->old_sha1, remote_head->old_sha1))\n+\t\t\treturn r;\n+\n+\t/* Nothing is the same */\n+\treturn NULL;\n+}\n+\n+static struct ref *write_remote_refs(const struct ref *refs,\n+\t\tstruct refspec *refspec, const char *reflog)\n+{\n+\tstruct ref *local_refs = NULL;\n+\tstruct ref **tail = &local_refs;\n+\tstruct ref *r;\n+\n+\tget_fetch_map(refs, refspec, &tail, 0);\n+\tget_fetch_map(refs, tag_refspec, &tail, 0);\n+\n+\tfor (r = local_refs; r; r = r->next)\n+\t\tupdate_ref(reflog,\n+\t\t\t   r->peer_ref->name, r->old_sha1, NULL, 0, DIE_ON_ERR);\n+\treturn local_refs;\n+}\n+\n+int cmd_clone(int argc, const char **argv, const char *prefix)\n+{\n+\tint use_local_hardlinks = 1;\n+\tint use_separate_remote = 1;\n+\tint is_bundle = 0;\n+\tstruct stat buf;\n+\tconst char *repo_name, *repo, *work_tree, *git_dir;\n+\tchar *path, *dir;\n+\tconst struct ref *refs, *head_points_at, *remote_head, *mapped_refs;\n+\tchar branch_top[256], key[256], value[256];\n+\tstruct strbuf reflog_msg;\n+\n+\tstruct refspec refspec;\n+\n+\tjunk_pid = getpid();\n+\n+\targc = parse_options(argc, argv, builtin_clone_options,\n+\t\t\t     builtin_clone_usage, 0);\n+\n+\tif (argc == 0)\n+\t\tdie(\"You must specify a repository to clone.\");\n+\n+\tif (option_no_hardlinks)\n+\t\tuse_local_hardlinks = 0;\n+\n+\tif (option_bare) {\n+\t\tif (option_origin)\n+\t\t\tdie(\"--bare and --origin %s options are incompatible.\",\n+\t\t\t    option_origin);\n+\t\toption_no_checkout = 1;\n+\t\tuse_separate_remote = 0;\n+\t}\n+\n+\tif (!option_origin)\n+\t\toption_origin = \"origin\";\n+\n+\trepo_name = argv[0];\n+\n+\tpath = get_repo_path(repo_name, &is_bundle);\n+\tif (path)\n+\t\trepo = path;\n+\telse if (!strchr(repo_name, ':'))\n+\t\trepo = xstrdup(make_absolute_path(repo_name));\n+\telse\n+\t\trepo = repo_name;\n+\n+\tif (argc == 2)\n+\t\tdir = xstrdup(argv[1]);\n+\telse\n+\t\tdir = guess_dir_name(repo_name, is_bundle);\n+\n+\tif (!stat(dir, &buf))\n+\t\tdie(\"destination directory '%s' already exists.\", dir);\n+\n+\tstrbuf_init(&reflog_msg, 0);\n+\tstrbuf_addf(&reflog_msg, \"clone: from %s\", repo);\n+\n+\tif (option_bare)\n+\t\twork_tree = NULL;\n+\telse {\n+\t\twork_tree = getenv(\"GIT_WORK_TREE\");\n+\t\tif (work_tree && !stat(work_tree, &buf))\n+\t\t\tdie(\"working tree '%s' already exists.\", work_tree);\n+\t}\n+\n+\tif (option_bare || work_tree)\n+\t\tgit_dir = xstrdup(dir);\n+\telse {\n+\t\twork_tree = dir;\n+\t\tgit_dir = xstrdup(mkpath(\"%s/.git\", dir));\n+\t}\n+\n+\tif (!option_bare) {\n+\t\tjunk_work_tree = work_tree;\n+\t\tif (mkdir(work_tree, 0755))\n+\t\t\tdie(\"could not create work tree dir '%s'.\", work_tree);\n+\t\tset_git_work_tree(work_tree);\n+\t}\n+\tjunk_git_dir = git_dir;\n+\tatexit(remove_junk);\n+\tsignal(SIGINT, remove_junk_on_signal);\n+\n+\tsetenv(CONFIG_ENVIRONMENT, xstrdup(mkpath(\"%s/config\", git_dir)), 1);\n+\n+\tset_git_dir(make_absolute_path(git_dir));\n+\n+\tfprintf(stderr, \"Initialize %s\\n\", git_dir);\n+\tinit_db(option_template, option_quiet ? INIT_DB_QUIET : 0);\n+\n+\tif (option_reference)\n+\t\tsetup_reference(git_dir);\n+\n+\tgit_config(git_default_config);\n+\n+\tif (option_bare) {\n+\t\tstrcpy(branch_top, \"refs/heads/\");\n+\n+\t\tgit_config_set(\"core.bare\", \"true\");\n+\t} else {\n+\t\tsnprintf(branch_top, sizeof(branch_top),\n+\t\t\t \"refs/remotes/%s/\", option_origin);\n+\n+\t\t/* Configure the remote */\n+\t\tsnprintf(key, sizeof(key), \"remote.%s.url\", option_origin);\n+\t\tgit_config_set(key, repo);\n+\n+\t\tsnprintf(key, sizeof(key), \"remote.%s.fetch\", option_origin);\n+\t\tsnprintf(value, sizeof(value),\n+\t\t\t\t\"+refs/heads/*:%s*\", branch_top);\n+\t\tgit_config_set_multivar(key, value, \"^$\", 0);\n+\t}\n+\n+\trefspec.force = 0;\n+\trefspec.pattern = 1;\n+\trefspec.src = \"refs/heads/\";\n+\trefspec.dst = branch_top;\n+\n+\tif (path && !is_bundle)\n+\t\trefs = clone_local(path, git_dir);\n+\telse {\n+\t\tstruct remote *remote = remote_get(argv[0]);\n+\t\tstruct transport *transport = transport_get(remote, argv[0]);\n+\n+\t\ttransport_set_option(transport, TRANS_OPT_KEEP, \"yes\");\n+\n+\t\tif (option_depth)\n+\t\t\ttransport_set_option(transport, TRANS_OPT_DEPTH,\n+\t\t\t\t\t     option_depth);\n+\n+\t\tif (option_quiet)\n+\t\t\ttransport->verbose = -1;\n+\n+\t\trefs = transport_get_remote_refs(transport);\n+\t\ttransport_fetch_refs(transport, refs);\n+\t}\n+\n+\tclear_extra_refs();\n+\n+\tmapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf);\n+\n+\thead_points_at = locate_head(refs, mapped_refs, &remote_head);\n+\n+\tif (head_points_at) {\n+\t\t/* Local default branch link */\n+\t\tcreate_symref(\"HEAD\", head_points_at->name, NULL);\n+\n+\t\tif (!option_bare) {\n+\t\t\tstruct strbuf head_ref;\n+\t\t\tconst char *head = head_points_at->name;\n+\n+\t\t\tif (!prefixcmp(head, \"refs/heads/\"))\n+\t\t\t\thead += 11;\n+\n+\t\t\t/* Set up the initial local branch */\n+\n+\t\t\t/* Local branch initial value */\n+\t\t\tupdate_ref(reflog_msg.buf, \"HEAD\",\n+\t\t\t\t   head_points_at->old_sha1,\n+\t\t\t\t   NULL, 0, DIE_ON_ERR);\n+\n+\t\t\tstrbuf_init(&head_ref, 0);\n+\t\t\tstrbuf_addstr(&head_ref, branch_top);\n+\t\t\tstrbuf_addstr(&head_ref, \"HEAD\");\n+\n+\t\t\t/* Remote branch link */\n+\t\t\tcreate_symref(head_ref.buf,\n+\t\t\t\t      head_points_at->peer_ref->name,\n+\t\t\t\t      reflog_msg.buf);\n+\n+\t\t\tsnprintf(key, sizeof(key), \"branch.%s.remote\", head);\n+\t\t\tgit_config_set(key, option_origin);\n+\t\t\tsnprintf(key, sizeof(key), \"branch.%s.merge\", head);\n+\t\t\tgit_config_set(key, head_points_at->name);\n+\t\t}\n+\t} else if (remote_head) {\n+\t\t/* Source had detached HEAD pointing somewhere. */\n+\t\tif (option_bare)\n+\t\t\toption_no_checkout = 1;\n+\t\telse\n+\t\t\tupdate_ref(reflog_msg.buf, \"HEAD\",\n+\t\t\t\t   remote_head->old_sha1,\n+\t\t\t\t   NULL, REF_NODEREF, DIE_ON_ERR);\n+\t} else {\n+\t\t/* Nothing to checkout out */\n+\t\tif (!option_no_checkout)\n+\t\t\twarning (\"remote HEAD refers to nonexistent ref, \"\n+\t\t\t\t\"unable to checkout.\\n\");\n+\t\toption_no_checkout = 1;\n+\t}\n+\n+\tif (!option_no_checkout) {\n+\t\tstruct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));\n+\t\tstruct unpack_trees_options opts;\n+\t\tstruct tree *tree;\n+\t\tstruct tree_desc t;\n+\t\tint fd;\n+\n+\t\t/* We need to be in the new work tree for the checkout */\n+\t\tsetup_work_tree();\n+\n+\t\tfd = hold_locked_index(lock_file, 1);\n+\n+\t\tmemset(&opts, 0, sizeof opts);\n+\t\topts.update = 1;\n+\t\topts.verbose_update = !option_quiet;\n+\t\topts.dst_index = &the_index;\n+\n+\t\ttree = parse_tree_indirect(remote_head->old_sha1);\n+\t\tparse_tree(tree);\n+\t\tinit_tree_desc(&t, tree->buffer, tree->size);\n+\t\tunpack_trees(1, &t, &opts);\n+\n+\t\tif (write_cache(fd, active_cache, active_nr) ||\n+\t\t    commit_locked_index(lock_file))\n+\t\t\tdie(\"unable to write new index file\");\n+\t}\n+\n+\tstrbuf_release(&reflog_msg);\n+\tjunk_pid = 0;\n+\treturn 0;\n+}\ndiff --git a/builtin.h b/builtin.h\nindex 95126fd..23a90de 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -24,6 +24,7 @@ extern int cmd_check_attr(int argc, const char **argv, const char *prefix);\n extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);\n extern int cmd_cherry(int argc, const char **argv, const char *prefix);\n extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);\n+extern int cmd_clone(int argc, const char **argv, const char *prefix);\n extern int cmd_clean(int argc, const char **argv, const char *prefix);\n extern int cmd_commit(int argc, const char **argv, const char *prefix);\n extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);\ndiff --git a/contrib/examples/git-clone.sh b/contrib/examples/git-clone.sh\nnew file mode 100755\nindex 0000000..2636159\n--- /dev/null\n+++ b/contrib/examples/git-clone.sh\n@@ -0,0 +1,522 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2005, Linus Torvalds\n+# Copyright (c) 2005, Junio C Hamano\n+#\n+# Clone a repository into a different directory that does not yet exist.\n+\n+# See git-sh-setup why.\n+unset CDPATH\n+\n+OPTIONS_SPEC=\"\\\n+git-clone [options] [--] <repo> [<dir>]\n+--\n+n,no-checkout        don't create a checkout\n+bare                 create a bare repository\n+naked                create a bare repository\n+l,local              to clone from a local repository\n+no-hardlinks         don't use local hardlinks, always copy\n+s,shared             setup as a shared repository\n+template=            path to the template directory\n+q,quiet              be quiet\n+reference=           reference repository\n+o,origin=            use <name> instead of 'origin' to track upstream\n+u,upload-pack=       path to git-upload-pack on the remote\n+depth=               create a shallow clone of that depth\n+\n+use-separate-remote  compatibility, do not use\n+no-separate-remote   compatibility, do not use\"\n+\n+die() {\n+\techo >&2 \"$@\"\n+\texit 1\n+}\n+\n+usage() {\n+\texec \"$0\" -h\n+}\n+\n+eval \"$(echo \"$OPTIONS_SPEC\" | git rev-parse --parseopt -- \"$@\" || echo exit $?)\"\n+\n+get_repo_base() {\n+\t(\n+\t\tcd \"`/bin/pwd`\" &&\n+\t\tcd \"$1\" || cd \"$1.git\" &&\n+\t\t{\n+\t\t\tcd .git\n+\t\t\tpwd\n+\t\t}\n+\t) 2>/dev/null\n+}\n+\n+if [ -n \"$GIT_SSL_NO_VERIFY\" -o \\\n+\t\"`git config --bool http.sslVerify`\" = false ]; then\n+    curl_extra_args=\"-k\"\n+fi\n+\n+http_fetch () {\n+\t# $1 = Remote, $2 = Local\n+\tcurl -nsfL $curl_extra_args \"$1\" >\"$2\"\n+\tcurl_exit_status=$?\n+\tcase $curl_exit_status in\n+\t126|127) exit ;;\n+\t*)\t return $curl_exit_status ;;\n+\tesac\n+}\n+\n+clone_dumb_http () {\n+\t# $1 - remote, $2 - local\n+\tcd \"$2\" &&\n+\tclone_tmp=\"$GIT_DIR/clone-tmp\" &&\n+\tmkdir -p \"$clone_tmp\" || exit 1\n+\tif [ -n \"$GIT_CURL_FTP_NO_EPSV\" -o \\\n+\t\t\"`git config --bool http.noEPSV`\" = true ]; then\n+\t\tcurl_extra_args=\"${curl_extra_args} --disable-epsv\"\n+\tfi\n+\thttp_fetch \"$1/info/refs\" \"$clone_tmp/refs\" ||\n+\t\tdie \"Cannot get remote repository information.\n+Perhaps git-update-server-info needs to be run there?\"\n+\ttest \"z$quiet\" = z && v=-v || v=\n+\twhile read sha1 refname\n+\tdo\n+\t\tname=`expr \"z$refname\" : 'zrefs/\\(.*\\)'` &&\n+\t\tcase \"$name\" in\n+\t\t*^*)\tcontinue;;\n+\t\tesac\n+\t\tcase \"$bare,$name\" in\n+\t\tyes,* | ,heads/* | ,tags/*) ;;\n+\t\t*)\tcontinue ;;\n+\t\tesac\n+\t\tif test -n \"$use_separate_remote\" &&\n+\t\t   branch_name=`expr \"z$name\" : 'zheads/\\(.*\\)'`\n+\t\tthen\n+\t\t\ttname=\"remotes/$origin/$branch_name\"\n+\t\telse\n+\t\t\ttname=$name\n+\t\tfi\n+\t\tgit-http-fetch $v -a -w \"$tname\" \"$sha1\" \"$1\" || exit 1\n+\tdone <\"$clone_tmp/refs\"\n+\trm -fr \"$clone_tmp\"\n+\thttp_fetch \"$1/HEAD\" \"$GIT_DIR/REMOTE_HEAD\" ||\n+\trm -f \"$GIT_DIR/REMOTE_HEAD\"\n+\tif test -f \"$GIT_DIR/REMOTE_HEAD\"; then\n+\t\thead_sha1=`cat \"$GIT_DIR/REMOTE_HEAD\"`\n+\t\tcase \"$head_sha1\" in\n+\t\t'ref: refs/'*)\n+\t\t\t;;\n+\t\t*)\n+\t\t\tgit-http-fetch $v -a \"$head_sha1\" \"$1\" ||\n+\t\t\trm -f \"$GIT_DIR/REMOTE_HEAD\"\n+\t\t\t;;\n+\t\tesac\n+\tfi\n+}\n+\n+quiet=\n+local=no\n+use_local_hardlink=yes\n+local_shared=no\n+unset template\n+no_checkout=\n+upload_pack=\n+bare=\n+reference=\n+origin=\n+origin_override=\n+use_separate_remote=t\n+depth=\n+no_progress=\n+local_explicitly_asked_for=\n+test -t 1 || no_progress=--no-progress\n+\n+while test $# != 0\n+do\n+\tcase \"$1\" in\n+\t-n|--no-checkout)\n+\t\tno_checkout=yes ;;\n+\t--naked|--bare)\n+\t\tbare=yes ;;\n+\t-l|--local)\n+\t\tlocal_explicitly_asked_for=yes\n+\t\tuse_local_hardlink=yes\n+\t\t;;\n+\t--no-hardlinks)\n+\t\tuse_local_hardlink=no ;;\n+\t-s|--shared)\n+\t\tlocal_shared=yes ;;\n+\t--template)\n+\t\tshift; template=\"--template=$1\" ;;\n+\t-q|--quiet)\n+\t\tquiet=-q ;;\n+\t--use-separate-remote|--no-separate-remote)\n+\t\tdie \"clones are always made with separate-remote layout\" ;;\n+\t--reference)\n+\t\tshift; reference=\"$1\" ;;\n+\t-o|--origin)\n+\t\tshift;\n+\t\tcase \"$1\" in\n+\t\t'')\n+\t\t    usage ;;\n+\t\t*/*)\n+\t\t    die \"'$1' is not suitable for an origin name\"\n+\t\tesac\n+\t\tgit check-ref-format \"heads/$1\" ||\n+\t\t    die \"'$1' is not suitable for a branch name\"\n+\t\ttest -z \"$origin_override\" ||\n+\t\t    die \"Do not give more than one --origin options.\"\n+\t\torigin_override=yes\n+\t\torigin=\"$1\"\n+\t\t;;\n+\t-u|--upload-pack)\n+\t\tshift\n+\t\tupload_pack=\"--upload-pack=$1\" ;;\n+\t--depth)\n+\t\tshift\n+\t\tdepth=\"--depth=$1\" ;;\n+\t--)\n+\t\tshift\n+\t\tbreak ;;\n+\t*)\n+\t\tusage ;;\n+\tesac\n+\tshift\n+done\n+\n+repo=\"$1\"\n+test -n \"$repo\" ||\n+    die 'you must specify a repository to clone.'\n+\n+# --bare implies --no-checkout and --no-separate-remote\n+if test yes = \"$bare\"\n+then\n+\tif test yes = \"$origin_override\"\n+\tthen\n+\t\tdie '--bare and --origin $origin options are incompatible.'\n+\tfi\n+\tno_checkout=yes\n+\tuse_separate_remote=\n+fi\n+\n+if test -z \"$origin\"\n+then\n+\torigin=origin\n+fi\n+\n+# Turn the source into an absolute path if\n+# it is local\n+if base=$(get_repo_base \"$repo\"); then\n+\trepo=\"$base\"\n+\tif test -z \"$depth\"\n+\tthen\n+\t\tlocal=yes\n+\tfi\n+elif test -f \"$repo\"\n+then\n+\tcase \"$repo\" in /*) ;; *) repo=\"$PWD/$repo\" ;; esac\n+fi\n+\n+# Decide the directory name of the new repository\n+if test -n \"$2\"\n+then\n+\tdir=\"$2\"\n+else\n+\t# Derive one from the repository name\n+\t# Try using \"humanish\" part of source repo if user didn't specify one\n+\tif test -f \"$repo\"\n+\tthen\n+\t\t# Cloning from a bundle\n+\t\tdir=$(echo \"$repo\" | sed -e 's|/*\\.bundle$||' -e 's|.*/||g')\n+\telse\n+\t\tdir=$(echo \"$repo\" |\n+\t\t\tsed -e 's|/$||' -e 's|:*/*\\.git$||' -e 's|.*[/:]||g')\n+\tfi\n+fi\n+\n+[ -e \"$dir\" ] && die \"destination directory '$dir' already exists.\"\n+[ yes = \"$bare\" ] && unset GIT_WORK_TREE\n+[ -n \"$GIT_WORK_TREE\" ] && [ -e \"$GIT_WORK_TREE\" ] &&\n+die \"working tree '$GIT_WORK_TREE' already exists.\"\n+D=\n+W=\n+cleanup() {\n+\terr=$?\n+\ttest -z \"$D\" && rm -rf \"$dir\"\n+\ttest -z \"$W\" && test -n \"$GIT_WORK_TREE\" && rm -rf \"$GIT_WORK_TREE\"\n+\tcd ..\n+\ttest -n \"$D\" && rm -rf \"$D\"\n+\ttest -n \"$W\" && rm -rf \"$W\"\n+\texit $err\n+}\n+trap cleanup 0\n+mkdir -p \"$dir\" && D=$(cd \"$dir\" && pwd) || usage\n+test -n \"$GIT_WORK_TREE\" && mkdir -p \"$GIT_WORK_TREE\" &&\n+W=$(cd \"$GIT_WORK_TREE\" && pwd) && GIT_WORK_TREE=\"$W\" && export GIT_WORK_TREE\n+if test yes = \"$bare\" || test -n \"$GIT_WORK_TREE\"; then\n+\tGIT_DIR=\"$D\"\n+else\n+\tGIT_DIR=\"$D/.git\"\n+fi &&\n+export GIT_DIR &&\n+GIT_CONFIG=\"$GIT_DIR/config\" git-init $quiet ${template+\"$template\"} || usage\n+\n+if test -n \"$bare\"\n+then\n+\tGIT_CONFIG=\"$GIT_DIR/config\" git config core.bare true\n+fi\n+\n+if test -n \"$reference\"\n+then\n+\tref_git=\n+\tif test -d \"$reference\"\n+\tthen\n+\t\tif test -d \"$reference/.git/objects\"\n+\t\tthen\n+\t\t\tref_git=\"$reference/.git\"\n+\t\telif test -d \"$reference/objects\"\n+\t\tthen\n+\t\t\tref_git=\"$reference\"\n+\t\tfi\n+\tfi\n+\tif test -n \"$ref_git\"\n+\tthen\n+\t\tref_git=$(cd \"$ref_git\" && pwd)\n+\t\techo \"$ref_git/objects\" >\"$GIT_DIR/objects/info/alternates\"\n+\t\t(\n+\t\t\tGIT_DIR=\"$ref_git\" git for-each-ref \\\n+\t\t\t\t--format='%(objectname) %(*objectname)'\n+\t\t) |\n+\t\twhile read a b\n+\t\tdo\n+\t\t\ttest -z \"$a\" ||\n+\t\t\tgit update-ref \"refs/reference-tmp/$a\" \"$a\"\n+\t\t\ttest -z \"$b\" ||\n+\t\t\tgit update-ref \"refs/reference-tmp/$b\" \"$b\"\n+\t\tdone\n+\telse\n+\t\tdie \"reference repository '$reference' is not a local directory.\"\n+\tfi\n+fi\n+\n+rm -f \"$GIT_DIR/CLONE_HEAD\"\n+\n+# We do local magic only when the user tells us to.\n+case \"$local\" in\n+yes)\n+\t( cd \"$repo/objects\" ) ||\n+\t\tdie \"cannot chdir to local '$repo/objects'.\"\n+\n+\tif test \"$local_shared\" = yes\n+\tthen\n+\t\tmkdir -p \"$GIT_DIR/objects/info\"\n+\t\techo \"$repo/objects\" >>\"$GIT_DIR/objects/info/alternates\"\n+\telse\n+\t\tcpio_quiet_flag=\"\"\n+\t\tcpio --help 2>&1 | grep -- --quiet >/dev/null && \\\n+\t\t\tcpio_quiet_flag=--quiet\n+\t\tl= &&\n+\t\tif test \"$use_local_hardlink\" = yes\n+\t\tthen\n+\t\t\t# See if we can hardlink and drop \"l\" if not.\n+\t\t\tsample_file=$(cd \"$repo\" && \\\n+\t\t\t\t      find objects -type f -print | sed -e 1q)\n+\t\t\t# objects directory should not be empty because\n+\t\t\t# we are cloning!\n+\t\t\ttest -f \"$repo/$sample_file\" ||\n+\t\t\t\tdie \"fatal: cannot clone empty repository\"\n+\t\t\tif ln \"$repo/$sample_file\" \"$GIT_DIR/objects/sample\" 2>/dev/null\n+\t\t\tthen\n+\t\t\t\trm -f \"$GIT_DIR/objects/sample\"\n+\t\t\t\tl=l\n+\t\t\telif test -n \"$local_explicitly_asked_for\"\n+\t\t\tthen\n+\t\t\t\techo >&2 \"Warning: -l asked but cannot hardlink to $repo\"\n+\t\t\tfi\n+\t\tfi &&\n+\t\tcd \"$repo\" &&\n+\t\tfind objects -depth -print | cpio $cpio_quiet_flag -pumd$l \"$GIT_DIR/\" || \\\n+\t\t\texit 1\n+\tfi\n+\tgit-ls-remote \"$repo\" >\"$GIT_DIR/CLONE_HEAD\" || exit 1\n+\t;;\n+*)\n+\tcase \"$repo\" in\n+\trsync://*)\n+\t\tcase \"$depth\" in\n+\t\t\"\") ;;\n+\t\t*) die \"shallow over rsync not supported\" ;;\n+\t\tesac\n+\t\trsync $quiet -av --ignore-existing  \\\n+\t\t\t--exclude info \"$repo/objects/\" \"$GIT_DIR/objects/\" ||\n+\t\texit\n+\t\t# Look at objects/info/alternates for rsync -- http will\n+\t\t# support it natively and git native ones will do it on the\n+\t\t# remote end.  Not having that file is not a crime.\n+\t\trsync -q \"$repo/objects/info/alternates\" \\\n+\t\t\t\"$GIT_DIR/TMP_ALT\" 2>/dev/null ||\n+\t\t\trm -f \"$GIT_DIR/TMP_ALT\"\n+\t\tif test -f \"$GIT_DIR/TMP_ALT\"\n+\t\tthen\n+\t\t    ( cd \"$D\" &&\n+\t\t      . git-parse-remote &&\n+\t\t      resolve_alternates \"$repo\" <\"$GIT_DIR/TMP_ALT\" ) |\n+\t\t    while read alt\n+\t\t    do\n+\t\t\tcase \"$alt\" in 'bad alternate: '*) die \"$alt\";; esac\n+\t\t\tcase \"$quiet\" in\n+\t\t\t'')\techo >&2 \"Getting alternate: $alt\" ;;\n+\t\t\tesac\n+\t\t\trsync $quiet -av --ignore-existing  \\\n+\t\t\t    --exclude info \"$alt\" \"$GIT_DIR/objects\" || exit\n+\t\t    done\n+\t\t    rm -f \"$GIT_DIR/TMP_ALT\"\n+\t\tfi\n+\t\tgit-ls-remote \"$repo\" >\"$GIT_DIR/CLONE_HEAD\" || exit 1\n+\t\t;;\n+\thttps://*|http://*|ftp://*)\n+\t\tcase \"$depth\" in\n+\t\t\"\") ;;\n+\t\t*) die \"shallow over http or ftp not supported\" ;;\n+\t\tesac\n+\t\tif test -z \"@@NO_CURL@@\"\n+\t\tthen\n+\t\t\tclone_dumb_http \"$repo\" \"$D\"\n+\t\telse\n+\t\t\tdie \"http transport not supported, rebuild Git with curl support\"\n+\t\tfi\n+\t\t;;\n+\t*)\n+\t\tif [ -f \"$repo\" ] ; then\n+\t\t\tgit bundle unbundle \"$repo\" > \"$GIT_DIR/CLONE_HEAD\" ||\n+\t\t\tdie \"unbundle from '$repo' failed.\"\n+\t\telse\n+\t\t\tcase \"$upload_pack\" in\n+\t\t\t'') git-fetch-pack --all -k $quiet $depth $no_progress \"$repo\";;\n+\t\t\t*) git-fetch-pack --all -k \\\n+\t\t\t\t$quiet \"$upload_pack\" $depth $no_progress \"$repo\" ;;\n+\t\t\tesac >\"$GIT_DIR/CLONE_HEAD\" ||\n+\t\t\tdie \"fetch-pack from '$repo' failed.\"\n+\t\tfi\n+\t\t;;\n+\tesac\n+\t;;\n+esac\n+test -d \"$GIT_DIR/refs/reference-tmp\" && rm -fr \"$GIT_DIR/refs/reference-tmp\"\n+\n+if test -f \"$GIT_DIR/CLONE_HEAD\"\n+then\n+\t# Read git-fetch-pack -k output and store the remote branches.\n+\tif [ -n \"$use_separate_remote\" ]\n+\tthen\n+\t\tbranch_top=\"remotes/$origin\"\n+\telse\n+\t\tbranch_top=\"heads\"\n+\tfi\n+\ttag_top=\"tags\"\n+\twhile read sha1 name\n+\tdo\n+\t\tcase \"$name\" in\n+\t\t*'^{}')\n+\t\t\tcontinue ;;\n+\t\tHEAD)\n+\t\t\tdestname=\"REMOTE_HEAD\" ;;\n+\t\trefs/heads/*)\n+\t\t\tdestname=\"refs/$branch_top/${name#refs/heads/}\" ;;\n+\t\trefs/tags/*)\n+\t\t\tdestname=\"refs/$tag_top/${name#refs/tags/}\" ;;\n+\t\t*)\n+\t\t\tcontinue ;;\n+\t\tesac\n+\t\tgit update-ref -m \"clone: from $repo\" \"$destname\" \"$sha1\" \"\"\n+\tdone < \"$GIT_DIR/CLONE_HEAD\"\n+fi\n+\n+if test -n \"$W\"; then\n+\tcd \"$W\" || exit\n+else\n+\tcd \"$D\" || exit\n+fi\n+\n+if test -z \"$bare\"\n+then\n+\t# a non-bare repository is always in separate-remote layout\n+\tremote_top=\"refs/remotes/$origin\"\n+\thead_sha1=\n+\ttest ! -r \"$GIT_DIR/REMOTE_HEAD\" || head_sha1=`cat \"$GIT_DIR/REMOTE_HEAD\"`\n+\tcase \"$head_sha1\" in\n+\t'ref: refs/'*)\n+\t\t# Uh-oh, the remote told us (http transport done against\n+\t\t# new style repository with a symref HEAD).\n+\t\t# Ideally we should skip the guesswork but for now\n+\t\t# opt for minimum change.\n+\t\thead_sha1=`expr \"z$head_sha1\" : 'zref: refs/heads/\\(.*\\)'`\n+\t\thead_sha1=`cat \"$GIT_DIR/$remote_top/$head_sha1\"`\n+\t\t;;\n+\tesac\n+\n+\t# The name under $remote_top the remote HEAD seems to point at.\n+\thead_points_at=$(\n+\t\t(\n+\t\t\ttest -f \"$GIT_DIR/$remote_top/master\" && echo \"master\"\n+\t\t\tcd \"$GIT_DIR/$remote_top\" &&\n+\t\t\tfind . -type f -print | sed -e 's/^\\.\\///'\n+\t\t) | (\n+\t\tdone=f\n+\t\twhile read name\n+\t\tdo\n+\t\t\ttest t = $done && continue\n+\t\t\tbranch_tip=`cat \"$GIT_DIR/$remote_top/$name\"`\n+\t\t\tif test \"$head_sha1\" = \"$branch_tip\"\n+\t\t\tthen\n+\t\t\t\techo \"$name\"\n+\t\t\t\tdone=t\n+\t\t\tfi\n+\t\tdone\n+\t\t)\n+\t)\n+\n+\t# Upstream URL\n+\tgit config remote.\"$origin\".url \"$repo\" &&\n+\n+\t# Set up the mappings to track the remote branches.\n+\tgit config remote.\"$origin\".fetch \\\n+\t\t\"+refs/heads/*:$remote_top/*\" '^$' &&\n+\n+\t# Write out remote.$origin config, and update our \"$head_points_at\".\n+\tcase \"$head_points_at\" in\n+\t?*)\n+\t\t# Local default branch\n+\t\tgit symbolic-ref HEAD \"refs/heads/$head_points_at\" &&\n+\n+\t\t# Tracking branch for the primary branch at the remote.\n+\t\tgit update-ref HEAD \"$head_sha1\" &&\n+\n+\t\trm -f \"refs/remotes/$origin/HEAD\"\n+\t\tgit symbolic-ref \"refs/remotes/$origin/HEAD\" \\\n+\t\t\t\"refs/remotes/$origin/$head_points_at\" &&\n+\n+\t\tgit config branch.\"$head_points_at\".remote \"$origin\" &&\n+\t\tgit config branch.\"$head_points_at\".merge \"refs/heads/$head_points_at\"\n+\t\t;;\n+\t'')\n+\t\tif test -z \"$head_sha1\"\n+\t\tthen\n+\t\t\t# Source had nonexistent ref in HEAD\n+\t\t\techo >&2 \"Warning: Remote HEAD refers to nonexistent ref, unable to checkout.\"\n+\t\t\tno_checkout=t\n+\t\telse\n+\t\t\t# Source had detached HEAD pointing nowhere\n+\t\t\tgit update-ref --no-deref HEAD \"$head_sha1\" &&\n+\t\t\trm -f \"refs/remotes/$origin/HEAD\"\n+\t\tfi\n+\t\t;;\n+\tesac\n+\n+\tcase \"$no_checkout\" in\n+\t'')\n+\t\ttest \"z$quiet\" = z -a \"z$no_progress\" = z && v=-v || v=\n+\t\tgit read-tree -m -u $v HEAD HEAD\n+\tesac\n+fi\n+rm -f \"$GIT_DIR/CLONE_HEAD\" \"$GIT_DIR/REMOTE_HEAD\"\n+\n+trap - 0\ndiff --git a/git-clone.sh b/git-clone.sh\ndeleted file mode 100755\nindex 2636159..0000000\n--- a/git-clone.sh\n+++ /dev/null\n@@ -1,522 +0,0 @@\n-#!/bin/sh\n-#\n-# Copyright (c) 2005, Linus Torvalds\n-# Copyright (c) 2005, Junio C Hamano\n-#\n-# Clone a repository into a different directory that does not yet exist.\n-\n-# See git-sh-setup why.\n-unset CDPATH\n-\n-OPTIONS_SPEC=\"\\\n-git-clone [options] [--] <repo> [<dir>]\n---\n-n,no-checkout        don't create a checkout\n-bare                 create a bare repository\n-naked                create a bare repository\n-l,local              to clone from a local repository\n-no-hardlinks         don't use local hardlinks, always copy\n-s,shared             setup as a shared repository\n-template=            path to the template directory\n-q,quiet              be quiet\n-reference=           reference repository\n-o,origin=            use <name> instead of 'origin' to track upstream\n-u,upload-pack=       path to git-upload-pack on the remote\n-depth=               create a shallow clone of that depth\n-\n-use-separate-remote  compatibility, do not use\n-no-separate-remote   compatibility, do not use\"\n-\n-die() {\n-\techo >&2 \"$@\"\n-\texit 1\n-}\n-\n-usage() {\n-\texec \"$0\" -h\n-}\n-\n-eval \"$(echo \"$OPTIONS_SPEC\" | git rev-parse --parseopt -- \"$@\" || echo exit $?)\"\n-\n-get_repo_base() {\n-\t(\n-\t\tcd \"`/bin/pwd`\" &&\n-\t\tcd \"$1\" || cd \"$1.git\" &&\n-\t\t{\n-\t\t\tcd .git\n-\t\t\tpwd\n-\t\t}\n-\t) 2>/dev/null\n-}\n-\n-if [ -n \"$GIT_SSL_NO_VERIFY\" -o \\\n-\t\"`git config --bool http.sslVerify`\" = false ]; then\n-    curl_extra_args=\"-k\"\n-fi\n-\n-http_fetch () {\n-\t# $1 = Remote, $2 = Local\n-\tcurl -nsfL $curl_extra_args \"$1\" >\"$2\"\n-\tcurl_exit_status=$?\n-\tcase $curl_exit_status in\n-\t126|127) exit ;;\n-\t*)\t return $curl_exit_status ;;\n-\tesac\n-}\n-\n-clone_dumb_http () {\n-\t# $1 - remote, $2 - local\n-\tcd \"$2\" &&\n-\tclone_tmp=\"$GIT_DIR/clone-tmp\" &&\n-\tmkdir -p \"$clone_tmp\" || exit 1\n-\tif [ -n \"$GIT_CURL_FTP_NO_EPSV\" -o \\\n-\t\t\"`git config --bool http.noEPSV`\" = true ]; then\n-\t\tcurl_extra_args=\"${curl_extra_args} --disable-epsv\"\n-\tfi\n-\thttp_fetch \"$1/info/refs\" \"$clone_tmp/refs\" ||\n-\t\tdie \"Cannot get remote repository information.\n-Perhaps git-update-server-info needs to be run there?\"\n-\ttest \"z$quiet\" = z && v=-v || v=\n-\twhile read sha1 refname\n-\tdo\n-\t\tname=`expr \"z$refname\" : 'zrefs/\\(.*\\)'` &&\n-\t\tcase \"$name\" in\n-\t\t*^*)\tcontinue;;\n-\t\tesac\n-\t\tcase \"$bare,$name\" in\n-\t\tyes,* | ,heads/* | ,tags/*) ;;\n-\t\t*)\tcontinue ;;\n-\t\tesac\n-\t\tif test -n \"$use_separate_remote\" &&\n-\t\t   branch_name=`expr \"z$name\" : 'zheads/\\(.*\\)'`\n-\t\tthen\n-\t\t\ttname=\"remotes/$origin/$branch_name\"\n-\t\telse\n-\t\t\ttname=$name\n-\t\tfi\n-\t\tgit-http-fetch $v -a -w \"$tname\" \"$sha1\" \"$1\" || exit 1\n-\tdone <\"$clone_tmp/refs\"\n-\trm -fr \"$clone_tmp\"\n-\thttp_fetch \"$1/HEAD\" \"$GIT_DIR/REMOTE_HEAD\" ||\n-\trm -f \"$GIT_DIR/REMOTE_HEAD\"\n-\tif test -f \"$GIT_DIR/REMOTE_HEAD\"; then\n-\t\thead_sha1=`cat \"$GIT_DIR/REMOTE_HEAD\"`\n-\t\tcase \"$head_sha1\" in\n-\t\t'ref: refs/'*)\n-\t\t\t;;\n-\t\t*)\n-\t\t\tgit-http-fetch $v -a \"$head_sha1\" \"$1\" ||\n-\t\t\trm -f \"$GIT_DIR/REMOTE_HEAD\"\n-\t\t\t;;\n-\t\tesac\n-\tfi\n-}\n-\n-quiet=\n-local=no\n-use_local_hardlink=yes\n-local_shared=no\n-unset template\n-no_checkout=\n-upload_pack=\n-bare=\n-reference=\n-origin=\n-origin_override=\n-use_separate_remote=t\n-depth=\n-no_progress=\n-local_explicitly_asked_for=\n-test -t 1 || no_progress=--no-progress\n-\n-while test $# != 0\n-do\n-\tcase \"$1\" in\n-\t-n|--no-checkout)\n-\t\tno_checkout=yes ;;\n-\t--naked|--bare)\n-\t\tbare=yes ;;\n-\t-l|--local)\n-\t\tlocal_explicitly_asked_for=yes\n-\t\tuse_local_hardlink=yes\n-\t\t;;\n-\t--no-hardlinks)\n-\t\tuse_local_hardlink=no ;;\n-\t-s|--shared)\n-\t\tlocal_shared=yes ;;\n-\t--template)\n-\t\tshift; template=\"--template=$1\" ;;\n-\t-q|--quiet)\n-\t\tquiet=-q ;;\n-\t--use-separate-remote|--no-separate-remote)\n-\t\tdie \"clones are always made with separate-remote layout\" ;;\n-\t--reference)\n-\t\tshift; reference=\"$1\" ;;\n-\t-o|--origin)\n-\t\tshift;\n-\t\tcase \"$1\" in\n-\t\t'')\n-\t\t    usage ;;\n-\t\t*/*)\n-\t\t    die \"'$1' is not suitable for an origin name\"\n-\t\tesac\n-\t\tgit check-ref-format \"heads/$1\" ||\n-\t\t    die \"'$1' is not suitable for a branch name\"\n-\t\ttest -z \"$origin_override\" ||\n-\t\t    die \"Do not give more than one --origin options.\"\n-\t\torigin_override=yes\n-\t\torigin=\"$1\"\n-\t\t;;\n-\t-u|--upload-pack)\n-\t\tshift\n-\t\tupload_pack=\"--upload-pack=$1\" ;;\n-\t--depth)\n-\t\tshift\n-\t\tdepth=\"--depth=$1\" ;;\n-\t--)\n-\t\tshift\n-\t\tbreak ;;\n-\t*)\n-\t\tusage ;;\n-\tesac\n-\tshift\n-done\n-\n-repo=\"$1\"\n-test -n \"$repo\" ||\n-    die 'you must specify a repository to clone.'\n-\n-# --bare implies --no-checkout and --no-separate-remote\n-if test yes = \"$bare\"\n-then\n-\tif test yes = \"$origin_override\"\n-\tthen\n-\t\tdie '--bare and --origin $origin options are incompatible.'\n-\tfi\n-\tno_checkout=yes\n-\tuse_separate_remote=\n-fi\n-\n-if test -z \"$origin\"\n-then\n-\torigin=origin\n-fi\n-\n-# Turn the source into an absolute path if\n-# it is local\n-if base=$(get_repo_base \"$repo\"); then\n-\trepo=\"$base\"\n-\tif test -z \"$depth\"\n-\tthen\n-\t\tlocal=yes\n-\tfi\n-elif test -f \"$repo\"\n-then\n-\tcase \"$repo\" in /*) ;; *) repo=\"$PWD/$repo\" ;; esac\n-fi\n-\n-# Decide the directory name of the new repository\n-if test -n \"$2\"\n-then\n-\tdir=\"$2\"\n-else\n-\t# Derive one from the repository name\n-\t# Try using \"humanish\" part of source repo if user didn't specify one\n-\tif test -f \"$repo\"\n-\tthen\n-\t\t# Cloning from a bundle\n-\t\tdir=$(echo \"$repo\" | sed -e 's|/*\\.bundle$||' -e 's|.*/||g')\n-\telse\n-\t\tdir=$(echo \"$repo\" |\n-\t\t\tsed -e 's|/$||' -e 's|:*/*\\.git$||' -e 's|.*[/:]||g')\n-\tfi\n-fi\n-\n-[ -e \"$dir\" ] && die \"destination directory '$dir' already exists.\"\n-[ yes = \"$bare\" ] && unset GIT_WORK_TREE\n-[ -n \"$GIT_WORK_TREE\" ] && [ -e \"$GIT_WORK_TREE\" ] &&\n-die \"working tree '$GIT_WORK_TREE' already exists.\"\n-D=\n-W=\n-cleanup() {\n-\terr=$?\n-\ttest -z \"$D\" && rm -rf \"$dir\"\n-\ttest -z \"$W\" && test -n \"$GIT_WORK_TREE\" && rm -rf \"$GIT_WORK_TREE\"\n-\tcd ..\n-\ttest -n \"$D\" && rm -rf \"$D\"\n-\ttest -n \"$W\" && rm -rf \"$W\"\n-\texit $err\n-}\n-trap cleanup 0\n-mkdir -p \"$dir\" && D=$(cd \"$dir\" && pwd) || usage\n-test -n \"$GIT_WORK_TREE\" && mkdir -p \"$GIT_WORK_TREE\" &&\n-W=$(cd \"$GIT_WORK_TREE\" && pwd) && GIT_WORK_TREE=\"$W\" && export GIT_WORK_TREE\n-if test yes = \"$bare\" || test -n \"$GIT_WORK_TREE\"; then\n-\tGIT_DIR=\"$D\"\n-else\n-\tGIT_DIR=\"$D/.git\"\n-fi &&\n-export GIT_DIR &&\n-GIT_CONFIG=\"$GIT_DIR/config\" git-init $quiet ${template+\"$template\"} || usage\n-\n-if test -n \"$bare\"\n-then\n-\tGIT_CONFIG=\"$GIT_DIR/config\" git config core.bare true\n-fi\n-\n-if test -n \"$reference\"\n-then\n-\tref_git=\n-\tif test -d \"$reference\"\n-\tthen\n-\t\tif test -d \"$reference/.git/objects\"\n-\t\tthen\n-\t\t\tref_git=\"$reference/.git\"\n-\t\telif test -d \"$reference/objects\"\n-\t\tthen\n-\t\t\tref_git=\"$reference\"\n-\t\tfi\n-\tfi\n-\tif test -n \"$ref_git\"\n-\tthen\n-\t\tref_git=$(cd \"$ref_git\" && pwd)\n-\t\techo \"$ref_git/objects\" >\"$GIT_DIR/objects/info/alternates\"\n-\t\t(\n-\t\t\tGIT_DIR=\"$ref_git\" git for-each-ref \\\n-\t\t\t\t--format='%(objectname) %(*objectname)'\n-\t\t) |\n-\t\twhile read a b\n-\t\tdo\n-\t\t\ttest -z \"$a\" ||\n-\t\t\tgit update-ref \"refs/reference-tmp/$a\" \"$a\"\n-\t\t\ttest -z \"$b\" ||\n-\t\t\tgit update-ref \"refs/reference-tmp/$b\" \"$b\"\n-\t\tdone\n-\telse\n-\t\tdie \"reference repository '$reference' is not a local directory.\"\n-\tfi\n-fi\n-\n-rm -f \"$GIT_DIR/CLONE_HEAD\"\n-\n-# We do local magic only when the user tells us to.\n-case \"$local\" in\n-yes)\n-\t( cd \"$repo/objects\" ) ||\n-\t\tdie \"cannot chdir to local '$repo/objects'.\"\n-\n-\tif test \"$local_shared\" = yes\n-\tthen\n-\t\tmkdir -p \"$GIT_DIR/objects/info\"\n-\t\techo \"$repo/objects\" >>\"$GIT_DIR/objects/info/alternates\"\n-\telse\n-\t\tcpio_quiet_flag=\"\"\n-\t\tcpio --help 2>&1 | grep -- --quiet >/dev/null && \\\n-\t\t\tcpio_quiet_flag=--quiet\n-\t\tl= &&\n-\t\tif test \"$use_local_hardlink\" = yes\n-\t\tthen\n-\t\t\t# See if we can hardlink and drop \"l\" if not.\n-\t\t\tsample_file=$(cd \"$repo\" && \\\n-\t\t\t\t      find objects -type f -print | sed -e 1q)\n-\t\t\t# objects directory should not be empty because\n-\t\t\t# we are cloning!\n-\t\t\ttest -f \"$repo/$sample_file\" ||\n-\t\t\t\tdie \"fatal: cannot clone empty repository\"\n-\t\t\tif ln \"$repo/$sample_file\" \"$GIT_DIR/objects/sample\" 2>/dev/null\n-\t\t\tthen\n-\t\t\t\trm -f \"$GIT_DIR/objects/sample\"\n-\t\t\t\tl=l\n-\t\t\telif test -n \"$local_explicitly_asked_for\"\n-\t\t\tthen\n-\t\t\t\techo >&2 \"Warning: -l asked but cannot hardlink to $repo\"\n-\t\t\tfi\n-\t\tfi &&\n-\t\tcd \"$repo\" &&\n-\t\tfind objects -depth -print | cpio $cpio_quiet_flag -pumd$l \"$GIT_DIR/\" || \\\n-\t\t\texit 1\n-\tfi\n-\tgit-ls-remote \"$repo\" >\"$GIT_DIR/CLONE_HEAD\" || exit 1\n-\t;;\n-*)\n-\tcase \"$repo\" in\n-\trsync://*)\n-\t\tcase \"$depth\" in\n-\t\t\"\") ;;\n-\t\t*) die \"shallow over rsync not supported\" ;;\n-\t\tesac\n-\t\trsync $quiet -av --ignore-existing  \\\n-\t\t\t--exclude info \"$repo/objects/\" \"$GIT_DIR/objects/\" ||\n-\t\texit\n-\t\t# Look at objects/info/alternates for rsync -- http will\n-\t\t# support it natively and git native ones will do it on the\n-\t\t# remote end.  Not having that file is not a crime.\n-\t\trsync -q \"$repo/objects/info/alternates\" \\\n-\t\t\t\"$GIT_DIR/TMP_ALT\" 2>/dev/null ||\n-\t\t\trm -f \"$GIT_DIR/TMP_ALT\"\n-\t\tif test -f \"$GIT_DIR/TMP_ALT\"\n-\t\tthen\n-\t\t    ( cd \"$D\" &&\n-\t\t      . git-parse-remote &&\n-\t\t      resolve_alternates \"$repo\" <\"$GIT_DIR/TMP_ALT\" ) |\n-\t\t    while read alt\n-\t\t    do\n-\t\t\tcase \"$alt\" in 'bad alternate: '*) die \"$alt\";; esac\n-\t\t\tcase \"$quiet\" in\n-\t\t\t'')\techo >&2 \"Getting alternate: $alt\" ;;\n-\t\t\tesac\n-\t\t\trsync $quiet -av --ignore-existing  \\\n-\t\t\t    --exclude info \"$alt\" \"$GIT_DIR/objects\" || exit\n-\t\t    done\n-\t\t    rm -f \"$GIT_DIR/TMP_ALT\"\n-\t\tfi\n-\t\tgit-ls-remote \"$repo\" >\"$GIT_DIR/CLONE_HEAD\" || exit 1\n-\t\t;;\n-\thttps://*|http://*|ftp://*)\n-\t\tcase \"$depth\" in\n-\t\t\"\") ;;\n-\t\t*) die \"shallow over http or ftp not supported\" ;;\n-\t\tesac\n-\t\tif test -z \"@@NO_CURL@@\"\n-\t\tthen\n-\t\t\tclone_dumb_http \"$repo\" \"$D\"\n-\t\telse\n-\t\t\tdie \"http transport not supported, rebuild Git with curl support\"\n-\t\tfi\n-\t\t;;\n-\t*)\n-\t\tif [ -f \"$repo\" ] ; then\n-\t\t\tgit bundle unbundle \"$repo\" > \"$GIT_DIR/CLONE_HEAD\" ||\n-\t\t\tdie \"unbundle from '$repo' failed.\"\n-\t\telse\n-\t\t\tcase \"$upload_pack\" in\n-\t\t\t'') git-fetch-pack --all -k $quiet $depth $no_progress \"$repo\";;\n-\t\t\t*) git-fetch-pack --all -k \\\n-\t\t\t\t$quiet \"$upload_pack\" $depth $no_progress \"$repo\" ;;\n-\t\t\tesac >\"$GIT_DIR/CLONE_HEAD\" ||\n-\t\t\tdie \"fetch-pack from '$repo' failed.\"\n-\t\tfi\n-\t\t;;\n-\tesac\n-\t;;\n-esac\n-test -d \"$GIT_DIR/refs/reference-tmp\" && rm -fr \"$GIT_DIR/refs/reference-tmp\"\n-\n-if test -f \"$GIT_DIR/CLONE_HEAD\"\n-then\n-\t# Read git-fetch-pack -k output and store the remote branches.\n-\tif [ -n \"$use_separate_remote\" ]\n-\tthen\n-\t\tbranch_top=\"remotes/$origin\"\n-\telse\n-\t\tbranch_top=\"heads\"\n-\tfi\n-\ttag_top=\"tags\"\n-\twhile read sha1 name\n-\tdo\n-\t\tcase \"$name\" in\n-\t\t*'^{}')\n-\t\t\tcontinue ;;\n-\t\tHEAD)\n-\t\t\tdestname=\"REMOTE_HEAD\" ;;\n-\t\trefs/heads/*)\n-\t\t\tdestname=\"refs/$branch_top/${name#refs/heads/}\" ;;\n-\t\trefs/tags/*)\n-\t\t\tdestname=\"refs/$tag_top/${name#refs/tags/}\" ;;\n-\t\t*)\n-\t\t\tcontinue ;;\n-\t\tesac\n-\t\tgit update-ref -m \"clone: from $repo\" \"$destname\" \"$sha1\" \"\"\n-\tdone < \"$GIT_DIR/CLONE_HEAD\"\n-fi\n-\n-if test -n \"$W\"; then\n-\tcd \"$W\" || exit\n-else\n-\tcd \"$D\" || exit\n-fi\n-\n-if test -z \"$bare\"\n-then\n-\t# a non-bare repository is always in separate-remote layout\n-\tremote_top=\"refs/remotes/$origin\"\n-\thead_sha1=\n-\ttest ! -r \"$GIT_DIR/REMOTE_HEAD\" || head_sha1=`cat \"$GIT_DIR/REMOTE_HEAD\"`\n-\tcase \"$head_sha1\" in\n-\t'ref: refs/'*)\n-\t\t# Uh-oh, the remote told us (http transport done against\n-\t\t# new style repository with a symref HEAD).\n-\t\t# Ideally we should skip the guesswork but for now\n-\t\t# opt for minimum change.\n-\t\thead_sha1=`expr \"z$head_sha1\" : 'zref: refs/heads/\\(.*\\)'`\n-\t\thead_sha1=`cat \"$GIT_DIR/$remote_top/$head_sha1\"`\n-\t\t;;\n-\tesac\n-\n-\t# The name under $remote_top the remote HEAD seems to point at.\n-\thead_points_at=$(\n-\t\t(\n-\t\t\ttest -f \"$GIT_DIR/$remote_top/master\" && echo \"master\"\n-\t\t\tcd \"$GIT_DIR/$remote_top\" &&\n-\t\t\tfind . -type f -print | sed -e 's/^\\.\\///'\n-\t\t) | (\n-\t\tdone=f\n-\t\twhile read name\n-\t\tdo\n-\t\t\ttest t = $done && continue\n-\t\t\tbranch_tip=`cat \"$GIT_DIR/$remote_top/$name\"`\n-\t\t\tif test \"$head_sha1\" = \"$branch_tip\"\n-\t\t\tthen\n-\t\t\t\techo \"$name\"\n-\t\t\t\tdone=t\n-\t\t\tfi\n-\t\tdone\n-\t\t)\n-\t)\n-\n-\t# Upstream URL\n-\tgit config remote.\"$origin\".url \"$repo\" &&\n-\n-\t# Set up the mappings to track the remote branches.\n-\tgit config remote.\"$origin\".fetch \\\n-\t\t\"+refs/heads/*:$remote_top/*\" '^$' &&\n-\n-\t# Write out remote.$origin config, and update our \"$head_points_at\".\n-\tcase \"$head_points_at\" in\n-\t?*)\n-\t\t# Local default branch\n-\t\tgit symbolic-ref HEAD \"refs/heads/$head_points_at\" &&\n-\n-\t\t# Tracking branch for the primary branch at the remote.\n-\t\tgit update-ref HEAD \"$head_sha1\" &&\n-\n-\t\trm -f \"refs/remotes/$origin/HEAD\"\n-\t\tgit symbolic-ref \"refs/remotes/$origin/HEAD\" \\\n-\t\t\t\"refs/remotes/$origin/$head_points_at\" &&\n-\n-\t\tgit config branch.\"$head_points_at\".remote \"$origin\" &&\n-\t\tgit config branch.\"$head_points_at\".merge \"refs/heads/$head_points_at\"\n-\t\t;;\n-\t'')\n-\t\tif test -z \"$head_sha1\"\n-\t\tthen\n-\t\t\t# Source had nonexistent ref in HEAD\n-\t\t\techo >&2 \"Warning: Remote HEAD refers to nonexistent ref, unable to checkout.\"\n-\t\t\tno_checkout=t\n-\t\telse\n-\t\t\t# Source had detached HEAD pointing nowhere\n-\t\t\tgit update-ref --no-deref HEAD \"$head_sha1\" &&\n-\t\t\trm -f \"refs/remotes/$origin/HEAD\"\n-\t\tfi\n-\t\t;;\n-\tesac\n-\n-\tcase \"$no_checkout\" in\n-\t'')\n-\t\ttest \"z$quiet\" = z -a \"z$no_progress\" = z && v=-v || v=\n-\t\tgit read-tree -m -u $v HEAD HEAD\n-\tesac\n-fi\n-rm -f \"$GIT_DIR/CLONE_HEAD\" \"$GIT_DIR/REMOTE_HEAD\"\n-\n-trap - 0\ndiff --git a/git.c b/git.c\nindex c4e4644..4e7845a 100644\n--- a/git.c\n+++ b/git.c\n@@ -286,6 +286,7 @@ static void handle_internal_command(int argc, const char **argv)\n \t\t{ \"check-attr\", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"cherry\", cmd_cherry, RUN_SETUP },\n \t\t{ \"cherry-pick\", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },\n+\t\t{ \"clone\", cmd_clone },\n \t\t{ \"clean\", cmd_clean, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"commit\", cmd_commit, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"commit-tree\", cmd_commit_tree, RUN_SETUP },\n-- \n1.5.4.3.610.gea6cd"}]}