2008-04-27 17:39:30 +00:00
|
|
|
/*
|
|
|
|
* Builtin "git clone"
|
|
|
|
*
|
|
|
|
* Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>,
|
|
|
|
* 2008 Daniel Barkalow <barkalow@iabervon.org>
|
|
|
|
* Based on git-commit.sh by Junio C Hamano and Linus Torvalds
|
|
|
|
*
|
|
|
|
* Clone a repository into a different directory that does not yet exist.
|
|
|
|
*/
|
|
|
|
|
2019-01-24 08:29:12 +00:00
|
|
|
#define USE_THE_INDEX_COMPATIBILITY_MACROS
|
Fix sparse warnings
Fix warnings from 'make check'.
- These files don't include 'builtin.h' causing sparse to complain that
cmd_* isn't declared:
builtin/clone.c:364, builtin/fetch-pack.c:797,
builtin/fmt-merge-msg.c:34, builtin/hash-object.c:78,
builtin/merge-index.c:69, builtin/merge-recursive.c:22
builtin/merge-tree.c:341, builtin/mktag.c:156, builtin/notes.c:426
builtin/notes.c:822, builtin/pack-redundant.c:596,
builtin/pack-refs.c:10, builtin/patch-id.c:60, builtin/patch-id.c:149,
builtin/remote.c:1512, builtin/remote-ext.c:240,
builtin/remote-fd.c:53, builtin/reset.c:236, builtin/send-pack.c:384,
builtin/unpack-file.c:25, builtin/var.c:75
- These files have symbols which should be marked static since they're
only file scope:
submodule.c:12, diff.c:631, replace_object.c:92, submodule.c:13,
submodule.c:14, trace.c:78, transport.c:195, transport-helper.c:79,
unpack-trees.c:19, url.c:3, url.c:18, url.c:104, url.c:117, url.c:123,
url.c:129, url.c:136, thread-utils.c:21, thread-utils.c:48
- These files redeclare symbols to be different types:
builtin/index-pack.c:210, parse-options.c:564, parse-options.c:571,
usage.c:49, usage.c:58, usage.c:63, usage.c:72
- These files use a literal integer 0 when they really should use a NULL
pointer:
daemon.c:663, fast-import.c:2942, imap-send.c:1072, notes-merge.c:362
While we're in the area, clean up some unused #includes in builtin files
(mostly exec_cmd.h).
Signed-off-by: Stephen Boyd <bebarino@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-22 07:51:05 +00:00
|
|
|
#include "builtin.h"
|
2017-06-14 18:07:36 +00:00
|
|
|
#include "config.h"
|
2014-10-01 10:28:42 +00:00
|
|
|
#include "lockfile.h"
|
2008-04-27 17:39:30 +00:00
|
|
|
#include "parse-options.h"
|
|
|
|
#include "fetch-pack.h"
|
|
|
|
#include "refs.h"
|
2018-05-16 22:57:48 +00:00
|
|
|
#include "refspec.h"
|
2018-05-15 23:42:15 +00:00
|
|
|
#include "object-store.h"
|
2008-04-27 17:39:30 +00:00
|
|
|
#include "tree.h"
|
|
|
|
#include "tree-walk.h"
|
|
|
|
#include "unpack-trees.h"
|
|
|
|
#include "transport.h"
|
|
|
|
#include "strbuf.h"
|
|
|
|
#include "dir.h"
|
2019-07-10 23:59:03 +00:00
|
|
|
#include "dir-iterator.h"
|
|
|
|
#include "iterator.h"
|
chain kill signals for cleanup functions
If a piece of code wanted to do some cleanup before exiting
(e.g., cleaning up a lockfile or a tempfile), our usual
strategy was to install a signal handler that did something
like this:
do_cleanup(); /* actual work */
signal(signo, SIG_DFL); /* restore previous behavior */
raise(signo); /* deliver signal, killing ourselves */
For a single handler, this works fine. However, if we want
to clean up two _different_ things, we run into a problem.
The most recently installed handler will run, but when it
removes itself as a handler, it doesn't put back the first
handler.
This patch introduces sigchain, a tiny library for handling
a stack of signal handlers. You sigchain_push each handler,
and use sigchain_pop to restore whoever was before you in
the stack.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-01-22 06:02:35 +00:00
|
|
|
#include "sigchain.h"
|
2009-03-04 06:29:55 +00:00
|
|
|
#include "branch.h"
|
2009-02-25 08:32:13 +00:00
|
|
|
#include "remote.h"
|
2009-03-03 05:37:51 +00:00
|
|
|
#include "run-command.h"
|
2013-03-25 20:26:27 +00:00
|
|
|
#include "connected.h"
|
2017-08-18 22:20:21 +00:00
|
|
|
#include "packfile.h"
|
2017-12-08 15:58:46 +00:00
|
|
|
#include "list-objects-filter-options.h"
|
2008-04-27 17:39:30 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Overall FIXMEs:
|
|
|
|
* - respect DB_ENVIRONMENT for .git/objects.
|
|
|
|
*
|
|
|
|
* Implementation notes:
|
|
|
|
* - dropping use-separate-remote and no-separate-remote compatibility
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static const char * const builtin_clone_usage[] = {
|
2015-01-13 07:44:47 +00:00
|
|
|
N_("git clone [<options>] [--] <repo> [<dir>]"),
|
2008-04-27 17:39:30 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2012-01-07 14:45:59 +00:00
|
|
|
static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;
|
2017-03-17 22:38:03 +00:00
|
|
|
static int option_local = -1, option_no_hardlinks, option_shared;
|
2017-04-26 23:12:33 +00:00
|
|
|
static int option_no_tags;
|
2016-06-19 20:51:56 +00:00
|
|
|
static int option_shallow_submodules;
|
2016-06-12 10:54:00 +00:00
|
|
|
static int deepen;
|
|
|
|
static char *option_template, *option_depth, *option_since;
|
2008-04-27 17:39:30 +00:00
|
|
|
static char *option_origin = NULL;
|
2009-08-26 19:05:08 +00:00
|
|
|
static char *option_branch = NULL;
|
2016-06-12 10:54:05 +00:00
|
|
|
static struct string_list option_not = STRING_LIST_INIT_NODUP;
|
2011-03-19 15:16:56 +00:00
|
|
|
static const char *real_git_dir;
|
2008-04-27 17:39:30 +00:00
|
|
|
static char *option_upload_pack = "git-upload-pack";
|
2010-02-24 12:50:25 +00:00
|
|
|
static int option_verbosity;
|
2012-02-13 20:17:15 +00:00
|
|
|
static int option_progress = -1;
|
2019-11-21 22:04:35 +00:00
|
|
|
static int option_sparse_checkout;
|
2016-02-03 04:09:14 +00:00
|
|
|
static enum transport_family family;
|
2016-06-13 10:04:20 +00:00
|
|
|
static struct string_list option_config = STRING_LIST_INIT_NODUP;
|
2016-08-15 21:53:25 +00:00
|
|
|
static struct string_list option_required_reference = STRING_LIST_INIT_NODUP;
|
2016-08-15 21:53:26 +00:00
|
|
|
static struct string_list option_optional_reference = STRING_LIST_INIT_NODUP;
|
2014-10-14 19:38:52 +00:00
|
|
|
static int option_dissociate;
|
2016-03-01 02:07:20 +00:00
|
|
|
static int max_jobs = -1;
|
2017-03-17 22:38:03 +00:00
|
|
|
static struct string_list option_recurse_submodules = STRING_LIST_INIT_NODUP;
|
2017-12-08 15:58:46 +00:00
|
|
|
static struct list_objects_filter_options filter_options;
|
2019-04-12 19:51:22 +00:00
|
|
|
static struct string_list server_options = STRING_LIST_INIT_NODUP;
|
2019-05-19 14:26:49 +00:00
|
|
|
static int option_remote_submodules;
|
2017-03-17 22:38:03 +00:00
|
|
|
|
|
|
|
static int recurse_submodules_cb(const struct option *opt,
|
|
|
|
const char *arg, int unset)
|
|
|
|
{
|
|
|
|
if (unset)
|
|
|
|
string_list_clear((struct string_list *)opt->value, 0);
|
|
|
|
else if (arg)
|
|
|
|
string_list_append((struct string_list *)opt->value, arg);
|
|
|
|
else
|
|
|
|
string_list_append((struct string_list *)opt->value,
|
|
|
|
(const char *)opt->defval);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2011-08-23 01:05:15 +00:00
|
|
|
|
2008-04-27 17:39:30 +00:00
|
|
|
static struct option builtin_clone_options[] = {
|
2010-02-24 12:50:25 +00:00
|
|
|
OPT__VERBOSITY(&option_verbosity),
|
2012-02-13 20:17:15 +00:00
|
|
|
OPT_BOOL(0, "progress", &option_progress,
|
2012-08-20 12:32:02 +00:00
|
|
|
N_("force progress reporting")),
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL('n', "no-checkout", &option_no_checkout,
|
|
|
|
N_("don't create a checkout")),
|
2013-08-03 11:51:18 +00:00
|
|
|
OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
|
|
|
|
OPT_HIDDEN_BOOL(0, "naked", &option_bare,
|
|
|
|
N_("create a bare repository")),
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL(0, "mirror", &option_mirror,
|
|
|
|
N_("create a mirror repository (implies bare)")),
|
2012-05-30 11:10:16 +00:00
|
|
|
OPT_BOOL('l', "local", &option_local,
|
2012-08-20 12:32:02 +00:00
|
|
|
N_("to clone from a local repository")),
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL(0, "no-hardlinks", &option_no_hardlinks,
|
2012-08-20 12:32:02 +00:00
|
|
|
N_("don't use local hardlinks, always copy")),
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL('s', "shared", &option_shared,
|
2012-08-20 12:32:02 +00:00
|
|
|
N_("setup as shared repository")),
|
2017-03-17 22:38:03 +00:00
|
|
|
{ OPTION_CALLBACK, 0, "recurse-submodules", &option_recurse_submodules,
|
|
|
|
N_("pathspec"), N_("initialize submodules in the clone"),
|
|
|
|
PARSE_OPT_OPTARG, recurse_submodules_cb, (intptr_t)"." },
|
2020-03-16 20:27:43 +00:00
|
|
|
OPT_ALIAS(0, "recursive", "recurse-submodules"),
|
2016-03-01 02:07:20 +00:00
|
|
|
OPT_INTEGER('j', "jobs", &max_jobs,
|
|
|
|
N_("number of submodules cloned in parallel")),
|
2012-08-20 12:32:02 +00:00
|
|
|
OPT_STRING(0, "template", &option_template, N_("template-directory"),
|
|
|
|
N_("directory from which templates will be used")),
|
2016-08-15 21:53:25 +00:00
|
|
|
OPT_STRING_LIST(0, "reference", &option_required_reference, N_("repo"),
|
2015-05-21 04:15:19 +00:00
|
|
|
N_("reference repository")),
|
2016-08-15 21:53:26 +00:00
|
|
|
OPT_STRING_LIST(0, "reference-if-able", &option_optional_reference,
|
|
|
|
N_("repo"), N_("reference repository")),
|
2015-05-21 04:16:04 +00:00
|
|
|
OPT_BOOL(0, "dissociate", &option_dissociate,
|
|
|
|
N_("use --reference only while cloning")),
|
2012-08-20 12:32:02 +00:00
|
|
|
OPT_STRING('o', "origin", &option_origin, N_("name"),
|
|
|
|
N_("use <name> instead of 'origin' to track upstream")),
|
|
|
|
OPT_STRING('b', "branch", &option_branch, N_("branch"),
|
|
|
|
N_("checkout <branch> instead of the remote's HEAD")),
|
|
|
|
OPT_STRING('u', "upload-pack", &option_upload_pack, N_("path"),
|
|
|
|
N_("path to git-upload-pack on the remote")),
|
|
|
|
OPT_STRING(0, "depth", &option_depth, N_("depth"),
|
|
|
|
N_("create a shallow clone of that depth")),
|
2016-06-12 10:54:00 +00:00
|
|
|
OPT_STRING(0, "shallow-since", &option_since, N_("time"),
|
|
|
|
N_("create a shallow clone since a specific time")),
|
2016-06-12 10:54:05 +00:00
|
|
|
OPT_STRING_LIST(0, "shallow-exclude", &option_not, N_("revision"),
|
2016-12-04 22:03:59 +00:00
|
|
|
N_("deepen history of shallow clone, excluding rev")),
|
2012-01-07 14:45:59 +00:00
|
|
|
OPT_BOOL(0, "single-branch", &option_single_branch,
|
2012-08-20 12:32:02 +00:00
|
|
|
N_("clone only one branch, HEAD or --branch")),
|
2017-04-26 23:12:33 +00:00
|
|
|
OPT_BOOL(0, "no-tags", &option_no_tags,
|
|
|
|
N_("don't clone any tags, and make later fetches not to follow them")),
|
2016-04-26 01:12:27 +00:00
|
|
|
OPT_BOOL(0, "shallow-submodules", &option_shallow_submodules,
|
|
|
|
N_("any cloned submodules will be shallow")),
|
2012-08-20 12:32:02 +00:00
|
|
|
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
|
|
|
|
N_("separate git dir from working tree")),
|
|
|
|
OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
|
|
|
|
N_("set config inside the new repository")),
|
2019-04-12 19:51:22 +00:00
|
|
|
OPT_STRING_LIST(0, "server-option", &server_options,
|
|
|
|
N_("server-specific"), N_("option to transmit")),
|
2016-02-03 04:09:14 +00:00
|
|
|
OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
|
|
|
|
TRANSPORT_FAMILY_IPV4),
|
|
|
|
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
|
|
|
|
TRANSPORT_FAMILY_IPV6),
|
2017-12-08 15:58:46 +00:00
|
|
|
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
|
2019-05-19 14:26:49 +00:00
|
|
|
OPT_BOOL(0, "remote-submodules", &option_remote_submodules,
|
|
|
|
N_("any cloned submodules will use their remote-tracking branch")),
|
2019-11-21 22:04:35 +00:00
|
|
|
OPT_BOOL(0, "sparse", &option_sparse_checkout,
|
|
|
|
N_("initialize sparse-checkout file to include only files at root")),
|
2008-04-27 17:39:30 +00:00
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
2015-08-10 09:37:55 +00:00
|
|
|
static const char *get_repo_path_1(struct strbuf *path, int *is_bundle)
|
2008-04-27 17:39:30 +00:00
|
|
|
{
|
standardize and improve lookup rules for external local repos
When you specify a local repository on the command line of
clone, ls-remote, upload-pack, receive-pack, or upload-archive,
or in a request to git-daemon, we perform a little bit of
lookup magic, doing things like looking in working trees for
.git directories and appending ".git" for bare repos.
For clone, this magic happens in get_repo_path. For
everything else, it happens in enter_repo. In both cases,
there are some ambiguous or confusing cases that aren't
handled well, and there is one case that is not handled the
same by both methods.
This patch tries to provide (and test!) standard, sensible
lookup rules for both code paths. The intended changes are:
1. When looking up "foo", we have always preferred
a working tree "foo" (containing "foo/.git" over the
bare "foo.git". But we did not prefer a bare "foo" over
"foo.git". With this patch, we do so.
2. We would select directories that existed but didn't
actually look like git repositories. With this patch,
we make sure a selected directory looks like a git
repo. Not only is this more sensible in general, but it
will help anybody who is negatively affected by change
(1) negatively (e.g., if they had "foo.git" next to its
separate work tree "foo", and expect to keep finding
"foo.git" when they reference "foo").
3. The enter_repo code path would, given "foo", look for
"foo.git/.git" (i.e., do the ".git" append magic even
for a repo with working tree). The clone code path did
not; with this patch, they now behave the same.
In the unlikely case of a working tree overlaying a bare
repo (i.e., a ".git" directory _inside_ a bare repo), we
continue to treat it as a working tree (prefering the
"inner" .git over the bare repo). This is mainly because the
combination seems nonsensical, and I'd rather stick with
existing behavior on the off chance that somebody is relying
on it.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-02 21:59:13 +00:00
|
|
|
static char *suffix[] = { "/.git", "", ".git/.git", ".git" };
|
2008-04-27 17:39:30 +00:00
|
|
|
static char *bundle_suffix[] = { ".bundle", "" };
|
2015-08-10 09:37:55 +00:00
|
|
|
size_t baselen = path->len;
|
2008-04-27 17:39:30 +00:00
|
|
|
struct stat st;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(suffix); i++) {
|
2015-08-10 09:37:55 +00:00
|
|
|
strbuf_setlen(path, baselen);
|
|
|
|
strbuf_addstr(path, suffix[i]);
|
|
|
|
if (stat(path->buf, &st))
|
2011-08-21 11:58:09 +00:00
|
|
|
continue;
|
2015-08-10 09:37:55 +00:00
|
|
|
if (S_ISDIR(st.st_mode) && is_git_directory(path->buf)) {
|
2008-04-27 17:39:30 +00:00
|
|
|
*is_bundle = 0;
|
2015-08-10 09:37:55 +00:00
|
|
|
return path->buf;
|
2011-08-21 11:58:09 +00:00
|
|
|
} else if (S_ISREG(st.st_mode) && st.st_size > 8) {
|
|
|
|
/* Is it a "gitfile"? */
|
|
|
|
char signature[8];
|
2015-08-10 09:37:55 +00:00
|
|
|
const char *dst;
|
|
|
|
int len, fd = open(path->buf, O_RDONLY);
|
2011-08-21 11:58:09 +00:00
|
|
|
if (fd < 0)
|
|
|
|
continue;
|
|
|
|
len = read_in_full(fd, signature, 8);
|
|
|
|
close(fd);
|
|
|
|
if (len != 8 || strncmp(signature, "gitdir: ", 8))
|
|
|
|
continue;
|
2015-08-10 09:37:55 +00:00
|
|
|
dst = read_gitfile(path->buf);
|
|
|
|
if (dst) {
|
2011-08-21 11:58:09 +00:00
|
|
|
*is_bundle = 0;
|
2015-08-10 09:37:55 +00:00
|
|
|
return dst;
|
2011-08-21 11:58:09 +00:00
|
|
|
}
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(bundle_suffix); i++) {
|
2015-08-10 09:37:55 +00:00
|
|
|
strbuf_setlen(path, baselen);
|
|
|
|
strbuf_addstr(path, bundle_suffix[i]);
|
|
|
|
if (!stat(path->buf, &st) && S_ISREG(st.st_mode)) {
|
2008-04-27 17:39:30 +00:00
|
|
|
*is_bundle = 1;
|
2015-08-10 09:37:55 +00:00
|
|
|
return path->buf;
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-08-10 09:37:55 +00:00
|
|
|
static char *get_repo_path(const char *repo, int *is_bundle)
|
|
|
|
{
|
|
|
|
struct strbuf path = STRBUF_INIT;
|
|
|
|
const char *raw;
|
|
|
|
char *canon;
|
|
|
|
|
|
|
|
strbuf_addstr(&path, repo);
|
|
|
|
raw = get_repo_path_1(&path, is_bundle);
|
2017-01-26 17:54:23 +00:00
|
|
|
canon = raw ? absolute_pathdup(raw) : NULL;
|
2015-08-10 09:37:55 +00:00
|
|
|
strbuf_release(&path);
|
|
|
|
return canon;
|
|
|
|
}
|
|
|
|
|
2008-08-01 14:01:36 +00:00
|
|
|
static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
|
2008-04-27 17:39:30 +00:00
|
|
|
{
|
2015-08-10 15:48:23 +00:00
|
|
|
const char *end = repo + strlen(repo), *start, *ptr;
|
2015-07-09 18:24:08 +00:00
|
|
|
size_t len;
|
2009-05-13 16:32:06 +00:00
|
|
|
char *dir;
|
2008-07-19 09:32:45 +00:00
|
|
|
|
2015-08-10 15:48:23 +00:00
|
|
|
/*
|
|
|
|
* Skip scheme.
|
|
|
|
*/
|
|
|
|
start = strstr(repo, "://");
|
|
|
|
if (start == NULL)
|
|
|
|
start = repo;
|
|
|
|
else
|
|
|
|
start += 3;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip authentication data. The stripping does happen
|
|
|
|
* greedily, such that we strip up to the last '@' inside
|
|
|
|
* the host part.
|
|
|
|
*/
|
|
|
|
for (ptr = start; ptr < end && !is_dir_sep(*ptr); ptr++) {
|
|
|
|
if (*ptr == '@')
|
|
|
|
start = ptr + 1;
|
|
|
|
}
|
|
|
|
|
2008-07-19 09:32:45 +00:00
|
|
|
/*
|
2009-05-13 16:32:06 +00:00
|
|
|
* Strip trailing spaces, slashes and /.git
|
2008-07-19 09:32:45 +00:00
|
|
|
*/
|
2015-08-10 15:48:23 +00:00
|
|
|
while (start < end && (is_dir_sep(end[-1]) || isspace(end[-1])))
|
2008-07-19 09:32:45 +00:00
|
|
|
end--;
|
2015-08-10 15:48:23 +00:00
|
|
|
if (end - start > 5 && is_dir_sep(end[-5]) &&
|
2008-07-19 09:32:45 +00:00
|
|
|
!strncmp(end - 4, ".git", 4)) {
|
|
|
|
end -= 5;
|
2015-08-10 15:48:23 +00:00
|
|
|
while (start < end && is_dir_sep(end[-1]))
|
2008-07-19 09:32:45 +00:00
|
|
|
end--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2015-08-10 15:48:24 +00:00
|
|
|
* Strip trailing port number if we've got only a
|
|
|
|
* hostname (that is, there is no dir separator but a
|
|
|
|
* colon). This check is required such that we do not
|
|
|
|
* strip URI's like '/foo/bar:2222.git', which should
|
|
|
|
* result in a dir '2222' being guessed due to backwards
|
|
|
|
* compatibility.
|
|
|
|
*/
|
|
|
|
if (memchr(start, '/', end - start) == NULL
|
|
|
|
&& memchr(start, ':', end - start) != NULL) {
|
|
|
|
ptr = end;
|
|
|
|
while (start < ptr && isdigit(ptr[-1]) && ptr[-1] != ':')
|
|
|
|
ptr--;
|
|
|
|
if (start < ptr && ptr[-1] == ':')
|
|
|
|
end = ptr - 1;
|
|
|
|
}
|
|
|
|
|
2008-07-19 09:32:45 +00:00
|
|
|
/*
|
2015-08-10 15:48:23 +00:00
|
|
|
* Find last component. To remain backwards compatible we
|
|
|
|
* also regard colons as path separators, such that
|
|
|
|
* cloning a repository 'foo:bar.git' would result in a
|
|
|
|
* directory 'bar' being guessed.
|
2008-07-19 09:32:45 +00:00
|
|
|
*/
|
2015-08-10 15:48:23 +00:00
|
|
|
ptr = end;
|
|
|
|
while (start < ptr && !is_dir_sep(ptr[-1]) && ptr[-1] != ':')
|
|
|
|
ptr--;
|
|
|
|
start = ptr;
|
2008-07-19 09:32:45 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Strip .{bundle,git}.
|
|
|
|
*/
|
clone: use computed length in guess_dir_name
Commit 7e837c6 (clone: simplify string handling in
guess_dir_name(), 2015-07-09) changed clone to use
strip_suffix instead of hand-rolled pointer manipulation.
However, strip_suffix will strip from the end of a
NUL-terminated string, and we may have already stripped some
characters (like directory separators, or "/.git"). This
leads to commands like:
git clone host:foo.git/
failing to strip the ".git".
We must instead convert our pointer arithmetic into a
computed length and feed that to strip_suffix_mem, which will
then reduce the length further for us.
It would be nicer if we could drop the pointer manipulation
entirely, and just continually strip using strip_suffix. But
that doesn't quite work for two reasons:
1. The early suffixes we're stripping are not constant; we
need to look for is_dir_sep, which could be one of
several characters.
2. Mid-way through the stripping we compute the pointer
"start", which shows us the beginning of the pathname.
Which really give us two lengths to work with: the
offset from the start of the string, and from the start
of the path. By using pointers for the early part, we
can just compute the length from "start" when we need
it.
Signed-off-by: Jeff King <peff@peff.net>
Acked-by: Sebastian Schuberth <sschuberth@gmail.com>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-10 15:48:22 +00:00
|
|
|
len = end - start;
|
|
|
|
strip_suffix_mem(start, &len, is_bundle ? ".bundle" : ".git");
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2015-08-10 15:48:25 +00:00
|
|
|
if (!len || (len == 1 && *start == '/'))
|
2016-02-27 06:41:55 +00:00
|
|
|
die(_("No directory name could be guessed.\n"
|
|
|
|
"Please specify a directory on the command line"));
|
2015-08-10 15:48:25 +00:00
|
|
|
|
2015-07-09 18:24:08 +00:00
|
|
|
if (is_bare)
|
|
|
|
dir = xstrfmt("%.*s.git", (int)len, start);
|
|
|
|
else
|
|
|
|
dir = xstrndup(start, len);
|
2009-05-13 16:32:06 +00:00
|
|
|
/*
|
|
|
|
* Replace sequences of 'control' characters and whitespace
|
|
|
|
* with one ascii space, remove leading and trailing spaces.
|
|
|
|
*/
|
|
|
|
if (*dir) {
|
|
|
|
char *out = dir;
|
|
|
|
int prev_space = 1 /* strip leading whitespace */;
|
|
|
|
for (end = dir; *end; ++end) {
|
|
|
|
char ch = *end;
|
|
|
|
if ((unsigned char)ch < '\x20')
|
|
|
|
ch = '\x20';
|
|
|
|
if (isspace(ch)) {
|
|
|
|
if (prev_space)
|
|
|
|
continue;
|
|
|
|
prev_space = 1;
|
|
|
|
} else
|
|
|
|
prev_space = 0;
|
|
|
|
*out++ = ch;
|
|
|
|
}
|
|
|
|
*out = '\0';
|
|
|
|
if (out > dir && prev_space)
|
|
|
|
out[-1] = '\0';
|
2008-08-01 14:01:36 +00:00
|
|
|
}
|
2009-05-13 16:32:06 +00:00
|
|
|
return dir;
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|
|
|
|
|
2008-09-03 18:55:55 +00:00
|
|
|
static void strip_trailing_slashes(char *dir)
|
|
|
|
{
|
|
|
|
char *end = dir + strlen(dir);
|
|
|
|
|
|
|
|
while (dir < end - 1 && is_dir_sep(end[-1]))
|
|
|
|
end--;
|
|
|
|
*end = '\0';
|
|
|
|
}
|
|
|
|
|
2011-08-23 01:05:15 +00:00
|
|
|
static int add_one_reference(struct string_list_item *item, void *cb_data)
|
2008-04-27 17:39:30 +00:00
|
|
|
{
|
2016-08-15 21:53:24 +00:00
|
|
|
struct strbuf err = STRBUF_INIT;
|
2016-08-15 21:53:26 +00:00
|
|
|
int *required = cb_data;
|
2016-08-15 21:53:24 +00:00
|
|
|
char *ref_git = compute_alternate_path(item->string, &err);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2016-08-15 21:53:26 +00:00
|
|
|
if (!ref_git) {
|
|
|
|
if (*required)
|
|
|
|
die("%s", err.buf);
|
|
|
|
else
|
|
|
|
fprintf(stderr,
|
|
|
|
_("info: Could not add alternate for '%s': %s\n"),
|
|
|
|
item->string, err.buf);
|
|
|
|
} else {
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
strbuf_addf(&sb, "%s/objects", ref_git);
|
|
|
|
add_to_alternates_file(sb.buf);
|
|
|
|
strbuf_release(&sb);
|
|
|
|
}
|
2013-12-05 13:02:31 +00:00
|
|
|
|
2016-08-15 21:53:24 +00:00
|
|
|
strbuf_release(&err);
|
2016-08-15 21:53:26 +00:00
|
|
|
free(ref_git);
|
2011-08-23 01:05:15 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2011-08-23 01:05:15 +00:00
|
|
|
static void setup_reference(void)
|
|
|
|
{
|
2016-08-15 21:53:26 +00:00
|
|
|
int required = 1;
|
|
|
|
for_each_string_list(&option_required_reference,
|
|
|
|
add_one_reference, &required);
|
|
|
|
required = 0;
|
|
|
|
for_each_string_list(&option_optional_reference,
|
|
|
|
add_one_reference, &required);
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|
|
|
|
|
2019-05-09 21:29:22 +00:00
|
|
|
static void copy_alternates(struct strbuf *src, const char *src_repo)
|
2011-08-23 01:05:16 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Read from the source objects/info/alternates file
|
|
|
|
* and copy the entries to corresponding file in the
|
|
|
|
* destination repository with add_to_alternates_file().
|
|
|
|
* Both src and dst have "$path/objects/info/alternates".
|
|
|
|
*
|
|
|
|
* Instead of copying bit-for-bit from the original,
|
|
|
|
* we need to append to existing one so that the already
|
|
|
|
* created entry via "clone -s" is not lost, and also
|
|
|
|
* to turn entries with paths relative to the original
|
|
|
|
* absolute, so that they can be used in the new repository.
|
|
|
|
*/
|
2017-05-03 10:16:47 +00:00
|
|
|
FILE *in = xfopen(src->buf, "r");
|
2011-08-23 01:05:16 +00:00
|
|
|
struct strbuf line = STRBUF_INIT;
|
|
|
|
|
2015-10-28 20:29:24 +00:00
|
|
|
while (strbuf_getline(&line, in) != EOF) {
|
2014-11-30 08:24:27 +00:00
|
|
|
char *abs_path;
|
2011-08-23 01:05:16 +00:00
|
|
|
if (!line.len || line.buf[0] == '#')
|
|
|
|
continue;
|
|
|
|
if (is_absolute_path(line.buf)) {
|
|
|
|
add_to_alternates_file(line.buf);
|
|
|
|
continue;
|
|
|
|
}
|
2014-11-30 08:24:27 +00:00
|
|
|
abs_path = mkpathdup("%s/objects/%s", src_repo, line.buf);
|
clone: detect errors in normalize_path_copy
When we are copying the alternates from the source
repository, if we find a relative path that is too deep for
the source (e.g., "../../../objects" from "/repo.git/objects"),
then normalize_path_copy will report an error and leave
trash in the buffer, which we will add to our new alternates
file. Instead, let's detect the error, print a warning, and
skip copying that alternate.
There's no need to die. The relative path is probably just
broken cruft in the source repo. If it turns out to have
been important for accessing some objects, we rely on other
parts of the clone to detect that, just as they would with a
missing object in the source repo itself (though note that
clones with "-s" are inherently local, which may do fewer
object-quality checks in the first place).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-10-05 14:29:29 +00:00
|
|
|
if (!normalize_path_copy(abs_path, abs_path))
|
|
|
|
add_to_alternates_file(abs_path);
|
|
|
|
else
|
|
|
|
warning("skipping invalid relative alternate: %s/%s",
|
|
|
|
src_repo, line.buf);
|
2014-11-30 08:24:27 +00:00
|
|
|
free(abs_path);
|
2011-08-23 01:05:16 +00:00
|
|
|
}
|
|
|
|
strbuf_release(&line);
|
|
|
|
fclose(in);
|
|
|
|
}
|
|
|
|
|
2019-07-10 23:59:02 +00:00
|
|
|
static void mkdir_if_missing(const char *pathname, mode_t mode)
|
|
|
|
{
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
if (!mkdir(pathname, mode))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (errno != EEXIST)
|
|
|
|
die_errno(_("failed to create directory '%s'"), pathname);
|
|
|
|
else if (stat(pathname, &st))
|
|
|
|
die_errno(_("failed to stat '%s'"), pathname);
|
|
|
|
else if (!S_ISDIR(st.st_mode))
|
|
|
|
die(_("%s exists and is not a directory"), pathname);
|
|
|
|
}
|
|
|
|
|
2011-08-23 01:05:16 +00:00
|
|
|
static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
|
2019-07-10 23:59:03 +00:00
|
|
|
const char *src_repo)
|
2008-04-27 17:39:30 +00:00
|
|
|
{
|
|
|
|
int src_len, dest_len;
|
2019-07-10 23:59:03 +00:00
|
|
|
struct dir_iterator *iter;
|
|
|
|
int iter_status;
|
|
|
|
unsigned int flags;
|
2020-03-10 13:11:22 +00:00
|
|
|
struct strbuf realpath = STRBUF_INIT;
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2019-07-10 23:59:02 +00:00
|
|
|
mkdir_if_missing(dest->buf, 0777);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2019-07-10 23:59:03 +00:00
|
|
|
flags = DIR_ITERATOR_PEDANTIC | DIR_ITERATOR_FOLLOW_SYMLINKS;
|
|
|
|
iter = dir_iterator_begin(src->buf, flags);
|
|
|
|
|
|
|
|
if (!iter)
|
|
|
|
die_errno(_("failed to start iterator over '%s'"), src->buf);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2008-11-21 00:45:00 +00:00
|
|
|
strbuf_addch(src, '/');
|
|
|
|
src_len = src->len;
|
|
|
|
strbuf_addch(dest, '/');
|
|
|
|
dest_len = dest->len;
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2019-07-10 23:59:03 +00:00
|
|
|
while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
|
2008-11-21 00:45:00 +00:00
|
|
|
strbuf_setlen(src, src_len);
|
2019-07-10 23:59:03 +00:00
|
|
|
strbuf_addstr(src, iter->relative_path);
|
2008-11-21 00:45:00 +00:00
|
|
|
strbuf_setlen(dest, dest_len);
|
2019-07-10 23:59:03 +00:00
|
|
|
strbuf_addstr(dest, iter->relative_path);
|
|
|
|
|
|
|
|
if (S_ISDIR(iter->st.st_mode)) {
|
|
|
|
mkdir_if_missing(dest->buf, 0777);
|
2011-08-23 01:05:16 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Files that cannot be copied bit-for-bit... */
|
2019-07-10 23:59:04 +00:00
|
|
|
if (!fspathcmp(iter->relative_path, "info/alternates")) {
|
2019-05-09 21:29:22 +00:00
|
|
|
copy_alternates(src, src_repo);
|
2008-04-27 17:39:30 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-11-21 00:45:00 +00:00
|
|
|
if (unlink(dest->buf) && errno != ENOENT)
|
2011-02-22 23:41:26 +00:00
|
|
|
die_errno(_("failed to unlink '%s'"), dest->buf);
|
2008-05-20 18:15:14 +00:00
|
|
|
if (!option_no_hardlinks) {
|
2020-03-10 13:11:22 +00:00
|
|
|
strbuf_realpath(&realpath, src->buf, 1);
|
|
|
|
if (!link(realpath.buf, dest->buf))
|
2008-05-20 18:15:14 +00:00
|
|
|
continue;
|
2012-05-30 11:10:16 +00:00
|
|
|
if (option_local > 0)
|
2011-02-22 23:41:26 +00:00
|
|
|
die_errno(_("failed to create link '%s'"), dest->buf);
|
2008-05-20 18:15:14 +00:00
|
|
|
option_no_hardlinks = 1;
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|
2009-09-12 09:03:48 +00:00
|
|
|
if (copy_file_with_time(dest->buf, src->buf, 0666))
|
2011-02-22 23:41:26 +00:00
|
|
|
die_errno(_("failed to copy file to '%s'"), dest->buf);
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|
2019-07-10 23:59:03 +00:00
|
|
|
|
|
|
|
if (iter_status != ITER_DONE) {
|
|
|
|
strbuf_setlen(src, src_len);
|
|
|
|
die(_("failed to iterate over '%s'"), src->buf);
|
|
|
|
}
|
2020-03-10 13:11:22 +00:00
|
|
|
|
|
|
|
strbuf_release(&realpath);
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|
|
|
|
|
2012-01-16 09:46:12 +00:00
|
|
|
static void clone_local(const char *src_repo, const char *dest_repo)
|
2008-04-27 17:39:30 +00:00
|
|
|
{
|
2011-08-23 01:05:16 +00:00
|
|
|
if (option_shared) {
|
|
|
|
struct strbuf alt = STRBUF_INIT;
|
2017-12-11 23:16:12 +00:00
|
|
|
get_common_dir(&alt, src_repo);
|
|
|
|
strbuf_addstr(&alt, "/objects");
|
2011-08-23 01:05:16 +00:00
|
|
|
add_to_alternates_file(alt.buf);
|
|
|
|
strbuf_release(&alt);
|
|
|
|
} else {
|
|
|
|
struct strbuf src = STRBUF_INIT;
|
|
|
|
struct strbuf dest = STRBUF_INIT;
|
2015-09-28 13:06:15 +00:00
|
|
|
get_common_dir(&src, src_repo);
|
|
|
|
get_common_dir(&dest, dest_repo);
|
|
|
|
strbuf_addstr(&src, "/objects");
|
|
|
|
strbuf_addstr(&dest, "/objects");
|
2019-07-10 23:59:03 +00:00
|
|
|
copy_or_link_directory(&src, &dest, src_repo);
|
2008-11-21 00:45:00 +00:00
|
|
|
strbuf_release(&src);
|
|
|
|
strbuf_release(&dest);
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|
|
|
|
|
2010-04-23 12:37:22 +00:00
|
|
|
if (0 <= option_verbosity)
|
2013-09-18 20:05:13 +00:00
|
|
|
fprintf(stderr, _("done.\n"));
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const char *junk_work_tree;
|
2018-01-02 21:11:39 +00:00
|
|
|
static int junk_work_tree_flags;
|
2008-04-27 17:39:30 +00:00
|
|
|
static const char *junk_git_dir;
|
2018-01-02 21:11:39 +00:00
|
|
|
static int junk_git_dir_flags;
|
2013-04-27 18:39:04 +00:00
|
|
|
static enum {
|
2013-03-26 22:22:09 +00:00
|
|
|
JUNK_LEAVE_NONE,
|
|
|
|
JUNK_LEAVE_REPO,
|
|
|
|
JUNK_LEAVE_ALL
|
|
|
|
} junk_mode = JUNK_LEAVE_NONE;
|
|
|
|
|
|
|
|
static const char junk_leave_repo_msg[] =
|
|
|
|
N_("Clone succeeded, but checkout failed.\n"
|
|
|
|
"You can inspect what was checked out with 'git status'\n"
|
2019-04-25 09:45:58 +00:00
|
|
|
"and retry with 'git restore --source=HEAD :/'\n");
|
2008-04-27 17:39:30 +00:00
|
|
|
|
|
|
|
static void remove_junk(void)
|
|
|
|
{
|
2008-10-09 19:12:12 +00:00
|
|
|
struct strbuf sb = STRBUF_INIT;
|
2013-03-26 22:22:09 +00:00
|
|
|
|
|
|
|
switch (junk_mode) {
|
|
|
|
case JUNK_LEAVE_REPO:
|
|
|
|
warning("%s", _(junk_leave_repo_msg));
|
|
|
|
/* fall-through */
|
|
|
|
case JUNK_LEAVE_ALL:
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
/* proceed to removal */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-04-27 17:39:30 +00:00
|
|
|
if (junk_git_dir) {
|
|
|
|
strbuf_addstr(&sb, junk_git_dir);
|
2018-01-02 21:11:39 +00:00
|
|
|
remove_dir_recursively(&sb, junk_git_dir_flags);
|
2008-04-27 17:39:30 +00:00
|
|
|
strbuf_reset(&sb);
|
|
|
|
}
|
|
|
|
if (junk_work_tree) {
|
|
|
|
strbuf_addstr(&sb, junk_work_tree);
|
2018-01-02 21:11:39 +00:00
|
|
|
remove_dir_recursively(&sb, junk_work_tree_flags);
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|
2017-08-30 17:49:37 +00:00
|
|
|
strbuf_release(&sb);
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void remove_junk_on_signal(int signo)
|
|
|
|
{
|
|
|
|
remove_junk();
|
chain kill signals for cleanup functions
If a piece of code wanted to do some cleanup before exiting
(e.g., cleaning up a lockfile or a tempfile), our usual
strategy was to install a signal handler that did something
like this:
do_cleanup(); /* actual work */
signal(signo, SIG_DFL); /* restore previous behavior */
raise(signo); /* deliver signal, killing ourselves */
For a single handler, this works fine. However, if we want
to clean up two _different_ things, we run into a problem.
The most recently installed handler will run, but when it
removes itself as a handler, it doesn't put back the first
handler.
This patch introduces sigchain, a tiny library for handling
a stack of signal handlers. You sigchain_push each handler,
and use sigchain_pop to restore whoever was before you in
the stack.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-01-22 06:02:35 +00:00
|
|
|
sigchain_pop(signo);
|
2008-04-27 17:39:30 +00:00
|
|
|
raise(signo);
|
|
|
|
}
|
|
|
|
|
2012-01-16 09:46:13 +00:00
|
|
|
static struct ref *find_remote_branch(const struct ref *refs, const char *branch)
|
|
|
|
{
|
|
|
|
struct ref *ref;
|
|
|
|
struct strbuf head = STRBUF_INIT;
|
|
|
|
strbuf_addstr(&head, "refs/heads/");
|
|
|
|
strbuf_addstr(&head, branch);
|
|
|
|
ref = find_ref_by_name(refs, head.buf);
|
|
|
|
strbuf_release(&head);
|
2012-01-16 09:46:15 +00:00
|
|
|
|
|
|
|
if (ref)
|
|
|
|
return ref;
|
|
|
|
|
|
|
|
strbuf_addstr(&head, "refs/tags/");
|
|
|
|
strbuf_addstr(&head, branch);
|
|
|
|
ref = find_ref_by_name(refs, head.buf);
|
|
|
|
strbuf_release(&head);
|
|
|
|
|
2012-01-16 09:46:13 +00:00
|
|
|
return ref;
|
|
|
|
}
|
|
|
|
|
2009-09-26 03:54:42 +00:00
|
|
|
static struct ref *wanted_peer_refs(const struct ref *refs,
|
clone: respect additional configured fetch refspecs during initial fetch
The initial fetch during a clone doesn't transfer refs matching
additional fetch refspecs given on the command line as configuration
variables, e.g. '-c remote.origin.fetch=<refspec>'. This contradicts
the documentation stating that configuration variables specified via
'git clone -c <key>=<value> ...' "take effect immediately after the
repository is initialized, but before the remote history is fetched"
and the given example specifically mentions "adding additional fetch
refspecs to the origin remote". Furthermore, one-shot configuration
variables specified via 'git -c <key>=<value> clone ...', though not
written to the newly created repository's config file, live during the
lifetime of the 'clone' command, including the initial fetch. All
this implies that any fetch refspecs specified this way should already
be taken into account during the initial fetch.
The reason for this is that the initial fetch is not a fully fledged
'git fetch' but a bunch of direct calls into the fetch/transport
machinery with clone's own refs-to-refspec matching logic, which
bypasses parts of 'git fetch' processing configured fetch refspecs.
This logic only considers a single default refspec, potentially
influenced by options like '--single-branch' and '--mirror'. The
configured refspecs are, however, already read and parsed properly
when clone calls remote.c:remote_get(), but it never looks at the
parsed refspecs in the resulting 'struct remote'.
Modify clone to take the remote's configured fetch refspecs into
account to retrieve all matching refs during the initial fetch. Note
that we have to explicitly add the default fetch refspec to the
remote's refspecs, because at that point the remote only includes the
fetch refspecs specified on the command line.
Add tests to check that refspecs given both via 'git clone -c ...' and
'git -c ... clone' retrieve all refs matching either the default or
the additional refspecs, and that it works even when the user
specifies an alternative remote name via '--origin=<name>'.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Reviewed-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-14 10:46:19 +00:00
|
|
|
struct refspec *refspec)
|
2008-04-27 17:39:30 +00:00
|
|
|
{
|
clone: always fetch remote HEAD
In most cases, fetching the remote HEAD explicitly is
unnecessary. It's just a symref pointing to a branch which
we are already fetching, so we will already ask for its sha1.
However, if the remote has a detached HEAD, things are less
certain. We do not ask for HEAD's sha1, but we do try to
write it into a local detached HEAD. In most cases this is
fine, as the remote HEAD is pointing to some part of the
history graph that we will fetch via the refs.
But if the remote HEAD points to an "orphan" commit (one
which was is not an ancestor of any refs), then we will not
have the object, and update_ref will complain when we try to
write the detached HEAD, aborting the whole clone.
This patch makes clone always explicitly ask the remote for
the sha1 of its HEAD commit. In the non-detached case, this
is a no-op, as we were going to ask for that sha1 anyway. In
the regular detached case, this will add an extra "want" to
the protocol negotiation, but will not change the history
that gets sent. And in the detached orphan case, we will
fetch the orphaned history so that we can write it into our
local detached HEAD.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-07 23:03:22 +00:00
|
|
|
struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD"));
|
|
|
|
struct ref *local_refs = head;
|
|
|
|
struct ref **tail = head ? &head->next : &local_refs;
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2012-01-07 14:45:59 +00:00
|
|
|
if (option_single_branch) {
|
|
|
|
struct ref *remote_head = NULL;
|
|
|
|
|
|
|
|
if (!option_branch)
|
|
|
|
remote_head = guess_remote_head(head, refs, 0);
|
2012-06-22 09:35:47 +00:00
|
|
|
else {
|
|
|
|
local_refs = NULL;
|
|
|
|
tail = &local_refs;
|
|
|
|
remote_head = copy_ref(find_remote_branch(refs, option_branch));
|
|
|
|
}
|
2012-01-07 14:45:59 +00:00
|
|
|
|
|
|
|
if (!remote_head && option_branch)
|
|
|
|
warning(_("Could not find remote branch %s to clone."),
|
|
|
|
option_branch);
|
2012-01-16 09:46:15 +00:00
|
|
|
else {
|
clone: respect additional configured fetch refspecs during initial fetch
The initial fetch during a clone doesn't transfer refs matching
additional fetch refspecs given on the command line as configuration
variables, e.g. '-c remote.origin.fetch=<refspec>'. This contradicts
the documentation stating that configuration variables specified via
'git clone -c <key>=<value> ...' "take effect immediately after the
repository is initialized, but before the remote history is fetched"
and the given example specifically mentions "adding additional fetch
refspecs to the origin remote". Furthermore, one-shot configuration
variables specified via 'git -c <key>=<value> clone ...', though not
written to the newly created repository's config file, live during the
lifetime of the 'clone' command, including the initial fetch. All
this implies that any fetch refspecs specified this way should already
be taken into account during the initial fetch.
The reason for this is that the initial fetch is not a fully fledged
'git fetch' but a bunch of direct calls into the fetch/transport
machinery with clone's own refs-to-refspec matching logic, which
bypasses parts of 'git fetch' processing configured fetch refspecs.
This logic only considers a single default refspec, potentially
influenced by options like '--single-branch' and '--mirror'. The
configured refspecs are, however, already read and parsed properly
when clone calls remote.c:remote_get(), but it never looks at the
parsed refspecs in the resulting 'struct remote'.
Modify clone to take the remote's configured fetch refspecs into
account to retrieve all matching refs during the initial fetch. Note
that we have to explicitly add the default fetch refspec to the
remote's refspecs, because at that point the remote only includes the
fetch refspecs specified on the command line.
Add tests to check that refspecs given both via 'git clone -c ...' and
'git -c ... clone' retrieve all refs matching either the default or
the additional refspecs, and that it works even when the user
specifies an alternative remote name via '--origin=<name>'.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Reviewed-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-14 10:46:19 +00:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < refspec->nr; i++)
|
|
|
|
get_fetch_map(remote_head, &refspec->items[i],
|
|
|
|
&tail, 0);
|
2012-01-16 09:46:15 +00:00
|
|
|
|
|
|
|
/* if --branch=tag, pull the requested tag explicitly */
|
|
|
|
get_fetch_map(remote_head, tag_refspec, &tail, 0);
|
|
|
|
}
|
clone: respect additional configured fetch refspecs during initial fetch
The initial fetch during a clone doesn't transfer refs matching
additional fetch refspecs given on the command line as configuration
variables, e.g. '-c remote.origin.fetch=<refspec>'. This contradicts
the documentation stating that configuration variables specified via
'git clone -c <key>=<value> ...' "take effect immediately after the
repository is initialized, but before the remote history is fetched"
and the given example specifically mentions "adding additional fetch
refspecs to the origin remote". Furthermore, one-shot configuration
variables specified via 'git -c <key>=<value> clone ...', though not
written to the newly created repository's config file, live during the
lifetime of the 'clone' command, including the initial fetch. All
this implies that any fetch refspecs specified this way should already
be taken into account during the initial fetch.
The reason for this is that the initial fetch is not a fully fledged
'git fetch' but a bunch of direct calls into the fetch/transport
machinery with clone's own refs-to-refspec matching logic, which
bypasses parts of 'git fetch' processing configured fetch refspecs.
This logic only considers a single default refspec, potentially
influenced by options like '--single-branch' and '--mirror'. The
configured refspecs are, however, already read and parsed properly
when clone calls remote.c:remote_get(), but it never looks at the
parsed refspecs in the resulting 'struct remote'.
Modify clone to take the remote's configured fetch refspecs into
account to retrieve all matching refs during the initial fetch. Note
that we have to explicitly add the default fetch refspec to the
remote's refspecs, because at that point the remote only includes the
fetch refspecs specified on the command line.
Add tests to check that refspecs given both via 'git clone -c ...' and
'git -c ... clone' retrieve all refs matching either the default or
the additional refspecs, and that it works even when the user
specifies an alternative remote name via '--origin=<name>'.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Reviewed-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-14 10:46:19 +00:00
|
|
|
} else {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < refspec->nr; i++)
|
|
|
|
get_fetch_map(refs, &refspec->items[i], &tail, 0);
|
|
|
|
}
|
2012-01-07 14:45:59 +00:00
|
|
|
|
2017-04-26 23:12:33 +00:00
|
|
|
if (!option_mirror && !option_single_branch && !option_no_tags)
|
2008-08-08 02:29:35 +00:00
|
|
|
get_fetch_map(refs, tag_refspec, &tail, 0);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2009-09-26 03:54:42 +00:00
|
|
|
return local_refs;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void write_remote_refs(const struct ref *local_refs)
|
|
|
|
{
|
|
|
|
const struct ref *r;
|
|
|
|
|
2015-06-22 14:03:01 +00:00
|
|
|
struct ref_transaction *t;
|
|
|
|
struct strbuf err = STRBUF_INIT;
|
|
|
|
|
|
|
|
t = ref_transaction_begin(&err);
|
|
|
|
if (!t)
|
|
|
|
die("%s", err.buf);
|
2013-06-20 08:37:46 +00:00
|
|
|
|
clone: always fetch remote HEAD
In most cases, fetching the remote HEAD explicitly is
unnecessary. It's just a symref pointing to a branch which
we are already fetching, so we will already ask for its sha1.
However, if the remote has a detached HEAD, things are less
certain. We do not ask for HEAD's sha1, but we do try to
write it into a local detached HEAD. In most cases this is
fine, as the remote HEAD is pointing to some part of the
history graph that we will fetch via the refs.
But if the remote HEAD points to an "orphan" commit (one
which was is not an ancestor of any refs), then we will not
have the object, and update_ref will complain when we try to
write the detached HEAD, aborting the whole clone.
This patch makes clone always explicitly ask the remote for
the sha1 of its HEAD commit. In the non-detached case, this
is a no-op, as we were going to ask for that sha1 anyway. In
the regular detached case, this will add an extra "want" to
the protocol negotiation, but will not change the history
that gets sent. And in the detached orphan case, we will
fetch the orphaned history so that we can write it into our
local detached HEAD.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-07 23:03:22 +00:00
|
|
|
for (r = local_refs; r; r = r->next) {
|
|
|
|
if (!r->peer_ref)
|
|
|
|
continue;
|
2017-10-15 22:06:53 +00:00
|
|
|
if (ref_transaction_create(t, r->peer_ref->name, &r->old_oid,
|
2015-06-22 14:03:01 +00:00
|
|
|
0, NULL, &err))
|
|
|
|
die("%s", err.buf);
|
clone: always fetch remote HEAD
In most cases, fetching the remote HEAD explicitly is
unnecessary. It's just a symref pointing to a branch which
we are already fetching, so we will already ask for its sha1.
However, if the remote has a detached HEAD, things are less
certain. We do not ask for HEAD's sha1, but we do try to
write it into a local detached HEAD. In most cases this is
fine, as the remote HEAD is pointing to some part of the
history graph that we will fetch via the refs.
But if the remote HEAD points to an "orphan" commit (one
which was is not an ancestor of any refs), then we will not
have the object, and update_ref will complain when we try to
write the detached HEAD, aborting the whole clone.
This patch makes clone always explicitly ask the remote for
the sha1 of its HEAD commit. In the non-detached case, this
is a no-op, as we were going to ask for that sha1 anyway. In
the regular detached case, this will add an extra "want" to
the protocol negotiation, but will not change the history
that gets sent. And in the detached orphan case, we will
fetch the orphaned history so that we can write it into our
local detached HEAD.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-07 23:03:22 +00:00
|
|
|
}
|
2008-06-15 14:06:16 +00:00
|
|
|
|
2015-06-22 14:03:01 +00:00
|
|
|
if (initial_ref_transaction_commit(t, &err))
|
|
|
|
die("%s", err.buf);
|
|
|
|
|
|
|
|
strbuf_release(&err);
|
|
|
|
ref_transaction_free(t);
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|
|
|
|
|
2012-01-07 14:45:59 +00:00
|
|
|
static void write_followtags(const struct ref *refs, const char *msg)
|
|
|
|
{
|
|
|
|
const struct ref *ref;
|
|
|
|
for (ref = refs; ref; ref = ref->next) {
|
2013-11-30 20:55:40 +00:00
|
|
|
if (!starts_with(ref->name, "refs/tags/"))
|
2012-01-07 14:45:59 +00:00
|
|
|
continue;
|
2013-11-30 20:55:40 +00:00
|
|
|
if (ends_with(ref->name, "^{}"))
|
2012-01-07 14:45:59 +00:00
|
|
|
continue;
|
clone: use "quick" lookup while following tags
When cloning with --single-branch, we implement git-fetch's usual
tag-following behavior, grabbing any tag objects that point to objects
we have locally.
When we're a partial clone, though, our has_object_file() check will
actually lazy-fetch each tag. That not only defeats the purpose of
--single-branch, but it does it incredibly slowly, potentially kicking
off a new fetch for each tag. This is even worse for a shallow clone,
which implies --single-branch, because even tags which are supersets of
each other will be fetched individually.
We can fix this by passing OBJECT_INFO_SKIP_FETCH_OBJECT to the call,
which is what git-fetch does in this case.
Likewise, let's include OBJECT_INFO_QUICK, as that's what git-fetch
does. The rationale is discussed in 5827a03545 (fetch: use "quick"
has_sha1_file for tag following, 2016-10-13), but here the tradeoff
would apply even more so because clone is very unlikely to be racing
with another process repacking our newly-created repository.
This may provide a very small speedup even in the non-partial case case,
as we'd avoid calling reprepare_packed_git() for each tag (though in
practice, we'd only have a single packfile, so that reprepare should be
quite cheap).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-01 12:15:37 +00:00
|
|
|
if (!has_object_file_with_flags(&ref->old_oid,
|
|
|
|
OBJECT_INFO_QUICK |
|
|
|
|
OBJECT_INFO_SKIP_FETCH_OBJECT))
|
2012-01-07 14:45:59 +00:00
|
|
|
continue;
|
2017-10-15 22:06:51 +00:00
|
|
|
update_ref(msg, ref->name, &ref->old_oid, NULL, 0,
|
|
|
|
UPDATE_REFS_DIE_ON_ERR);
|
2012-01-07 14:45:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-15 22:06:54 +00:00
|
|
|
static int iterate_ref_map(void *cb_data, struct object_id *oid)
|
2013-03-25 20:26:27 +00:00
|
|
|
{
|
|
|
|
struct ref **rm = cb_data;
|
|
|
|
struct ref *ref = *rm;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip anything missing a peer_ref, which we are not
|
|
|
|
* actually going to write a ref for.
|
|
|
|
*/
|
|
|
|
while (ref && !ref->peer_ref)
|
|
|
|
ref = ref->next;
|
|
|
|
/* Returning -1 notes "end of list" to the caller. */
|
|
|
|
if (!ref)
|
|
|
|
return -1;
|
|
|
|
|
2017-10-15 22:06:54 +00:00
|
|
|
oidcpy(oid, &ref->old_oid);
|
2013-03-25 20:26:27 +00:00
|
|
|
*rm = ref->next;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-01-16 09:46:11 +00:00
|
|
|
static void update_remote_refs(const struct ref *refs,
|
|
|
|
const struct ref *mapped_refs,
|
|
|
|
const struct ref *remote_head_points_at,
|
|
|
|
const char *branch_top,
|
2013-05-26 01:16:17 +00:00
|
|
|
const char *msg,
|
2013-07-18 19:48:28 +00:00
|
|
|
struct transport *transport,
|
connected: always use partial clone optimization
With 50033772d5 ("connected: verify promisor-ness of partial clone",
2020-01-30), the fast path (checking promisor packs) in
check_connected() now passes a subset of the slow path (rev-list) - if
all objects to be checked are found in promisor packs, both the fast
path and the slow path will pass; otherwise, the fast path will
definitely not pass. This means that we can always attempt the fast path
whenever we need to do the slow path.
The fast path is currently guarded by a flag; therefore, remove that
flag. Also, make the fast path fallback to the slow path - if the fast
path fails, the failing OID and all remaining OIDs will be passed to
rev-list.
The main user-visible benefit is the performance of fetch from a partial
clone - specifically, the speedup of the connectivity check done before
the fetch. In particular, a no-op fetch into a partial clone on my
computer was sped up from 7 seconds to 0.01 seconds. This is a
complement to the work in 2df1aa239c ("fetch: forgo full
connectivity check if --filter", 2020-01-30), which is the child of the
aforementioned 50033772d5. In that commit, the connectivity check
*after* the fetch was sped up.
The addition of the fast path might cause performance reductions in
these cases:
- If a partial clone or a fetch into a partial clone fails, Git will
fruitlessly run rev-list (it is expected that everything fetched
would go into promisor packs, so if that didn't happen, it is most
likely that rev-list will fail too).
- Any connectivity checks done by receive-pack, in the (in my opinion,
unlikely) event that a partial clone serves receive-pack.
I think that these cases are rare enough, and the performance reduction
in this case minor enough (additional object DB access), that the
benefit of avoiding a flag outweighs these.
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Reviewed-by: Josh Steadmon <steadmon@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-20 22:00:45 +00:00
|
|
|
int check_connectivity)
|
2012-01-16 09:46:11 +00:00
|
|
|
{
|
2013-03-25 20:26:27 +00:00
|
|
|
const struct ref *rm = mapped_refs;
|
|
|
|
|
clone: drop connectivity check for local clones
Commit 0433ad1 (clone: run check_everything_connected,
2013-03-25) added the same connectivity check to clone that
we use for fetching. The intent was to provide enough safety
checks that "git clone git://..." could be counted on to
detect bit errors and other repo corruption, and not
silently propagate them to the clone.
For local clones, this turns out to be a bad idea, for two
reasons:
1. Local clones use hard linking (or even shared object
stores), and so complete far more quickly. The time
spent on the connectivity check is therefore
proportionally much more painful.
2. Local clones do not actually meet our safety guarantee
anyway. The connectivity check makes sure we have all
of the objects we claim to, but it does not check for
bit errors. We will notice bit errors in commits and
trees, but we do not load blob objects at all. Whereas
over the pack transport, we actually recompute the sha1
of each object in the incoming packfile; bit errors
change the sha1 of the object, which is then caught by
the connectivity check.
This patch drops the connectivity check in the local case.
Note that we have to revert the changes from 0433ad1 to
t5710, as we no longer notice the corruption during clone.
We could go a step further and provide a "verify even local
clones" option, but it is probably not worthwhile. You can
already spell that as "cd foo.git && git fsck && git clone ."
or as "git clone --no-local foo.git".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-07-08 07:30:41 +00:00
|
|
|
if (check_connectivity) {
|
check_everything_connected: use a struct with named options
The number of variants of check_everything_connected has
grown over the years, so that the "real" function takes
several possibly-zero, possibly-NULL arguments. We hid the
complexity behind some wrapper functions, but this doesn't
scale well when we want to add new options.
If we add more wrapper variants to handle the new options,
then we can get a combinatorial explosion when those options
might be used together (right now nobody wants to use both
"shallow" and "transport" together, so we get by with just a
few wrappers).
If instead we add new parameters to each function, each of
which can have a default value, then callers who want the
defaults end up with confusing invocations like:
check_everything_connected(fn, 0, data, -1, 0, NULL);
where it is unclear which parameter is which (and every
caller needs updated when we add new options).
Instead, let's add a struct to hold all of the optional
parameters. This is a little more verbose for the callers
(who have to declare the struct and fill it in), but it
makes their code much easier to follow, because every option
is named as it is set (and unused options do not have to be
mentioned at all).
Note that we could also stick the iteration function and its
callback data into the option struct, too. But since those
are required for each call, by avoiding doing so, we can let
very simple callers just pass "NULL" for the options and not
worry about the struct at all.
While we're touching each site, let's also rename the
function to check_connected(). The existing name was quite
long, and not all of the wrappers even used the full name.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-15 10:30:40 +00:00
|
|
|
struct check_connected_options opt = CHECK_CONNECTED_INIT;
|
|
|
|
|
|
|
|
opt.transport = transport;
|
2016-07-15 10:33:18 +00:00
|
|
|
opt.progress = transport->progress;
|
check_everything_connected: use a struct with named options
The number of variants of check_everything_connected has
grown over the years, so that the "real" function takes
several possibly-zero, possibly-NULL arguments. We hid the
complexity behind some wrapper functions, but this doesn't
scale well when we want to add new options.
If we add more wrapper variants to handle the new options,
then we can get a combinatorial explosion when those options
might be used together (right now nobody wants to use both
"shallow" and "transport" together, so we get by with just a
few wrappers).
If instead we add new parameters to each function, each of
which can have a default value, then callers who want the
defaults end up with confusing invocations like:
check_everything_connected(fn, 0, data, -1, 0, NULL);
where it is unclear which parameter is which (and every
caller needs updated when we add new options).
Instead, let's add a struct to hold all of the optional
parameters. This is a little more verbose for the callers
(who have to declare the struct and fill it in), but it
makes their code much easier to follow, because every option
is named as it is set (and unused options do not have to be
mentioned at all).
Note that we could also stick the iteration function and its
callback data into the option struct, too. But since those
are required for each call, by avoiding doing so, we can let
very simple callers just pass "NULL" for the options and not
worry about the struct at all.
While we're touching each site, let's also rename the
function to check_connected(). The existing name was quite
long, and not all of the wrappers even used the full name.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-15 10:30:40 +00:00
|
|
|
|
|
|
|
if (check_connected(iterate_ref_map, &rm, &opt))
|
clone: drop connectivity check for local clones
Commit 0433ad1 (clone: run check_everything_connected,
2013-03-25) added the same connectivity check to clone that
we use for fetching. The intent was to provide enough safety
checks that "git clone git://..." could be counted on to
detect bit errors and other repo corruption, and not
silently propagate them to the clone.
For local clones, this turns out to be a bad idea, for two
reasons:
1. Local clones use hard linking (or even shared object
stores), and so complete far more quickly. The time
spent on the connectivity check is therefore
proportionally much more painful.
2. Local clones do not actually meet our safety guarantee
anyway. The connectivity check makes sure we have all
of the objects we claim to, but it does not check for
bit errors. We will notice bit errors in commits and
trees, but we do not load blob objects at all. Whereas
over the pack transport, we actually recompute the sha1
of each object in the incoming packfile; bit errors
change the sha1 of the object, which is then caught by
the connectivity check.
This patch drops the connectivity check in the local case.
Note that we have to revert the changes from 0433ad1 to
t5710, as we no longer notice the corruption during clone.
We could go a step further and provide a "verify even local
clones" option, but it is probably not worthwhile. You can
already spell that as "cd foo.git && git fsck && git clone ."
or as "git clone --no-local foo.git".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-07-08 07:30:41 +00:00
|
|
|
die(_("remote did not send all necessary objects"));
|
|
|
|
}
|
2013-03-25 20:26:27 +00:00
|
|
|
|
2012-01-16 09:46:11 +00:00
|
|
|
if (refs) {
|
|
|
|
write_remote_refs(mapped_refs);
|
2017-04-26 23:12:33 +00:00
|
|
|
if (option_single_branch && !option_no_tags)
|
2012-01-16 09:46:11 +00:00
|
|
|
write_followtags(refs, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (remote_head_points_at && !option_bare) {
|
|
|
|
struct strbuf head_ref = STRBUF_INIT;
|
|
|
|
strbuf_addstr(&head_ref, branch_top);
|
|
|
|
strbuf_addstr(&head_ref, "HEAD");
|
2016-01-12 09:57:34 +00:00
|
|
|
if (create_symref(head_ref.buf,
|
|
|
|
remote_head_points_at->peer_ref->name,
|
|
|
|
msg) < 0)
|
2016-02-27 06:41:55 +00:00
|
|
|
die(_("unable to update %s"), head_ref.buf);
|
2016-01-12 09:57:34 +00:00
|
|
|
strbuf_release(&head_ref);
|
2012-01-16 09:46:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-16 09:46:10 +00:00
|
|
|
static void update_head(const struct ref *our, const struct ref *remote,
|
|
|
|
const char *msg)
|
|
|
|
{
|
refactor skip_prefix to return a boolean
The skip_prefix() function returns a pointer to the content
past the prefix, or NULL if the prefix was not found. While
this is nice and simple, in practice it makes it hard to use
for two reasons:
1. When you want to conditionally skip or keep the string
as-is, you have to introduce a temporary variable.
For example:
tmp = skip_prefix(buf, "foo");
if (tmp)
buf = tmp;
2. It is verbose to check the outcome in a conditional, as
you need extra parentheses to silence compiler
warnings. For example:
if ((cp = skip_prefix(buf, "foo"))
/* do something with cp */
Both of these make it harder to use for long if-chains, and
we tend to use starts_with() instead. However, the first line
of "do something" is often to then skip forward in buf past
the prefix, either using a magic constant or with an extra
strlen(3) (which is generally computed at compile time, but
means we are repeating ourselves).
This patch refactors skip_prefix() to return a simple boolean,
and to provide the pointer value as an out-parameter. If the
prefix is not found, the out-parameter is untouched. This
lets you write:
if (skip_prefix(arg, "foo ", &arg))
do_foo(arg);
else if (skip_prefix(arg, "bar ", &arg))
do_bar(arg);
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-06-18 19:44:19 +00:00
|
|
|
const char *head;
|
|
|
|
if (our && skip_prefix(our->name, "refs/heads/", &head)) {
|
2012-01-16 09:46:10 +00:00
|
|
|
/* Local default branch link */
|
2016-01-12 09:57:34 +00:00
|
|
|
if (create_symref("HEAD", our->name, NULL) < 0)
|
2016-02-27 06:41:55 +00:00
|
|
|
die(_("unable to update HEAD"));
|
2012-01-16 09:46:10 +00:00
|
|
|
if (!option_bare) {
|
2017-10-15 22:06:51 +00:00
|
|
|
update_ref(msg, "HEAD", &our->old_oid, NULL, 0,
|
2014-04-07 13:47:56 +00:00
|
|
|
UPDATE_REFS_DIE_ON_ERR);
|
2012-01-16 09:46:10 +00:00
|
|
|
install_branch_config(0, head, option_origin, our->name);
|
|
|
|
}
|
2012-01-16 09:46:15 +00:00
|
|
|
} else if (our) {
|
2018-06-29 01:21:58 +00:00
|
|
|
struct commit *c = lookup_commit_reference(the_repository,
|
|
|
|
&our->old_oid);
|
2012-01-16 09:46:15 +00:00
|
|
|
/* --branch specifies a non-branch (i.e. tags), detach HEAD */
|
2017-11-05 08:42:06 +00:00
|
|
|
update_ref(msg, "HEAD", &c->object.oid, NULL, REF_NO_DEREF,
|
2017-10-15 22:06:51 +00:00
|
|
|
UPDATE_REFS_DIE_ON_ERR);
|
2012-01-16 09:46:10 +00:00
|
|
|
} else if (remote) {
|
|
|
|
/*
|
|
|
|
* We know remote HEAD points to a non-branch, or
|
2012-01-16 09:46:14 +00:00
|
|
|
* HEAD points to a branch but we don't know which one.
|
2012-01-16 09:46:10 +00:00
|
|
|
* Detach HEAD in all these cases.
|
|
|
|
*/
|
2017-11-05 08:42:06 +00:00
|
|
|
update_ref(msg, "HEAD", &remote->old_oid, NULL, REF_NO_DEREF,
|
2017-10-15 22:06:51 +00:00
|
|
|
UPDATE_REFS_DIE_ON_ERR);
|
2012-01-16 09:46:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-21 22:04:35 +00:00
|
|
|
static int git_sparse_checkout_init(const char *repo)
|
|
|
|
{
|
|
|
|
struct argv_array argv = ARGV_ARRAY_INIT;
|
|
|
|
int result = 0;
|
|
|
|
argv_array_pushl(&argv, "-C", repo, "sparse-checkout", "init", NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We must apply the setting in the current process
|
|
|
|
* for the later checkout to use the sparse-checkout file.
|
|
|
|
*/
|
|
|
|
core_apply_sparse_checkout = 1;
|
|
|
|
|
|
|
|
if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
|
|
|
|
error(_("failed to initialize sparse-checkout"));
|
|
|
|
result = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
argv_array_clear(&argv);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
clone: pass --progress decision to recursive submodules
When cloning with "--recursive", we'd generally expect
submodules to show progress reports if the main clone did,
too.
In older versions of git, this mostly worked out of the
box. Since we show progress by default when stderr is a tty,
and since the child clones inherit the parent stderr, then
both processes would come to the same decision by default.
If the parent clone was asked for "--quiet", we passed down
"--quiet" to the child. However, if stderr was not a tty and
the user specified "--progress", we did not propagate this
to the child.
That's a minor bug, but things got much worse when we
switched recently to submodule--helper's update_clone
command. With that change, the stderr of the child clones
are always connected to a pipe, and we never output
progress at all.
This patch teaches git-submodule and git-submodule--helper
how to pass down an explicit "--progress" flag when cloning.
The clone command then decides to propagate that flag based
on the cloning decision made earlier (which takes into
account isatty(2) of the parent process, existing --progress
or --quiet flags, etc). Since the child processes always run
without a tty on stderr, we don't have to worry about
passing an explicit "--no-progress"; it's the default for
them.
This fixes the recent loss of progress during recursive
clones. And as a bonus, it makes:
git clone --recursive --progress ... 2>&1 | cat
work by triggering progress explicitly in the children.
Signed-off-by: Jeff King <peff@peff.net>
Acked-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-09-22 05:24:46 +00:00
|
|
|
static int checkout(int submodule_progress)
|
2012-01-16 09:46:09 +00:00
|
|
|
{
|
2017-02-21 23:47:27 +00:00
|
|
|
struct object_id oid;
|
2012-01-16 09:46:09 +00:00
|
|
|
char *head;
|
2017-10-05 20:32:04 +00:00
|
|
|
struct lock_file lock_file = LOCK_INIT;
|
2012-01-16 09:46:09 +00:00
|
|
|
struct unpack_trees_options opts;
|
|
|
|
struct tree *tree;
|
|
|
|
struct tree_desc t;
|
2014-06-13 12:19:23 +00:00
|
|
|
int err = 0;
|
2012-01-16 09:46:09 +00:00
|
|
|
|
|
|
|
if (option_no_checkout)
|
|
|
|
return 0;
|
|
|
|
|
refs: convert resolve_refdup and refs_resolve_refdup to struct object_id
All of the callers already pass the hash member of struct object_id, so
update them to pass a pointer to the struct directly,
This transformation was done with an update to declaration and
definition and the following semantic patch:
@@
expression E1, E2, E3, E4;
@@
- resolve_refdup(E1, E2, E3.hash, E4)
+ resolve_refdup(E1, E2, &E3, E4)
@@
expression E1, E2, E3, E4;
@@
- resolve_refdup(E1, E2, E3->hash, E4)
+ resolve_refdup(E1, E2, E3, E4)
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-15 22:06:55 +00:00
|
|
|
head = resolve_refdup("HEAD", RESOLVE_REF_READING, &oid, NULL);
|
2012-01-16 09:46:09 +00:00
|
|
|
if (!head) {
|
|
|
|
warning(_("remote HEAD refers to nonexistent ref, "
|
|
|
|
"unable to checkout.\n"));
|
|
|
|
return 0;
|
|
|
|
}
|
2012-01-16 09:46:16 +00:00
|
|
|
if (!strcmp(head, "HEAD")) {
|
|
|
|
if (advice_detached_head)
|
2017-02-21 23:47:27 +00:00
|
|
|
detach_advice(oid_to_hex(&oid));
|
2020-03-16 18:05:05 +00:00
|
|
|
FREE_AND_NULL(head);
|
2012-01-16 09:46:16 +00:00
|
|
|
} else {
|
2013-11-30 20:55:40 +00:00
|
|
|
if (!starts_with(head, "refs/heads/"))
|
2012-01-16 09:46:09 +00:00
|
|
|
die(_("HEAD not found below refs/heads!"));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We need to be in the new work tree for the checkout */
|
|
|
|
setup_work_tree();
|
|
|
|
|
2017-10-05 20:32:04 +00:00
|
|
|
hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
|
2012-01-16 09:46:09 +00:00
|
|
|
|
|
|
|
memset(&opts, 0, sizeof opts);
|
|
|
|
opts.update = 1;
|
|
|
|
opts.merge = 1;
|
2018-08-17 18:00:39 +00:00
|
|
|
opts.clone = 1;
|
2012-01-16 09:46:09 +00:00
|
|
|
opts.fn = oneway_merge;
|
2012-05-07 19:35:36 +00:00
|
|
|
opts.verbose_update = (option_verbosity >= 0);
|
2012-01-16 09:46:09 +00:00
|
|
|
opts.src_index = &the_index;
|
|
|
|
opts.dst_index = &the_index;
|
2020-03-16 18:05:05 +00:00
|
|
|
init_checkout_metadata(&opts.meta, head, &oid, NULL);
|
2012-01-16 09:46:09 +00:00
|
|
|
|
2017-05-06 22:10:37 +00:00
|
|
|
tree = parse_tree_indirect(&oid);
|
2012-01-16 09:46:09 +00:00
|
|
|
parse_tree(tree);
|
|
|
|
init_tree_desc(&t, tree->buffer, tree->size);
|
clone: die on errors from unpack_trees
When clone is populating the working tree, it ignores the
return status from unpack_trees; this means we may report a
successful clone, even when the checkout fails.
When checkout fails, we may want to leave the $GIT_DIR in
place, as it might be possible to recover the data through
further use of "git checkout" (e.g., if the checkout failed
due to a transient error, disk full, etc). However, we
already die on a number of other checkout-related errors, so
this patch follows that pattern.
In addition to marking a now-passing test, we need to adjust
t5710, which blindly assumed it could make bogus clones of
very deep alternates hierarchies. By using "--bare", we can
avoid it actually touching any objects.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-25 20:23:59 +00:00
|
|
|
if (unpack_trees(1, &t, &opts) < 0)
|
|
|
|
die(_("unable to checkout working tree"));
|
2012-01-16 09:46:09 +00:00
|
|
|
|
2020-03-16 18:05:05 +00:00
|
|
|
free(head);
|
|
|
|
|
2017-10-05 20:32:04 +00:00
|
|
|
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
|
2012-01-16 09:46:09 +00:00
|
|
|
die(_("unable to write new index file"));
|
|
|
|
|
2019-08-18 20:04:20 +00:00
|
|
|
err |= run_hook_le(NULL, "post-checkout", oid_to_hex(&null_oid),
|
2017-02-21 23:47:27 +00:00
|
|
|
oid_to_hex(&oid), "1", NULL);
|
2012-01-16 09:46:09 +00:00
|
|
|
|
2017-03-17 22:38:03 +00:00
|
|
|
if (!err && (option_recurse_submodules.nr > 0)) {
|
2016-03-01 02:07:20 +00:00
|
|
|
struct argv_array args = ARGV_ARRAY_INIT;
|
clone --recurse-submodules: prevent name squatting on Windows
In addition to preventing `.git` from being tracked by Git, on Windows
we also have to prevent `git~1` from being tracked, as the default NTFS
short name (also known as the "8.3 filename") for the file name `.git`
is `git~1`, otherwise it would be possible for malicious repositories to
write directly into the `.git/` directory, e.g. a `post-checkout` hook
that would then be executed _during_ a recursive clone.
When we implemented appropriate protections in 2b4c6efc821 (read-cache:
optionally disallow NTFS .git variants, 2014-12-16), we had analyzed
carefully that the `.git` directory or file would be guaranteed to be
the first directory entry to be written. Otherwise it would be possible
e.g. for a file named `..git` to be assigned the short name `git~1` and
subsequently, the short name generated for `.git` would be `git~2`. Or
`git~3`. Or even `~9999999` (for a detailed explanation of the lengths
we have to go to protect `.gitmodules`, see the commit message of
e7cb0b4455c (is_ntfs_dotgit: match other .git files, 2018-05-11)).
However, by exploiting two issues (that will be addressed in a related
patch series close by), it is currently possible to clone a submodule
into a non-empty directory:
- On Windows, file names cannot end in a space or a period (for
historical reasons: the period separating the base name from the file
extension was not actually written to disk, and the base name/file
extension was space-padded to the full 8/3 characters, respectively).
Helpfully, when creating a directory under the name, say, `sub.`, that
trailing period is trimmed automatically and the actual name on disk
is `sub`.
This means that while Git thinks that the submodule names `sub` and
`sub.` are different, they both access `.git/modules/sub/`.
- While the backslash character is a valid file name character on Linux,
it is not so on Windows. As Git tries to be cross-platform, it
therefore allows backslash characters in the file names stored in tree
objects.
Which means that it is totally possible that a submodule `c` sits next
to a file `c\..git`, and on Windows, during recursive clone a file
called `..git` will be written into `c/`, of course _before_ the
submodule is cloned.
Note that the actual exploit is not quite as simple as having a
submodule `c` next to a file `c\..git`, as we have to make sure that the
directory `.git/modules/b` already exists when the submodule is checked
out, otherwise a different code path is taken in `module_clone()` that
does _not_ allow a non-empty submodule directory to exist already.
Even if we will address both issues nearby (the next commit will
disallow backslash characters in tree entries' file names on Windows,
and another patch will disallow creating directories/files with trailing
spaces or periods), it is a wise idea to defend in depth against this
sort of attack vector: when submodules are cloned recursively, we now
_require_ the directory to be empty, addressing CVE-2019-1349.
Note: the code path we patch is shared with the code path of `git
submodule update --init`, which must not expect, in general, that the
directory is empty. Hence we have to introduce the new option
`--force-init` and hand it all the way down from `git submodule` to the
actual `git submodule--helper` process that performs the initial clone.
Reported-by: Nicolas Joly <Nicolas.Joly@microsoft.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2019-09-12 12:20:39 +00:00
|
|
|
argv_array_pushl(&args, "submodule", "update", "--require-init", "--recursive", NULL);
|
2016-03-01 02:07:20 +00:00
|
|
|
|
2016-06-19 20:51:56 +00:00
|
|
|
if (option_shallow_submodules == 1)
|
2016-04-26 01:12:27 +00:00
|
|
|
argv_array_push(&args, "--depth=1");
|
|
|
|
|
2016-03-01 02:07:20 +00:00
|
|
|
if (max_jobs != -1)
|
|
|
|
argv_array_pushf(&args, "--jobs=%d", max_jobs);
|
|
|
|
|
clone: pass --progress decision to recursive submodules
When cloning with "--recursive", we'd generally expect
submodules to show progress reports if the main clone did,
too.
In older versions of git, this mostly worked out of the
box. Since we show progress by default when stderr is a tty,
and since the child clones inherit the parent stderr, then
both processes would come to the same decision by default.
If the parent clone was asked for "--quiet", we passed down
"--quiet" to the child. However, if stderr was not a tty and
the user specified "--progress", we did not propagate this
to the child.
That's a minor bug, but things got much worse when we
switched recently to submodule--helper's update_clone
command. With that change, the stderr of the child clones
are always connected to a pipe, and we never output
progress at all.
This patch teaches git-submodule and git-submodule--helper
how to pass down an explicit "--progress" flag when cloning.
The clone command then decides to propagate that flag based
on the cloning decision made earlier (which takes into
account isatty(2) of the parent process, existing --progress
or --quiet flags, etc). Since the child processes always run
without a tty on stderr, we don't have to worry about
passing an explicit "--no-progress"; it's the default for
them.
This fixes the recent loss of progress during recursive
clones. And as a bonus, it makes:
git clone --recursive --progress ... 2>&1 | cat
work by triggering progress explicitly in the children.
Signed-off-by: Jeff King <peff@peff.net>
Acked-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-09-22 05:24:46 +00:00
|
|
|
if (submodule_progress)
|
|
|
|
argv_array_push(&args, "--progress");
|
|
|
|
|
2017-08-03 22:25:44 +00:00
|
|
|
if (option_verbosity < 0)
|
|
|
|
argv_array_push(&args, "--quiet");
|
|
|
|
|
2019-05-19 14:26:49 +00:00
|
|
|
if (option_remote_submodules) {
|
|
|
|
argv_array_push(&args, "--remote");
|
|
|
|
argv_array_push(&args, "--no-fetch");
|
|
|
|
}
|
|
|
|
|
2020-02-21 03:10:27 +00:00
|
|
|
if (option_single_branch >= 0)
|
|
|
|
argv_array_push(&args, option_single_branch ?
|
|
|
|
"--single-branch" :
|
|
|
|
"--no-single-branch");
|
|
|
|
|
2016-03-01 02:07:20 +00:00
|
|
|
err = run_command_v_opt(args.argv, RUN_GIT_CMD);
|
|
|
|
argv_array_clear(&args);
|
|
|
|
}
|
2012-01-16 09:46:09 +00:00
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2011-06-09 20:56:19 +00:00
|
|
|
static int write_one_config(const char *key, const char *value, void *data)
|
|
|
|
{
|
2017-05-02 00:05:15 +00:00
|
|
|
return git_config_set_multivar_gently(key,
|
|
|
|
value ? value : "true",
|
|
|
|
CONFIG_REGEX_NONE, 0);
|
2011-06-09 20:56:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2016-02-27 06:41:55 +00:00
|
|
|
die(_("unable to write parameters to config file"));
|
2011-06-09 20:56:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-31 20:11:31 +00:00
|
|
|
static void write_refspec_config(const char *src_ref_prefix,
|
|
|
|
const struct ref *our_head_points_at,
|
|
|
|
const struct ref *remote_head_points_at,
|
|
|
|
struct strbuf *branch_top)
|
2012-09-20 18:04:08 +00:00
|
|
|
{
|
|
|
|
struct strbuf key = STRBUF_INIT;
|
|
|
|
struct strbuf value = STRBUF_INIT;
|
|
|
|
|
|
|
|
if (option_mirror || !option_bare) {
|
|
|
|
if (option_single_branch && !option_mirror) {
|
|
|
|
if (option_branch) {
|
2014-06-23 21:27:36 +00:00
|
|
|
if (starts_with(our_head_points_at->name, "refs/tags/"))
|
2012-09-20 18:04:08 +00:00
|
|
|
strbuf_addf(&value, "+%s:%s", our_head_points_at->name,
|
|
|
|
our_head_points_at->name);
|
|
|
|
else
|
|
|
|
strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name,
|
|
|
|
branch_top->buf, option_branch);
|
|
|
|
} else if (remote_head_points_at) {
|
refactor skip_prefix to return a boolean
The skip_prefix() function returns a pointer to the content
past the prefix, or NULL if the prefix was not found. While
this is nice and simple, in practice it makes it hard to use
for two reasons:
1. When you want to conditionally skip or keep the string
as-is, you have to introduce a temporary variable.
For example:
tmp = skip_prefix(buf, "foo");
if (tmp)
buf = tmp;
2. It is verbose to check the outcome in a conditional, as
you need extra parentheses to silence compiler
warnings. For example:
if ((cp = skip_prefix(buf, "foo"))
/* do something with cp */
Both of these make it harder to use for long if-chains, and
we tend to use starts_with() instead. However, the first line
of "do something" is often to then skip forward in buf past
the prefix, either using a magic constant or with an extra
strlen(3) (which is generally computed at compile time, but
means we are repeating ourselves).
This patch refactors skip_prefix() to return a simple boolean,
and to provide the pointer value as an out-parameter. If the
prefix is not found, the out-parameter is untouched. This
lets you write:
if (skip_prefix(arg, "foo ", &arg))
do_foo(arg);
else if (skip_prefix(arg, "bar ", &arg))
do_bar(arg);
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-06-18 19:44:19 +00:00
|
|
|
const char *head = remote_head_points_at->name;
|
|
|
|
if (!skip_prefix(head, "refs/heads/", &head))
|
2018-05-02 09:38:39 +00:00
|
|
|
BUG("remote HEAD points at non-head?");
|
refactor skip_prefix to return a boolean
The skip_prefix() function returns a pointer to the content
past the prefix, or NULL if the prefix was not found. While
this is nice and simple, in practice it makes it hard to use
for two reasons:
1. When you want to conditionally skip or keep the string
as-is, you have to introduce a temporary variable.
For example:
tmp = skip_prefix(buf, "foo");
if (tmp)
buf = tmp;
2. It is verbose to check the outcome in a conditional, as
you need extra parentheses to silence compiler
warnings. For example:
if ((cp = skip_prefix(buf, "foo"))
/* do something with cp */
Both of these make it harder to use for long if-chains, and
we tend to use starts_with() instead. However, the first line
of "do something" is often to then skip forward in buf past
the prefix, either using a magic constant or with an extra
strlen(3) (which is generally computed at compile time, but
means we are repeating ourselves).
This patch refactors skip_prefix() to return a simple boolean,
and to provide the pointer value as an out-parameter. If the
prefix is not found, the out-parameter is untouched. This
lets you write:
if (skip_prefix(arg, "foo ", &arg))
do_foo(arg);
else if (skip_prefix(arg, "bar ", &arg))
do_bar(arg);
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-06-18 19:44:19 +00:00
|
|
|
|
2012-09-20 18:04:08 +00:00
|
|
|
strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name,
|
refactor skip_prefix to return a boolean
The skip_prefix() function returns a pointer to the content
past the prefix, or NULL if the prefix was not found. While
this is nice and simple, in practice it makes it hard to use
for two reasons:
1. When you want to conditionally skip or keep the string
as-is, you have to introduce a temporary variable.
For example:
tmp = skip_prefix(buf, "foo");
if (tmp)
buf = tmp;
2. It is verbose to check the outcome in a conditional, as
you need extra parentheses to silence compiler
warnings. For example:
if ((cp = skip_prefix(buf, "foo"))
/* do something with cp */
Both of these make it harder to use for long if-chains, and
we tend to use starts_with() instead. However, the first line
of "do something" is often to then skip forward in buf past
the prefix, either using a magic constant or with an extra
strlen(3) (which is generally computed at compile time, but
means we are repeating ourselves).
This patch refactors skip_prefix() to return a simple boolean,
and to provide the pointer value as an out-parameter. If the
prefix is not found, the out-parameter is untouched. This
lets you write:
if (skip_prefix(arg, "foo ", &arg))
do_foo(arg);
else if (skip_prefix(arg, "bar ", &arg))
do_bar(arg);
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-06-18 19:44:19 +00:00
|
|
|
branch_top->buf, head);
|
2012-09-20 18:04:08 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* otherwise, the next "git fetch" will
|
|
|
|
* simply fetch from HEAD without updating
|
2013-07-03 09:12:34 +00:00
|
|
|
* any remote-tracking branch, which is what
|
2012-09-20 18:04:08 +00:00
|
|
|
* we want.
|
|
|
|
*/
|
|
|
|
} else {
|
|
|
|
strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top->buf);
|
|
|
|
}
|
|
|
|
/* Configure the remote */
|
|
|
|
if (value.len) {
|
|
|
|
strbuf_addf(&key, "remote.%s.fetch", option_origin);
|
|
|
|
git_config_set_multivar(key.buf, value.buf, "^$", 0);
|
|
|
|
strbuf_reset(&key);
|
|
|
|
|
|
|
|
if (option_mirror) {
|
|
|
|
strbuf_addf(&key, "remote.%s.mirror", option_origin);
|
|
|
|
git_config_set(key.buf, "true");
|
|
|
|
strbuf_reset(&key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
strbuf_release(&key);
|
|
|
|
strbuf_release(&value);
|
|
|
|
}
|
|
|
|
|
2014-10-14 19:38:52 +00:00
|
|
|
static void dissociate_from_references(void)
|
|
|
|
{
|
|
|
|
static const char* argv[] = { "repack", "-a", "-d", NULL };
|
2015-10-22 16:41:17 +00:00
|
|
|
char *alternates = git_pathdup("objects/info/alternates");
|
2014-10-14 19:38:52 +00:00
|
|
|
|
2015-10-22 16:41:17 +00:00
|
|
|
if (!access(alternates, F_OK)) {
|
|
|
|
if (run_command_v_opt(argv, RUN_GIT_CMD|RUN_COMMAND_NO_STDIN))
|
|
|
|
die(_("cannot repack to clean up"));
|
|
|
|
if (unlink(alternates) && errno != ENOENT)
|
|
|
|
die_errno(_("cannot unlink temporary alternates file"));
|
|
|
|
}
|
|
|
|
free(alternates);
|
2014-10-14 19:38:52 +00:00
|
|
|
}
|
|
|
|
|
2019-10-28 16:55:23 +00:00
|
|
|
static int path_exists(const char *path)
|
2018-01-02 21:10:14 +00:00
|
|
|
{
|
|
|
|
struct stat sb;
|
|
|
|
return !stat(path, &sb);
|
|
|
|
}
|
|
|
|
|
2008-04-27 17:39:30 +00:00
|
|
|
int cmd_clone(int argc, const char **argv, const char *prefix)
|
|
|
|
{
|
2010-08-23 12:08:22 +00:00
|
|
|
int is_bundle = 0, is_local;
|
2008-04-27 17:39:30 +00:00
|
|
|
const char *repo_name, *repo, *work_tree, *git_dir;
|
|
|
|
char *path, *dir;
|
2009-01-11 12:19:12 +00:00
|
|
|
int dest_exists;
|
2009-11-18 01:42:24 +00:00
|
|
|
const struct ref *refs, *remote_head;
|
2009-08-26 19:05:08 +00:00
|
|
|
const struct ref *remote_head_points_at;
|
|
|
|
const struct ref *our_head_points_at;
|
2009-11-18 01:42:24 +00:00
|
|
|
struct ref *mapped_refs;
|
2012-01-24 11:10:38 +00:00
|
|
|
const struct ref *ref;
|
2018-11-14 10:46:18 +00:00
|
|
|
struct strbuf key = STRBUF_INIT;
|
|
|
|
struct strbuf default_refspec = STRBUF_INIT;
|
2008-11-21 00:45:01 +00:00
|
|
|
struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
|
2008-07-08 04:46:06 +00:00
|
|
|
struct transport *transport = NULL;
|
2012-01-16 09:46:13 +00:00
|
|
|
const char *src_ref_prefix = "refs/heads/";
|
2012-01-16 09:46:12 +00:00
|
|
|
struct remote *remote;
|
2012-01-24 11:10:38 +00:00
|
|
|
int err = 0, complete_refs_before_fetch = 1;
|
clone: pass --progress decision to recursive submodules
When cloning with "--recursive", we'd generally expect
submodules to show progress reports if the main clone did,
too.
In older versions of git, this mostly worked out of the
box. Since we show progress by default when stderr is a tty,
and since the child clones inherit the parent stderr, then
both processes would come to the same decision by default.
If the parent clone was asked for "--quiet", we passed down
"--quiet" to the child. However, if stderr was not a tty and
the user specified "--progress", we did not propagate this
to the child.
That's a minor bug, but things got much worse when we
switched recently to submodule--helper's update_clone
command. With that change, the stderr of the child clones
are always connected to a pipe, and we never output
progress at all.
This patch teaches git-submodule and git-submodule--helper
how to pass down an explicit "--progress" flag when cloning.
The clone command then decides to propagate that flag based
on the cloning decision made earlier (which takes into
account isatty(2) of the parent process, existing --progress
or --quiet flags, etc). Since the child processes always run
without a tty on stderr, we don't have to worry about
passing an explicit "--no-progress"; it's the default for
them.
This fixes the recent loss of progress during recursive
clones. And as a bonus, it makes:
git clone --recursive --progress ... 2>&1 | cat
work by triggering progress explicitly in the children.
Signed-off-by: Jeff King <peff@peff.net>
Acked-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-09-22 05:24:46 +00:00
|
|
|
int submodule_progress;
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2018-07-20 22:07:54 +00:00
|
|
|
struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2011-02-24 14:30:19 +00:00
|
|
|
packet_trace_identity("clone");
|
2009-05-23 18:53:12 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, builtin_clone_options,
|
2008-04-27 17:39:30 +00:00
|
|
|
builtin_clone_usage, 0);
|
|
|
|
|
2009-10-29 08:10:30 +00:00
|
|
|
if (argc > 2)
|
2011-02-22 23:41:26 +00:00
|
|
|
usage_msg_opt(_("Too many arguments."),
|
2009-10-29 08:10:30 +00:00
|
|
|
builtin_clone_usage, builtin_clone_options);
|
|
|
|
|
2008-04-27 17:39:30 +00:00
|
|
|
if (argc == 0)
|
2011-02-22 23:41:26 +00:00
|
|
|
usage_msg_opt(_("You must specify a repository to clone."),
|
2009-10-29 08:10:30 +00:00
|
|
|
builtin_clone_usage, builtin_clone_options);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2016-06-12 10:54:05 +00:00
|
|
|
if (option_depth || option_since || option_not.nr)
|
2016-06-12 10:54:00 +00:00
|
|
|
deepen = 1;
|
2012-01-07 14:45:59 +00:00
|
|
|
if (option_single_branch == -1)
|
2016-06-12 10:54:00 +00:00
|
|
|
option_single_branch = deepen ? 1 : 0;
|
2012-01-07 14:45:59 +00:00
|
|
|
|
2008-08-02 19:38:56 +00:00
|
|
|
if (option_mirror)
|
|
|
|
option_bare = 1;
|
|
|
|
|
2008-04-27 17:39:30 +00:00
|
|
|
if (option_bare) {
|
|
|
|
if (option_origin)
|
2011-02-22 23:41:26 +00:00
|
|
|
die(_("--bare and --origin %s options are incompatible."),
|
2008-04-27 17:39:30 +00:00
|
|
|
option_origin);
|
2013-01-11 03:09:59 +00:00
|
|
|
if (real_git_dir)
|
|
|
|
die(_("--bare and --separate-git-dir are incompatible."));
|
2008-04-27 17:39:30 +00:00
|
|
|
option_no_checkout = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!option_origin)
|
|
|
|
option_origin = "origin";
|
|
|
|
|
|
|
|
repo_name = argv[0];
|
|
|
|
|
|
|
|
path = get_repo_path(repo_name, &is_bundle);
|
|
|
|
if (path)
|
2017-01-26 17:54:23 +00:00
|
|
|
repo = absolute_pathdup(repo_name);
|
2008-04-27 17:39:30 +00:00
|
|
|
else if (!strchr(repo_name, ':'))
|
2011-04-10 19:34:06 +00:00
|
|
|
die(_("repository '%s' does not exist"), repo_name);
|
2008-04-27 17:39:30 +00:00
|
|
|
else
|
|
|
|
repo = repo_name;
|
|
|
|
|
2013-12-05 03:31:11 +00:00
|
|
|
/* no need to be strict, transport_set_option() will validate it again */
|
|
|
|
if (option_depth && atoi(option_depth) < 1)
|
|
|
|
die(_("depth %s is not a positive number"), option_depth);
|
|
|
|
|
2008-04-27 17:39:30 +00:00
|
|
|
if (argc == 2)
|
|
|
|
dir = xstrdup(argv[1]);
|
|
|
|
else
|
2008-08-01 14:01:36 +00:00
|
|
|
dir = guess_dir_name(repo_name, is_bundle, option_bare);
|
2008-09-03 18:55:55 +00:00
|
|
|
strip_trailing_slashes(dir);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2019-10-28 16:55:23 +00:00
|
|
|
dest_exists = path_exists(dir);
|
2009-01-11 12:19:12 +00:00
|
|
|
if (dest_exists && !is_empty_dir(dir))
|
2011-02-22 23:41:26 +00:00
|
|
|
die(_("destination path '%s' already exists and is not "
|
|
|
|
"an empty directory."), dir);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
|
|
|
strbuf_addf(&reflog_msg, "clone: from %s", repo);
|
|
|
|
|
|
|
|
if (option_bare)
|
|
|
|
work_tree = NULL;
|
|
|
|
else {
|
|
|
|
work_tree = getenv("GIT_WORK_TREE");
|
2019-10-28 16:55:23 +00:00
|
|
|
if (work_tree && path_exists(work_tree))
|
2011-02-22 23:41:26 +00:00
|
|
|
die(_("working tree '%s' already exists."), work_tree);
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (option_bare || work_tree)
|
|
|
|
git_dir = xstrdup(dir);
|
|
|
|
else {
|
|
|
|
work_tree = dir;
|
2012-09-04 17:31:14 +00:00
|
|
|
git_dir = mkpathdup("%s/.git", dir);
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|
|
|
|
|
clone: initialize atexit cleanup handler earlier
If clone fails, we generally try to clean up any directories
we've created. We do this by installing an atexit handler,
so that we don't have to manually trigger cleanup. However,
since we install this after touching the filesystem, any
errors between our initial mkdir() and our atexit() call
will result in us leaving a crufty directory around.
We can fix this by moving our atexit() call earlier. It's OK
to do it before the junk_work_tree variable is set, because
remove_junk makes sure the variable is initialized. This
means we "activate" the handler by assigning to the
junk_work_tree variable, which we now bump down to just
after we call mkdir(). We probably do not want to do it
before, because a plausible reason for mkdir() to fail is
EEXIST (i.e., we are racing with another "git init"), and we
would not want to remove their work.
OTOH, this is probably not that big a deal; we will allow
cloning into an empty directory (and skip the mkdir), which
is already racy (i.e., one clone may see the other's empty
dir and start writing into it). Still, it does not hurt to
err on the side of caution here.
Note that writing into junk_work_tree and junk_git_dir after
installing the handler is also technically racy, as we call
our handler on an async signal. Depending on the platform,
we could see a sheared write to the variables. Traditionally
we have not worried about this, and indeed we already do
this later in the function. If we want to address that, it
can come as a separate topic.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-03-18 18:55:32 +00:00
|
|
|
atexit(remove_junk);
|
|
|
|
sigchain_push_common(remove_junk_on_signal);
|
|
|
|
|
2008-04-27 17:39:30 +00:00
|
|
|
if (!option_bare) {
|
2008-06-25 05:41:34 +00:00
|
|
|
if (safe_create_leading_directories_const(work_tree) < 0)
|
2011-02-22 23:41:26 +00:00
|
|
|
die_errno(_("could not create leading directories of '%s'"),
|
2009-06-27 15:58:46 +00:00
|
|
|
work_tree);
|
2018-01-02 21:11:39 +00:00
|
|
|
if (dest_exists)
|
|
|
|
junk_work_tree_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
|
|
|
|
else if (mkdir(work_tree, 0777))
|
2015-03-18 19:02:01 +00:00
|
|
|
die_errno(_("could not create work tree dir '%s'"),
|
2009-06-27 15:58:46 +00:00
|
|
|
work_tree);
|
clone: initialize atexit cleanup handler earlier
If clone fails, we generally try to clean up any directories
we've created. We do this by installing an atexit handler,
so that we don't have to manually trigger cleanup. However,
since we install this after touching the filesystem, any
errors between our initial mkdir() and our atexit() call
will result in us leaving a crufty directory around.
We can fix this by moving our atexit() call earlier. It's OK
to do it before the junk_work_tree variable is set, because
remove_junk makes sure the variable is initialized. This
means we "activate" the handler by assigning to the
junk_work_tree variable, which we now bump down to just
after we call mkdir(). We probably do not want to do it
before, because a plausible reason for mkdir() to fail is
EEXIST (i.e., we are racing with another "git init"), and we
would not want to remove their work.
OTOH, this is probably not that big a deal; we will allow
cloning into an empty directory (and skip the mkdir), which
is already racy (i.e., one clone may see the other's empty
dir and start writing into it). Still, it does not hurt to
err on the side of caution here.
Note that writing into junk_work_tree and junk_git_dir after
installing the handler is also technically racy, as we call
our handler on an async signal. Depending on the platform,
we could see a sheared write to the variables. Traditionally
we have not worried about this, and indeed we already do
this later in the function. If we want to address that, it
can come as a separate topic.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-03-18 18:55:32 +00:00
|
|
|
junk_work_tree = work_tree;
|
2008-04-27 17:39:30 +00:00
|
|
|
set_git_work_tree(work_tree);
|
|
|
|
}
|
|
|
|
|
2018-01-02 21:11:39 +00:00
|
|
|
if (real_git_dir) {
|
2019-10-28 16:55:23 +00:00
|
|
|
if (path_exists(real_git_dir))
|
2018-01-02 21:11:39 +00:00
|
|
|
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;
|
|
|
|
}
|
2008-06-25 05:41:34 +00:00
|
|
|
if (safe_create_leading_directories_const(git_dir) < 0)
|
2011-02-22 23:41:26 +00:00
|
|
|
die(_("could not create leading directories of '%s'"), git_dir);
|
2011-03-19 15:16:56 +00:00
|
|
|
|
2011-02-22 23:41:27 +00:00
|
|
|
if (0 <= option_verbosity) {
|
|
|
|
if (option_bare)
|
2013-09-18 20:05:13 +00:00
|
|
|
fprintf(stderr, _("Cloning into bare repository '%s'...\n"), dir);
|
2011-02-22 23:41:27 +00:00
|
|
|
else
|
2013-09-18 20:05:13 +00:00
|
|
|
fprintf(stderr, _("Cloning into '%s'...\n"), dir);
|
2011-02-22 23:41:27 +00:00
|
|
|
}
|
2016-08-17 22:45:35 +00:00
|
|
|
|
2017-03-17 22:38:03 +00:00
|
|
|
if (option_recurse_submodules.nr > 0) {
|
|
|
|
struct string_list_item *item;
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
|
|
|
|
/* remove duplicates */
|
|
|
|
string_list_sort(&option_recurse_submodules);
|
|
|
|
string_list_remove_duplicates(&option_recurse_submodules, 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NEEDSWORK: In a multi-working-tree world, this needs to be
|
|
|
|
* set in the per-worktree config.
|
|
|
|
*/
|
|
|
|
for_each_string_list_item(item, &option_recurse_submodules) {
|
|
|
|
strbuf_addf(&sb, "submodule.active=%s",
|
|
|
|
item->string);
|
|
|
|
string_list_append(&option_config,
|
|
|
|
strbuf_detach(&sb, NULL));
|
|
|
|
}
|
|
|
|
|
2016-08-17 22:45:35 +00:00
|
|
|
if (option_required_reference.nr &&
|
|
|
|
option_optional_reference.nr)
|
|
|
|
die(_("clone --recursive is not compatible with "
|
|
|
|
"both --reference and --reference-if-able"));
|
|
|
|
else if (option_required_reference.nr) {
|
|
|
|
string_list_append(&option_config,
|
|
|
|
"submodule.alternateLocation=superproject");
|
|
|
|
string_list_append(&option_config,
|
|
|
|
"submodule.alternateErrorStrategy=die");
|
|
|
|
} else if (option_optional_reference.nr) {
|
|
|
|
string_list_append(&option_config,
|
|
|
|
"submodule.alternateLocation=superproject");
|
|
|
|
string_list_append(&option_config,
|
|
|
|
"submodule.alternateErrorStrategy=info");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-22 20:17:38 +00:00
|
|
|
init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, INIT_DB_QUIET);
|
2016-09-25 03:14:37 +00:00
|
|
|
|
|
|
|
if (real_git_dir)
|
|
|
|
git_dir = real_git_dir;
|
|
|
|
|
2011-06-09 20:56:19 +00:00
|
|
|
write_config(&option_config);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2008-05-25 21:25:02 +00:00
|
|
|
git_config(git_default_config, NULL);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
|
|
|
if (option_bare) {
|
2008-08-02 19:38:56 +00:00
|
|
|
if (option_mirror)
|
|
|
|
src_ref_prefix = "refs/";
|
2008-11-21 00:45:01 +00:00
|
|
|
strbuf_addstr(&branch_top, src_ref_prefix);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
|
|
|
git_config_set("core.bare", "true");
|
|
|
|
} else {
|
2008-11-21 00:45:01 +00:00
|
|
|
strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin);
|
2008-08-02 19:38:56 +00:00
|
|
|
}
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2010-03-29 16:48:24 +00:00
|
|
|
strbuf_addf(&key, "remote.%s.url", option_origin);
|
|
|
|
git_config_set(key.buf, repo);
|
|
|
|
strbuf_reset(&key);
|
|
|
|
|
2017-04-26 23:12:33 +00:00
|
|
|
if (option_no_tags) {
|
|
|
|
strbuf_addf(&key, "remote.%s.tagOpt", option_origin);
|
|
|
|
git_config_set(key.buf, "--no-tags");
|
|
|
|
strbuf_reset(&key);
|
|
|
|
}
|
|
|
|
|
2016-08-15 21:53:26 +00:00
|
|
|
if (option_required_reference.nr || option_optional_reference.nr)
|
2011-08-23 01:05:15 +00:00
|
|
|
setup_reference();
|
2010-03-29 16:48:23 +00:00
|
|
|
|
2020-01-24 21:19:34 +00:00
|
|
|
if (option_sparse_checkout && git_sparse_checkout_init(dir))
|
2019-11-21 22:04:35 +00:00
|
|
|
return 1;
|
|
|
|
|
clone: respect additional configured fetch refspecs during initial fetch
The initial fetch during a clone doesn't transfer refs matching
additional fetch refspecs given on the command line as configuration
variables, e.g. '-c remote.origin.fetch=<refspec>'. This contradicts
the documentation stating that configuration variables specified via
'git clone -c <key>=<value> ...' "take effect immediately after the
repository is initialized, but before the remote history is fetched"
and the given example specifically mentions "adding additional fetch
refspecs to the origin remote". Furthermore, one-shot configuration
variables specified via 'git -c <key>=<value> clone ...', though not
written to the newly created repository's config file, live during the
lifetime of the 'clone' command, including the initial fetch. All
this implies that any fetch refspecs specified this way should already
be taken into account during the initial fetch.
The reason for this is that the initial fetch is not a fully fledged
'git fetch' but a bunch of direct calls into the fetch/transport
machinery with clone's own refs-to-refspec matching logic, which
bypasses parts of 'git fetch' processing configured fetch refspecs.
This logic only considers a single default refspec, potentially
influenced by options like '--single-branch' and '--mirror'. The
configured refspecs are, however, already read and parsed properly
when clone calls remote.c:remote_get(), but it never looks at the
parsed refspecs in the resulting 'struct remote'.
Modify clone to take the remote's configured fetch refspecs into
account to retrieve all matching refs during the initial fetch. Note
that we have to explicitly add the default fetch refspec to the
remote's refspecs, because at that point the remote only includes the
fetch refspecs specified on the command line.
Add tests to check that refspecs given both via 'git clone -c ...' and
'git -c ... clone' retrieve all refs matching either the default or
the additional refspecs, and that it works even when the user
specifies an alternative remote name via '--origin=<name>'.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Reviewed-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-14 10:46:19 +00:00
|
|
|
remote = remote_get(option_origin);
|
2009-03-06 04:56:16 +00:00
|
|
|
|
2018-11-14 10:46:18 +00:00
|
|
|
strbuf_addf(&default_refspec, "+%s*:%s*", src_ref_prefix,
|
|
|
|
branch_top.buf);
|
clone: respect additional configured fetch refspecs during initial fetch
The initial fetch during a clone doesn't transfer refs matching
additional fetch refspecs given on the command line as configuration
variables, e.g. '-c remote.origin.fetch=<refspec>'. This contradicts
the documentation stating that configuration variables specified via
'git clone -c <key>=<value> ...' "take effect immediately after the
repository is initialized, but before the remote history is fetched"
and the given example specifically mentions "adding additional fetch
refspecs to the origin remote". Furthermore, one-shot configuration
variables specified via 'git -c <key>=<value> clone ...', though not
written to the newly created repository's config file, live during the
lifetime of the 'clone' command, including the initial fetch. All
this implies that any fetch refspecs specified this way should already
be taken into account during the initial fetch.
The reason for this is that the initial fetch is not a fully fledged
'git fetch' but a bunch of direct calls into the fetch/transport
machinery with clone's own refs-to-refspec matching logic, which
bypasses parts of 'git fetch' processing configured fetch refspecs.
This logic only considers a single default refspec, potentially
influenced by options like '--single-branch' and '--mirror'. The
configured refspecs are, however, already read and parsed properly
when clone calls remote.c:remote_get(), but it never looks at the
parsed refspecs in the resulting 'struct remote'.
Modify clone to take the remote's configured fetch refspecs into
account to retrieve all matching refs during the initial fetch. Note
that we have to explicitly add the default fetch refspec to the
remote's refspecs, because at that point the remote only includes the
fetch refspecs specified on the command line.
Add tests to check that refspecs given both via 'git clone -c ...' and
'git -c ... clone' retrieve all refs matching either the default or
the additional refspecs, and that it works even when the user
specifies an alternative remote name via '--origin=<name>'.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Reviewed-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-14 10:46:19 +00:00
|
|
|
refspec_append(&remote->fetch, default_refspec.buf);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2012-01-16 09:46:12 +00:00
|
|
|
transport = transport_get(remote, remote->url[0]);
|
2015-05-12 04:30:16 +00:00
|
|
|
transport_set_verbosity(transport, option_verbosity, option_progress);
|
2016-02-03 04:09:14 +00:00
|
|
|
transport->family = family;
|
2015-05-12 04:30:16 +00:00
|
|
|
|
2014-07-17 07:09:32 +00:00
|
|
|
path = get_repo_path(remote->url[0], &is_bundle);
|
|
|
|
is_local = option_local != 0 && path && !is_bundle;
|
|
|
|
if (is_local) {
|
|
|
|
if (option_depth)
|
|
|
|
warning(_("--depth is ignored in local clones; use file:// instead."));
|
2016-06-12 10:54:00 +00:00
|
|
|
if (option_since)
|
|
|
|
warning(_("--shallow-since is ignored in local clones; use file:// instead."));
|
2016-06-12 10:54:05 +00:00
|
|
|
if (option_not.nr)
|
|
|
|
warning(_("--shallow-exclude is ignored in local clones; use file:// instead."));
|
2017-12-08 15:58:46 +00:00
|
|
|
if (filter_options.choice)
|
|
|
|
warning(_("--filter is ignored in local clones; use file:// instead."));
|
2014-07-17 07:09:32 +00:00
|
|
|
if (!access(mkpath("%s/shallow", path), F_OK)) {
|
|
|
|
if (option_local > 0)
|
|
|
|
warning(_("source repository is shallow, ignoring --local"));
|
|
|
|
is_local = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (option_local > 0 && !is_local)
|
|
|
|
warning(_("--local is ignored"));
|
2013-12-05 13:02:39 +00:00
|
|
|
transport->cloning = 1;
|
2008-04-27 17:39:30 +00:00
|
|
|
|
clone: always set transport options
A clone will always create a transport struct, whether we
are cloning locally or using an actual protocol. In the
local case, we only use the transport to get the list of
refs, and then transfer the objects out-of-band.
However, there are many options that we do not bother
setting up in the local case. For the most part, these are
noops, because they only affect the object-fetching stage
(e.g., the --depth option). However, some options do have a
visible impact. For example, giving the path to upload-pack
via "-u" does not currently work for a local clone, even
though we need upload-pack to get the ref list.
We can just drop the conditional entirely and set these
options for both local and non-local clones. Rather than
keep track of which options impact the object versus the ref
fetching stage, we can simply let the noops be noops (and
the cost of setting the options in the first place is not
high).
The one exception is that we also check that the transport
provides both a "get_refs_list" and a "fetch" method. We
will now be checking the former for both cases (which is
good, since a transport that cannot fetch refs would not
work for a local clone), and we tweak the conditional to
check for a "fetch" only when we are non-local.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-09-18 20:35:13 +00:00
|
|
|
transport_set_option(transport, TRANS_OPT_KEEP, "yes");
|
2008-04-27 17:39:30 +00:00
|
|
|
|
clone: always set transport options
A clone will always create a transport struct, whether we
are cloning locally or using an actual protocol. In the
local case, we only use the transport to get the list of
refs, and then transfer the objects out-of-band.
However, there are many options that we do not bother
setting up in the local case. For the most part, these are
noops, because they only affect the object-fetching stage
(e.g., the --depth option). However, some options do have a
visible impact. For example, giving the path to upload-pack
via "-u" does not currently work for a local clone, even
though we need upload-pack to get the ref list.
We can just drop the conditional entirely and set these
options for both local and non-local clones. Rather than
keep track of which options impact the object versus the ref
fetching stage, we can simply let the noops be noops (and
the cost of setting the options in the first place is not
high).
The one exception is that we also check that the transport
provides both a "get_refs_list" and a "fetch" method. We
will now be checking the former for both cases (which is
good, since a transport that cannot fetch refs would not
work for a local clone), and we tweak the conditional to
check for a "fetch" only when we are non-local.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-09-18 20:35:13 +00:00
|
|
|
if (option_depth)
|
|
|
|
transport_set_option(transport, TRANS_OPT_DEPTH,
|
|
|
|
option_depth);
|
2016-06-12 10:54:00 +00:00
|
|
|
if (option_since)
|
|
|
|
transport_set_option(transport, TRANS_OPT_DEEPEN_SINCE,
|
|
|
|
option_since);
|
2016-06-12 10:54:05 +00:00
|
|
|
if (option_not.nr)
|
|
|
|
transport_set_option(transport, TRANS_OPT_DEEPEN_NOT,
|
|
|
|
(const char *)&option_not);
|
clone: always set transport options
A clone will always create a transport struct, whether we
are cloning locally or using an actual protocol. In the
local case, we only use the transport to get the list of
refs, and then transfer the objects out-of-band.
However, there are many options that we do not bother
setting up in the local case. For the most part, these are
noops, because they only affect the object-fetching stage
(e.g., the --depth option). However, some options do have a
visible impact. For example, giving the path to upload-pack
via "-u" does not currently work for a local clone, even
though we need upload-pack to get the ref list.
We can just drop the conditional entirely and set these
options for both local and non-local clones. Rather than
keep track of which options impact the object versus the ref
fetching stage, we can simply let the noops be noops (and
the cost of setting the options in the first place is not
high).
The one exception is that we also check that the transport
provides both a "get_refs_list" and a "fetch" method. We
will now be checking the former for both cases (which is
good, since a transport that cannot fetch refs would not
work for a local clone), and we tweak the conditional to
check for a "fetch" only when we are non-local.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-09-18 20:35:13 +00:00
|
|
|
if (option_single_branch)
|
|
|
|
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
|
2008-04-27 17:39:30 +00:00
|
|
|
|
clone: always set transport options
A clone will always create a transport struct, whether we
are cloning locally or using an actual protocol. In the
local case, we only use the transport to get the list of
refs, and then transfer the objects out-of-band.
However, there are many options that we do not bother
setting up in the local case. For the most part, these are
noops, because they only affect the object-fetching stage
(e.g., the --depth option). However, some options do have a
visible impact. For example, giving the path to upload-pack
via "-u" does not currently work for a local clone, even
though we need upload-pack to get the ref list.
We can just drop the conditional entirely and set these
options for both local and non-local clones. Rather than
keep track of which options impact the object versus the ref
fetching stage, we can simply let the noops be noops (and
the cost of setting the options in the first place is not
high).
The one exception is that we also check that the transport
provides both a "get_refs_list" and a "fetch" method. We
will now be checking the former for both cases (which is
good, since a transport that cannot fetch refs would not
work for a local clone), and we tweak the conditional to
check for a "fetch" only when we are non-local.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-09-18 20:35:13 +00:00
|
|
|
if (option_upload_pack)
|
|
|
|
transport_set_option(transport, TRANS_OPT_UPLOADPACK,
|
|
|
|
option_upload_pack);
|
2013-05-26 01:16:17 +00:00
|
|
|
|
2019-04-12 19:51:22 +00:00
|
|
|
if (server_options.nr)
|
|
|
|
transport->server_options = &server_options;
|
|
|
|
|
2017-12-08 15:58:46 +00:00
|
|
|
if (filter_options.choice) {
|
2019-06-27 22:54:10 +00:00
|
|
|
const char *spec =
|
|
|
|
expand_list_objects_filter_spec(&filter_options);
|
2017-12-08 15:58:46 +00:00
|
|
|
transport_set_option(transport, TRANS_OPT_LIST_OBJECTS_FILTER,
|
2019-06-27 22:54:10 +00:00
|
|
|
spec);
|
2017-12-08 15:58:46 +00:00
|
|
|
transport_set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (transport->smart_options && !deepen && !filter_options.choice)
|
clone: always set transport options
A clone will always create a transport struct, whether we
are cloning locally or using an actual protocol. In the
local case, we only use the transport to get the list of
refs, and then transfer the objects out-of-band.
However, there are many options that we do not bother
setting up in the local case. For the most part, these are
noops, because they only affect the object-fetching stage
(e.g., the --depth option). However, some options do have a
visible impact. For example, giving the path to upload-pack
via "-u" does not currently work for a local clone, even
though we need upload-pack to get the ref list.
We can just drop the conditional entirely and set these
options for both local and non-local clones. Rather than
keep track of which options impact the object versus the ref
fetching stage, we can simply let the noops be noops (and
the cost of setting the options in the first place is not
high).
The one exception is that we also check that the transport
provides both a "get_refs_list" and a "fetch" method. We
will now be checking the former for both cases (which is
good, since a transport that cannot fetch refs would not
work for a local clone), and we tweak the conditional to
check for a "fetch" only when we are non-local.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-09-18 20:35:13 +00:00
|
|
|
transport->smart_options->check_self_contained_and_connected = 1;
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2018-07-20 22:07:54 +00:00
|
|
|
|
|
|
|
argv_array_push(&ref_prefixes, "HEAD");
|
clone: respect additional configured fetch refspecs during initial fetch
The initial fetch during a clone doesn't transfer refs matching
additional fetch refspecs given on the command line as configuration
variables, e.g. '-c remote.origin.fetch=<refspec>'. This contradicts
the documentation stating that configuration variables specified via
'git clone -c <key>=<value> ...' "take effect immediately after the
repository is initialized, but before the remote history is fetched"
and the given example specifically mentions "adding additional fetch
refspecs to the origin remote". Furthermore, one-shot configuration
variables specified via 'git -c <key>=<value> clone ...', though not
written to the newly created repository's config file, live during the
lifetime of the 'clone' command, including the initial fetch. All
this implies that any fetch refspecs specified this way should already
be taken into account during the initial fetch.
The reason for this is that the initial fetch is not a fully fledged
'git fetch' but a bunch of direct calls into the fetch/transport
machinery with clone's own refs-to-refspec matching logic, which
bypasses parts of 'git fetch' processing configured fetch refspecs.
This logic only considers a single default refspec, potentially
influenced by options like '--single-branch' and '--mirror'. The
configured refspecs are, however, already read and parsed properly
when clone calls remote.c:remote_get(), but it never looks at the
parsed refspecs in the resulting 'struct remote'.
Modify clone to take the remote's configured fetch refspecs into
account to retrieve all matching refs during the initial fetch. Note
that we have to explicitly add the default fetch refspec to the
remote's refspecs, because at that point the remote only includes the
fetch refspecs specified on the command line.
Add tests to check that refspecs given both via 'git clone -c ...' and
'git -c ... clone' retrieve all refs matching either the default or
the additional refspecs, and that it works even when the user
specifies an alternative remote name via '--origin=<name>'.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Reviewed-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-14 10:46:19 +00:00
|
|
|
refspec_ref_prefixes(&remote->fetch, &ref_prefixes);
|
2018-07-20 22:07:54 +00:00
|
|
|
if (option_branch)
|
|
|
|
expand_ref_prefix(&ref_prefixes, option_branch);
|
|
|
|
if (!option_no_tags)
|
|
|
|
argv_array_push(&ref_prefixes, "refs/tags/");
|
|
|
|
|
|
|
|
refs = transport_get_remote_refs(transport, &ref_prefixes);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2012-02-11 06:20:56 +00:00
|
|
|
if (refs) {
|
clone: respect additional configured fetch refspecs during initial fetch
The initial fetch during a clone doesn't transfer refs matching
additional fetch refspecs given on the command line as configuration
variables, e.g. '-c remote.origin.fetch=<refspec>'. This contradicts
the documentation stating that configuration variables specified via
'git clone -c <key>=<value> ...' "take effect immediately after the
repository is initialized, but before the remote history is fetched"
and the given example specifically mentions "adding additional fetch
refspecs to the origin remote". Furthermore, one-shot configuration
variables specified via 'git -c <key>=<value> clone ...', though not
written to the newly created repository's config file, live during the
lifetime of the 'clone' command, including the initial fetch. All
this implies that any fetch refspecs specified this way should already
be taken into account during the initial fetch.
The reason for this is that the initial fetch is not a fully fledged
'git fetch' but a bunch of direct calls into the fetch/transport
machinery with clone's own refs-to-refspec matching logic, which
bypasses parts of 'git fetch' processing configured fetch refspecs.
This logic only considers a single default refspec, potentially
influenced by options like '--single-branch' and '--mirror'. The
configured refspecs are, however, already read and parsed properly
when clone calls remote.c:remote_get(), but it never looks at the
parsed refspecs in the resulting 'struct remote'.
Modify clone to take the remote's configured fetch refspecs into
account to retrieve all matching refs during the initial fetch. Note
that we have to explicitly add the default fetch refspec to the
remote's refspecs, because at that point the remote only includes the
fetch refspecs specified on the command line.
Add tests to check that refspecs given both via 'git clone -c ...' and
'git -c ... clone' retrieve all refs matching either the default or
the additional refspecs, and that it works even when the user
specifies an alternative remote name via '--origin=<name>'.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Reviewed-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-14 10:46:19 +00:00
|
|
|
mapped_refs = wanted_peer_refs(refs, &remote->fetch);
|
2012-02-11 06:20:56 +00:00
|
|
|
/*
|
|
|
|
* transport_get_remote_refs() may return refs with null sha-1
|
|
|
|
* in mapped_refs (see struct transport->get_refs_list
|
|
|
|
* comment). In that case we need fetch it early because
|
|
|
|
* remote_head code below relies on it.
|
|
|
|
*
|
|
|
|
* for normal clones, transport_get_remote_refs() should
|
|
|
|
* return reliable ref set, we can delay cloning until after
|
|
|
|
* remote HEAD check.
|
|
|
|
*/
|
|
|
|
for (ref = refs; ref; ref = ref->next)
|
2015-11-10 02:22:20 +00:00
|
|
|
if (is_null_oid(&ref->old_oid)) {
|
2012-02-11 06:20:56 +00:00
|
|
|
complete_refs_before_fetch = 0;
|
|
|
|
break;
|
|
|
|
}
|
2012-01-24 11:10:38 +00:00
|
|
|
|
2012-02-11 06:20:56 +00:00
|
|
|
if (!is_local && !complete_refs_before_fetch)
|
fetch-pack: unify ref in and out param
When a user fetches:
- at least one up-to-date ref and at least one non-up-to-date ref,
- using HTTP with protocol v0 (or something else that uses the fetch
command of a remote helper)
some refs might not be updated after the fetch.
This bug was introduced in commit 989b8c4452 ("fetch-pack: put shallow
info in output parameter", 2018-06-28) which allowed transports to
report the refs that they have fetched in a new out-parameter
"fetched_refs". If they do so, transport_fetch_refs() makes this
information available to its caller.
Users of "fetched_refs" rely on the following 3 properties:
(1) it is the complete list of refs that was passed to
transport_fetch_refs(),
(2) it has shallow information (REF_STATUS_REJECT_SHALLOW set if
relevant), and
(3) it has updated OIDs if ref-in-want was used (introduced after
989b8c4452).
In an effort to satisfy (1), whenever transport_fetch_refs()
filters the refs sent to the transport, it re-adds the filtered refs to
whatever the transport supplies before returning it to the user.
However, the implementation in 989b8c4452 unconditionally re-adds the
filtered refs without checking if the transport refrained from reporting
anything in "fetched_refs" (which it is allowed to do), resulting in an
incomplete list, no longer satisfying (1).
An earlier effort to resolve this [1] solved the issue by readding the
filtered refs only if the transport did not refrain from reporting in
"fetched_refs", but after further discussion, it seems that the better
solution is to revert the API change that introduced "fetched_refs".
This API change was first suggested as part of a ref-in-want
implementation that allowed for ref patterns and, thus, there could be
drastic differences between the input refs and the refs actually fetched
[2]; we eventually decided to only allow exact ref names, but this API
change remained even though its necessity was decreased.
Therefore, revert this API change by reverting commit 989b8c4452, and
make receive_wanted_refs() update the OIDs in the sought array (like how
update_shallow() updates shallow information in the sought array)
instead. A test is also included to show that the user-visible bug
discussed at the beginning of this commit message no longer exists.
[1] https://public-inbox.org/git/20180801171806.GA122458@google.com/
[2] https://public-inbox.org/git/86a128c5fb710a41791e7183207c4d64889f9307.1485381677.git.jonathantanmy@google.com/
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-01 20:13:20 +00:00
|
|
|
transport_fetch_refs(transport, mapped_refs);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2009-02-25 08:32:14 +00:00
|
|
|
remote_head = find_ref_by_name(refs, "HEAD");
|
2009-08-26 19:05:08 +00:00
|
|
|
remote_head_points_at =
|
|
|
|
guess_remote_head(remote_head, mapped_refs, 0);
|
|
|
|
|
|
|
|
if (option_branch) {
|
|
|
|
our_head_points_at =
|
2012-01-16 09:46:13 +00:00
|
|
|
find_remote_branch(mapped_refs, option_branch);
|
2009-08-26 19:05:08 +00:00
|
|
|
|
2012-01-16 09:46:14 +00:00
|
|
|
if (!our_head_points_at)
|
|
|
|
die(_("Remote branch %s not found in upstream %s"),
|
|
|
|
option_branch, option_origin);
|
2009-08-26 19:05:08 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
our_head_points_at = remote_head_points_at;
|
2009-01-23 00:07:32 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-10-11 16:49:02 +00:00
|
|
|
if (option_branch)
|
|
|
|
die(_("Remote branch %s not found in upstream %s"),
|
|
|
|
option_branch, option_origin);
|
|
|
|
|
2011-02-22 23:41:26 +00:00
|
|
|
warning(_("You appear to have cloned an empty repository."));
|
2012-02-11 06:20:56 +00:00
|
|
|
mapped_refs = NULL;
|
2009-08-26 19:05:08 +00:00
|
|
|
our_head_points_at = NULL;
|
|
|
|
remote_head_points_at = NULL;
|
2009-01-23 00:07:32 +00:00
|
|
|
remote_head = NULL;
|
|
|
|
option_no_checkout = 1;
|
2009-02-12 06:42:27 +00:00
|
|
|
if (!option_bare)
|
2009-03-04 06:29:55 +00:00
|
|
|
install_branch_config(0, "master", option_origin,
|
2009-02-12 06:42:27 +00:00
|
|
|
"refs/heads/master");
|
2009-01-23 00:07:32 +00:00
|
|
|
}
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2012-09-20 18:04:08 +00:00
|
|
|
write_refspec_config(src_ref_prefix, our_head_points_at,
|
|
|
|
remote_head_points_at, &branch_top);
|
|
|
|
|
2017-12-08 15:58:46 +00:00
|
|
|
if (filter_options.choice)
|
2019-05-29 21:26:43 +00:00
|
|
|
partial_clone_register(option_origin, &filter_options);
|
2017-12-08 15:58:46 +00:00
|
|
|
|
2012-01-16 09:46:12 +00:00
|
|
|
if (is_local)
|
|
|
|
clone_local(path, git_dir);
|
2012-01-24 11:10:38 +00:00
|
|
|
else if (refs && complete_refs_before_fetch)
|
fetch-pack: unify ref in and out param
When a user fetches:
- at least one up-to-date ref and at least one non-up-to-date ref,
- using HTTP with protocol v0 (or something else that uses the fetch
command of a remote helper)
some refs might not be updated after the fetch.
This bug was introduced in commit 989b8c4452 ("fetch-pack: put shallow
info in output parameter", 2018-06-28) which allowed transports to
report the refs that they have fetched in a new out-parameter
"fetched_refs". If they do so, transport_fetch_refs() makes this
information available to its caller.
Users of "fetched_refs" rely on the following 3 properties:
(1) it is the complete list of refs that was passed to
transport_fetch_refs(),
(2) it has shallow information (REF_STATUS_REJECT_SHALLOW set if
relevant), and
(3) it has updated OIDs if ref-in-want was used (introduced after
989b8c4452).
In an effort to satisfy (1), whenever transport_fetch_refs()
filters the refs sent to the transport, it re-adds the filtered refs to
whatever the transport supplies before returning it to the user.
However, the implementation in 989b8c4452 unconditionally re-adds the
filtered refs without checking if the transport refrained from reporting
anything in "fetched_refs" (which it is allowed to do), resulting in an
incomplete list, no longer satisfying (1).
An earlier effort to resolve this [1] solved the issue by readding the
filtered refs only if the transport did not refrain from reporting in
"fetched_refs", but after further discussion, it seems that the better
solution is to revert the API change that introduced "fetched_refs".
This API change was first suggested as part of a ref-in-want
implementation that allowed for ref patterns and, thus, there could be
drastic differences between the input refs and the refs actually fetched
[2]; we eventually decided to only allow exact ref names, but this API
change remained even though its necessity was decreased.
Therefore, revert this API change by reverting commit 989b8c4452, and
make receive_wanted_refs() update the OIDs in the sought array (like how
update_shallow() updates shallow information in the sought array)
instead. A test is also included to show that the user-visible bug
discussed at the beginning of this commit message no longer exists.
[1] https://public-inbox.org/git/20180801171806.GA122458@google.com/
[2] https://public-inbox.org/git/86a128c5fb710a41791e7183207c4d64889f9307.1485381677.git.jonathantanmy@google.com/
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-01 20:13:20 +00:00
|
|
|
transport_fetch_refs(transport, mapped_refs);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2012-01-16 09:46:11 +00:00
|
|
|
update_remote_refs(refs, mapped_refs, remote_head_points_at,
|
2017-12-08 15:58:46 +00:00
|
|
|
branch_top.buf, reflog_msg.buf, transport,
|
connected: always use partial clone optimization
With 50033772d5 ("connected: verify promisor-ness of partial clone",
2020-01-30), the fast path (checking promisor packs) in
check_connected() now passes a subset of the slow path (rev-list) - if
all objects to be checked are found in promisor packs, both the fast
path and the slow path will pass; otherwise, the fast path will
definitely not pass. This means that we can always attempt the fast path
whenever we need to do the slow path.
The fast path is currently guarded by a flag; therefore, remove that
flag. Also, make the fast path fallback to the slow path - if the fast
path fails, the failing OID and all remaining OIDs will be passed to
rev-list.
The main user-visible benefit is the performance of fetch from a partial
clone - specifically, the speedup of the connectivity check done before
the fetch. In particular, a no-op fetch into a partial clone on my
computer was sped up from 7 seconds to 0.01 seconds. This is a
complement to the work in 2df1aa239c ("fetch: forgo full
connectivity check if --filter", 2020-01-30), which is the child of the
aforementioned 50033772d5. In that commit, the connectivity check
*after* the fetch was sped up.
The addition of the fast path might cause performance reductions in
these cases:
- If a partial clone or a fetch into a partial clone fails, Git will
fruitlessly run rev-list (it is expected that everything fetched
would go into promisor packs, so if that didn't happen, it is most
likely that rev-list will fail too).
- Any connectivity checks done by receive-pack, in the (in my opinion,
unlikely) event that a partial clone serves receive-pack.
I think that these cases are rare enough, and the performance reduction
in this case minor enough (additional object DB access), that the
benefit of avoiding a flag outweighs these.
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Reviewed-by: Josh Steadmon <steadmon@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-20 22:00:45 +00:00
|
|
|
!is_local);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2012-01-16 09:46:10 +00:00
|
|
|
update_head(our_head_points_at, remote_head, reflog_msg.buf);
|
2008-07-08 04:46:06 +00:00
|
|
|
|
clone: pass --progress decision to recursive submodules
When cloning with "--recursive", we'd generally expect
submodules to show progress reports if the main clone did,
too.
In older versions of git, this mostly worked out of the
box. Since we show progress by default when stderr is a tty,
and since the child clones inherit the parent stderr, then
both processes would come to the same decision by default.
If the parent clone was asked for "--quiet", we passed down
"--quiet" to the child. However, if stderr was not a tty and
the user specified "--progress", we did not propagate this
to the child.
That's a minor bug, but things got much worse when we
switched recently to submodule--helper's update_clone
command. With that change, the stderr of the child clones
are always connected to a pipe, and we never output
progress at all.
This patch teaches git-submodule and git-submodule--helper
how to pass down an explicit "--progress" flag when cloning.
The clone command then decides to propagate that flag based
on the cloning decision made earlier (which takes into
account isatty(2) of the parent process, existing --progress
or --quiet flags, etc). Since the child processes always run
without a tty on stderr, we don't have to worry about
passing an explicit "--no-progress"; it's the default for
them.
This fixes the recent loss of progress during recursive
clones. And as a bonus, it makes:
git clone --recursive --progress ... 2>&1 | cat
work by triggering progress explicitly in the children.
Signed-off-by: Jeff King <peff@peff.net>
Acked-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-09-22 05:24:46 +00:00
|
|
|
/*
|
|
|
|
* We want to show progress for recursive submodule clones iff
|
|
|
|
* we did so for the main clone. But only the transport knows
|
|
|
|
* the final decision for this flag, so we need to rescue the value
|
|
|
|
* before we free the transport.
|
|
|
|
*/
|
|
|
|
submodule_progress = transport->progress;
|
|
|
|
|
2012-01-16 09:46:12 +00:00
|
|
|
transport_unlock_pack(transport);
|
|
|
|
transport_disconnect(transport);
|
2008-07-08 04:46:06 +00:00
|
|
|
|
2015-10-06 13:18:47 +00:00
|
|
|
if (option_dissociate) {
|
2019-05-17 18:41:49 +00:00
|
|
|
close_object_store(the_repository->objects);
|
2014-10-14 19:38:52 +00:00
|
|
|
dissociate_from_references();
|
2015-10-06 13:18:47 +00:00
|
|
|
}
|
2014-10-14 19:38:52 +00:00
|
|
|
|
2013-03-26 22:22:09 +00:00
|
|
|
junk_mode = JUNK_LEAVE_REPO;
|
clone: pass --progress decision to recursive submodules
When cloning with "--recursive", we'd generally expect
submodules to show progress reports if the main clone did,
too.
In older versions of git, this mostly worked out of the
box. Since we show progress by default when stderr is a tty,
and since the child clones inherit the parent stderr, then
both processes would come to the same decision by default.
If the parent clone was asked for "--quiet", we passed down
"--quiet" to the child. However, if stderr was not a tty and
the user specified "--progress", we did not propagate this
to the child.
That's a minor bug, but things got much worse when we
switched recently to submodule--helper's update_clone
command. With that change, the stderr of the child clones
are always connected to a pipe, and we never output
progress at all.
This patch teaches git-submodule and git-submodule--helper
how to pass down an explicit "--progress" flag when cloning.
The clone command then decides to propagate that flag based
on the cloning decision made earlier (which takes into
account isatty(2) of the parent process, existing --progress
or --quiet flags, etc). Since the child processes always run
without a tty on stderr, we don't have to worry about
passing an explicit "--no-progress"; it's the default for
them.
This fixes the recent loss of progress during recursive
clones. And as a bonus, it makes:
git clone --recursive --progress ... 2>&1 | cat
work by triggering progress explicitly in the children.
Signed-off-by: Jeff King <peff@peff.net>
Acked-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-09-22 05:24:46 +00:00
|
|
|
err = checkout(submodule_progress);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
|
|
|
strbuf_release(&reflog_msg);
|
2008-11-21 00:45:01 +00:00
|
|
|
strbuf_release(&branch_top);
|
|
|
|
strbuf_release(&key);
|
2018-11-14 10:46:18 +00:00
|
|
|
strbuf_release(&default_refspec);
|
2013-03-26 22:22:09 +00:00
|
|
|
junk_mode = JUNK_LEAVE_ALL;
|
2014-08-10 13:57:56 +00:00
|
|
|
|
2018-07-20 22:07:54 +00:00
|
|
|
argv_array_clear(&ref_prefixes);
|
2009-03-03 05:37:51 +00:00
|
|
|
return err;
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|