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.
|
|
|
|
*/
|
|
|
|
|
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"
|
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"
|
|
|
|
#include "tree.h"
|
|
|
|
#include "tree-walk.h"
|
|
|
|
#include "unpack-trees.h"
|
|
|
|
#include "transport.h"
|
|
|
|
#include "strbuf.h"
|
|
|
|
#include "dir.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"
|
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;
|
2012-05-30 11:10:16 +00:00
|
|
|
static int option_local = -1, option_no_hardlinks, option_shared, option_recursive;
|
2011-08-23 01:05:15 +00:00
|
|
|
static char *option_template, *option_depth;
|
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;
|
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;
|
2011-06-09 20:56:19 +00:00
|
|
|
static struct string_list option_config;
|
2011-08-23 01:05:15 +00:00
|
|
|
static struct string_list option_reference;
|
2014-10-14 19:38:52 +00:00
|
|
|
static int option_dissociate;
|
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")),
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL(0, "recursive", &option_recursive,
|
2012-08-20 12:32:02 +00:00
|
|
|
N_("initialize submodules in the clone")),
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL(0, "recurse-submodules", &option_recursive,
|
2012-08-20 12:32:02 +00:00
|
|
|
N_("initialize submodules in the clone")),
|
|
|
|
OPT_STRING(0, "template", &option_template, N_("template-directory"),
|
|
|
|
N_("directory from which templates will be used")),
|
2015-05-21 04:15:19 +00:00
|
|
|
OPT_STRING_LIST(0, "reference", &option_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")),
|
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")),
|
|
|
|
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")),
|
2008-04-27 17:39:30 +00:00
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
2009-08-19 23:07:43 +00:00
|
|
|
static const char *argv_submodule[] = {
|
|
|
|
"submodule", "update", "--init", "--recursive", NULL
|
|
|
|
};
|
|
|
|
|
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);
|
|
|
|
canon = raw ? xstrdup(absolute_path(raw)) : NULL;
|
|
|
|
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 == '/'))
|
|
|
|
die("No directory name could be guessed.\n"
|
|
|
|
"Please specify a directory on the command line");
|
|
|
|
|
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
|
|
|
{
|
2011-08-23 01:05:16 +00:00
|
|
|
char *ref_git;
|
2013-04-09 22:22:00 +00:00
|
|
|
const char *repo;
|
2011-08-23 01:05:16 +00:00
|
|
|
struct strbuf alternate = STRBUF_INIT;
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2013-04-09 22:22:00 +00:00
|
|
|
/* Beware: read_gitfile(), real_path() and mkpath() return static buffer */
|
2011-08-23 01:05:16 +00:00
|
|
|
ref_git = xstrdup(real_path(item->string));
|
2013-04-09 22:22:00 +00:00
|
|
|
|
|
|
|
repo = read_gitfile(ref_git);
|
|
|
|
if (!repo)
|
|
|
|
repo = read_gitfile(mkpath("%s/.git", ref_git));
|
|
|
|
if (repo) {
|
|
|
|
free(ref_git);
|
|
|
|
ref_git = xstrdup(repo);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!repo && is_directory(mkpath("%s/.git/objects", ref_git))) {
|
2012-09-04 17:31:14 +00:00
|
|
|
char *ref_git_git = mkpathdup("%s/.git", ref_git);
|
2011-08-23 01:05:16 +00:00
|
|
|
free(ref_git);
|
|
|
|
ref_git = ref_git_git;
|
2015-09-28 13:06:16 +00:00
|
|
|
} else if (!is_directory(mkpath("%s/objects", ref_git))) {
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
if (get_common_dir(&sb, ref_git))
|
|
|
|
die(_("reference repository '%s' as a linked checkout is not supported yet."),
|
|
|
|
item->string);
|
2013-04-08 22:46:39 +00:00
|
|
|
die(_("reference repository '%s' is not a local repository."),
|
2011-08-23 01:05:15 +00:00
|
|
|
item->string);
|
2015-09-28 13:06:16 +00:00
|
|
|
}
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2013-12-05 13:02:31 +00:00
|
|
|
if (!access(mkpath("%s/shallow", ref_git), F_OK))
|
|
|
|
die(_("reference repository '%s' is shallow"), item->string);
|
|
|
|
|
|
|
|
if (!access(mkpath("%s/info/grafts", ref_git), F_OK))
|
|
|
|
die(_("reference repository '%s' is grafted"), item->string);
|
|
|
|
|
2011-08-23 01:05:16 +00:00
|
|
|
strbuf_addf(&alternate, "%s/objects", ref_git);
|
|
|
|
add_to_alternates_file(alternate.buf);
|
|
|
|
strbuf_release(&alternate);
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
for_each_string_list(&option_reference, add_one_reference, NULL);
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|
|
|
|
|
2011-08-23 01:05:16 +00:00
|
|
|
static void copy_alternates(struct strbuf *src, struct strbuf *dst,
|
|
|
|
const char *src_repo)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
FILE *in = fopen(src->buf, "r");
|
|
|
|
struct strbuf line = STRBUF_INIT;
|
|
|
|
|
|
|
|
while (strbuf_getline(&line, in, '\n') != 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);
|
|
|
|
normalize_path_copy(abs_path, abs_path);
|
|
|
|
add_to_alternates_file(abs_path);
|
|
|
|
free(abs_path);
|
2011-08-23 01:05:16 +00:00
|
|
|
}
|
|
|
|
strbuf_release(&line);
|
|
|
|
fclose(in);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
|
|
|
|
const char *src_repo, int src_baselen)
|
2008-04-27 17:39:30 +00:00
|
|
|
{
|
|
|
|
struct dirent *de;
|
|
|
|
struct stat buf;
|
|
|
|
int src_len, dest_len;
|
|
|
|
DIR *dir;
|
|
|
|
|
2008-11-21 00:45:00 +00:00
|
|
|
dir = opendir(src->buf);
|
2008-04-27 17:39:30 +00:00
|
|
|
if (!dir)
|
2011-02-22 23:41:26 +00:00
|
|
|
die_errno(_("failed to open '%s'"), src->buf);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2008-11-21 00:45:00 +00:00
|
|
|
if (mkdir(dest->buf, 0777)) {
|
2008-04-27 17:39:30 +00:00
|
|
|
if (errno != EEXIST)
|
2011-02-22 23:41:26 +00:00
|
|
|
die_errno(_("failed to create directory '%s'"), dest->buf);
|
2008-11-21 00:45:00 +00:00
|
|
|
else if (stat(dest->buf, &buf))
|
2011-02-22 23:41:26 +00:00
|
|
|
die_errno(_("failed to stat '%s'"), dest->buf);
|
2008-04-27 17:39:30 +00:00
|
|
|
else if (!S_ISDIR(buf.st_mode))
|
2011-02-22 23:41:26 +00:00
|
|
|
die(_("%s exists and is not a directory"), dest->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
|
|
|
|
|
|
|
while ((de = readdir(dir)) != NULL) {
|
2008-11-21 00:45:00 +00:00
|
|
|
strbuf_setlen(src, src_len);
|
|
|
|
strbuf_addstr(src, de->d_name);
|
|
|
|
strbuf_setlen(dest, dest_len);
|
|
|
|
strbuf_addstr(dest, de->d_name);
|
|
|
|
if (stat(src->buf, &buf)) {
|
2011-02-22 23:41:26 +00:00
|
|
|
warning (_("failed to stat %s\n"), src->buf);
|
2008-04-27 17:39:30 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (S_ISDIR(buf.st_mode)) {
|
|
|
|
if (de->d_name[0] != '.')
|
2011-08-23 01:05:16 +00:00
|
|
|
copy_or_link_directory(src, dest,
|
|
|
|
src_repo, src_baselen);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Files that cannot be copied bit-for-bit... */
|
|
|
|
if (!strcmp(src->buf + src_baselen, "/info/alternates")) {
|
|
|
|
copy_alternates(src, dest, 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) {
|
2008-11-21 00:45:00 +00:00
|
|
|
if (!link(src->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
|
|
|
}
|
2008-05-18 04:00:01 +00:00
|
|
|
closedir(dir);
|
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;
|
|
|
|
strbuf_addf(&alt, "%s/objects", src_repo);
|
|
|
|
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");
|
2011-08-23 01:05:16 +00:00
|
|
|
copy_or_link_directory(&src, &dest, src_repo, src.len);
|
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;
|
|
|
|
static const char *junk_git_dir;
|
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"
|
|
|
|
"and retry the checkout with 'git checkout -f 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);
|
|
|
|
remove_dir_recursively(&sb, 0);
|
|
|
|
strbuf_reset(&sb);
|
|
|
|
}
|
|
|
|
if (junk_work_tree) {
|
|
|
|
strbuf_addstr(&sb, junk_work_tree);
|
|
|
|
remove_dir_recursively(&sb, 0);
|
|
|
|
strbuf_reset(&sb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
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 {
|
2012-01-07 14:45:59 +00:00
|
|
|
get_fetch_map(remote_head, refspec, &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);
|
|
|
|
}
|
2012-01-07 14:45:59 +00:00
|
|
|
} else
|
|
|
|
get_fetch_map(refs, refspec, &tail, 0);
|
|
|
|
|
|
|
|
if (!option_mirror && !option_single_branch)
|
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;
|
2015-06-22 14:03:01 +00:00
|
|
|
if (ref_transaction_create(t, r->peer_ref->name, r->old_sha1,
|
|
|
|
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;
|
|
|
|
if (!has_sha1_file(ref->old_sha1))
|
|
|
|
continue;
|
|
|
|
update_ref(msg, ref->name, ref->old_sha1,
|
2014-04-07 13:47:56 +00:00
|
|
|
NULL, 0, UPDATE_REFS_DIE_ON_ERR);
|
2012-01-07 14:45:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-25 20:26:27 +00:00
|
|
|
static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
hashcpy(sha1, ref->old_sha1);
|
|
|
|
*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,
|
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
|
|
|
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) {
|
2013-09-18 20:06:50 +00:00
|
|
|
if (transport->progress)
|
2013-09-18 20:05:13 +00:00
|
|
|
fprintf(stderr, _("Checking connectivity... "));
|
2013-07-18 19:48:28 +00:00
|
|
|
if (check_everything_connected_with_transport(iterate_ref_map,
|
|
|
|
0, &rm, transport))
|
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-09-18 20:06:50 +00:00
|
|
|
if (transport->progress)
|
2013-10-18 20:49:51 +00:00
|
|
|
fprintf(stderr, _("done.\n"));
|
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
|
|
|
}
|
2013-03-25 20:26:27 +00:00
|
|
|
|
2012-01-16 09:46:11 +00:00
|
|
|
if (refs) {
|
|
|
|
write_remote_refs(mapped_refs);
|
|
|
|
if (option_single_branch)
|
|
|
|
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");
|
|
|
|
create_symref(head_ref.buf,
|
|
|
|
remote_head_points_at->peer_ref->name,
|
|
|
|
msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 */
|
|
|
|
create_symref("HEAD", our->name, NULL);
|
|
|
|
if (!option_bare) {
|
2014-04-07 13:47:56 +00:00
|
|
|
update_ref(msg, "HEAD", our->old_sha1, NULL, 0,
|
|
|
|
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) {
|
|
|
|
struct commit *c = lookup_commit_reference(our->old_sha1);
|
|
|
|
/* --branch specifies a non-branch (i.e. tags), detach HEAD */
|
|
|
|
update_ref(msg, "HEAD", c->object.sha1,
|
2014-04-07 13:47:56 +00:00
|
|
|
NULL, REF_NODEREF, 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.
|
|
|
|
*/
|
|
|
|
update_ref(msg, "HEAD", remote->old_sha1,
|
2014-04-07 13:47:56 +00:00
|
|
|
NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
|
2012-01-16 09:46:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-16 09:46:09 +00:00
|
|
|
static int checkout(void)
|
|
|
|
{
|
|
|
|
unsigned char sha1[20];
|
|
|
|
char *head;
|
|
|
|
struct lock_file *lock_file;
|
|
|
|
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;
|
|
|
|
|
2014-07-15 19:59:36 +00:00
|
|
|
head = resolve_refdup("HEAD", RESOLVE_REF_READING, sha1, 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)
|
|
|
|
detach_advice(sha1_to_hex(sha1));
|
|
|
|
} 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!"));
|
|
|
|
}
|
|
|
|
free(head);
|
|
|
|
|
|
|
|
/* We need to be in the new work tree for the checkout */
|
|
|
|
setup_work_tree();
|
|
|
|
|
|
|
|
lock_file = xcalloc(1, sizeof(struct lock_file));
|
2014-06-13 12:19:23 +00:00
|
|
|
hold_locked_index(lock_file, 1);
|
2012-01-16 09:46:09 +00:00
|
|
|
|
|
|
|
memset(&opts, 0, sizeof opts);
|
|
|
|
opts.update = 1;
|
|
|
|
opts.merge = 1;
|
|
|
|
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;
|
|
|
|
|
|
|
|
tree = parse_tree_indirect(sha1);
|
|
|
|
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
|
|
|
|
2014-06-13 12:19:23 +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"));
|
|
|
|
|
2014-03-18 10:00:53 +00:00
|
|
|
err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1),
|
|
|
|
sha1_to_hex(sha1), "1", NULL);
|
2012-01-16 09:46:09 +00:00
|
|
|
|
|
|
|
if (!err && option_recursive)
|
|
|
|
err = run_command_v_opt(argv_submodule, RUN_GIT_CMD);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2011-06-09 20:56:19 +00:00
|
|
|
static int write_one_config(const char *key, const char *value, void *data)
|
|
|
|
{
|
|
|
|
return git_config_set_multivar(key, value ? value : "true", "^$", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void write_config(struct string_list *config)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < config->nr; i++) {
|
|
|
|
if (git_config_parse_parameter(config->items[i].string,
|
|
|
|
write_one_config, NULL) < 0)
|
|
|
|
die("unable to write parameters to config file");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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))
|
|
|
|
die("BUG: remote HEAD points at non-head?");
|
|
|
|
|
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 };
|
|
|
|
|
|
|
|
if (run_command_v_opt(argv, RUN_GIT_CMD|RUN_COMMAND_NO_STDIN))
|
|
|
|
die(_("cannot repack to clean up"));
|
|
|
|
if (unlink(git_path("objects/info/alternates")) && errno != ENOENT)
|
|
|
|
die_errno(_("cannot unlink temporary alternates file"));
|
|
|
|
}
|
|
|
|
|
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
|
|
|
struct stat buf;
|
|
|
|
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;
|
2008-11-21 00:45:01 +00:00
|
|
|
struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
|
|
|
|
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;
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2009-03-06 04:56:16 +00:00
|
|
|
struct refspec *refspec;
|
|
|
|
const char *fetch_pattern;
|
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
|
|
|
|
2012-01-07 14:45:59 +00:00
|
|
|
if (option_single_branch == -1)
|
|
|
|
option_single_branch = option_depth ? 1 : 0;
|
|
|
|
|
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)
|
2011-03-17 11:26:46 +00:00
|
|
|
repo = xstrdup(absolute_path(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
|
|
|
|
2009-01-11 12:19:12 +00:00
|
|
|
dest_exists = !stat(dir, &buf);
|
|
|
|
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");
|
|
|
|
if (work_tree && !stat(work_tree, &buf))
|
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);
|
2012-07-07 21:50:30 +00:00
|
|
|
if (!dest_exists && 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);
|
|
|
|
}
|
|
|
|
|
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_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
|
|
|
|
|
|
|
set_git_dir_init(git_dir, real_git_dir, 0);
|
2013-01-05 20:17:04 +00:00
|
|
|
if (real_git_dir) {
|
2011-03-19 15:16:56 +00:00
|
|
|
git_dir = real_git_dir;
|
2013-01-05 20:17:04 +00:00
|
|
|
junk_git_dir = real_git_dir;
|
|
|
|
}
|
2008-04-27 17:39:30 +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
|
|
|
}
|
2010-04-23 12:37:22 +00:00
|
|
|
init_db(option_template, INIT_DB_QUIET);
|
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
|
|
|
|
2009-03-06 04:56:16 +00:00
|
|
|
strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
|
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);
|
|
|
|
|
2011-08-23 01:05:15 +00:00
|
|
|
if (option_reference.nr)
|
|
|
|
setup_reference();
|
2014-10-14 19:38:52 +00:00
|
|
|
else if (option_dissociate) {
|
|
|
|
warning(_("--dissociate given, but there is no --reference"));
|
|
|
|
option_dissociate = 0;
|
|
|
|
}
|
2010-03-29 16:48:23 +00:00
|
|
|
|
2009-03-06 04:56:16 +00:00
|
|
|
fetch_pattern = value.buf;
|
|
|
|
refspec = parse_fetch_refspec(1, &fetch_pattern);
|
|
|
|
|
|
|
|
strbuf_reset(&value);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2012-01-16 09:46:12 +00:00
|
|
|
remote = remote_get(option_origin);
|
|
|
|
transport = transport_get(remote, remote->url[0]);
|
2015-05-12 04:30:16 +00:00
|
|
|
transport_set_verbosity(transport, option_verbosity, option_progress);
|
|
|
|
|
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."));
|
|
|
|
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
|
|
|
if (!transport->get_refs_list || (!is_local && !transport->fetch))
|
|
|
|
die(_("Don't know how to clone %s"), transport->url);
|
2008-05-27 14:28:43 +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);
|
|
|
|
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
|
|
|
|
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 (transport->smart_options && !option_depth)
|
|
|
|
transport->smart_options->check_self_contained_and_connected = 1;
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2012-01-16 09:46:12 +00:00
|
|
|
refs = transport_get_remote_refs(transport);
|
2008-04-27 17:39:30 +00:00
|
|
|
|
2012-02-11 06:20:56 +00:00
|
|
|
if (refs) {
|
|
|
|
mapped_refs = wanted_peer_refs(refs, refspec);
|
|
|
|
/*
|
|
|
|
* 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)
|
|
|
|
if (is_null_sha1(ref->old_sha1)) {
|
|
|
|
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)
|
|
|
|
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);
|
|
|
|
|
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)
|
2012-01-16 09:46:12 +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,
|
2013-07-18 19:48:28 +00:00
|
|
|
branch_top.buf, reflog_msg.buf, transport, !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
|
|
|
|
2012-01-16 09:46:12 +00:00
|
|
|
transport_unlock_pack(transport);
|
|
|
|
transport_disconnect(transport);
|
2008-07-08 04:46:06 +00:00
|
|
|
|
2014-10-14 19:38:52 +00:00
|
|
|
if (option_dissociate)
|
|
|
|
dissociate_from_references();
|
|
|
|
|
2013-03-26 22:22:09 +00:00
|
|
|
junk_mode = JUNK_LEAVE_REPO;
|
2012-01-16 09:46:09 +00:00
|
|
|
err = checkout();
|
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);
|
|
|
|
strbuf_release(&value);
|
2013-03-26 22:22:09 +00:00
|
|
|
junk_mode = JUNK_LEAVE_ALL;
|
2014-08-10 13:57:56 +00:00
|
|
|
|
|
|
|
free(refspec);
|
2009-03-03 05:37:51 +00:00
|
|
|
return err;
|
2008-04-27 17:39:30 +00:00
|
|
|
}
|