Merge branch 'nd/clone-single-branch'
* nd/clone-single-branch: clone: add --single-branch to fetch only one branch
This commit is contained in:
commit
7859f533e2
@ -13,7 +13,8 @@ SYNOPSIS
|
||||
[-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
|
||||
[-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>]
|
||||
[--separate-git-dir <git dir>]
|
||||
[--depth <depth>] [--recursive|--recurse-submodules] [--] <repository>
|
||||
[--depth <depth>] [--[no-]single-branch]
|
||||
[--recursive|--recurse-submodules] [--] <repository>
|
||||
[<directory>]
|
||||
|
||||
DESCRIPTION
|
||||
@ -179,6 +180,14 @@ objects from the source repository into a pack in the cloned repository.
|
||||
with a long history, and would want to send in fixes
|
||||
as patches.
|
||||
|
||||
--single-branch::
|
||||
Clone only the history leading to the tip of a single branch,
|
||||
either specified by the `--branch` option or the primary
|
||||
branch remote's `HEAD` points at. When creating a shallow
|
||||
clone with the `--depth` option, this is the default, unless
|
||||
`--no-single-branch` is given to fetch the histories near the
|
||||
tips of all branches.
|
||||
|
||||
--recursive::
|
||||
--recurse-submodules::
|
||||
After the clone is created, initialize all submodules within,
|
||||
|
@ -37,7 +37,7 @@ static const char * const builtin_clone_usage[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static int option_no_checkout, option_bare, option_mirror;
|
||||
static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;
|
||||
static int option_local, option_no_hardlinks, option_shared, option_recursive;
|
||||
static char *option_template, *option_depth;
|
||||
static char *option_origin = NULL;
|
||||
@ -48,6 +48,7 @@ static int option_verbosity;
|
||||
static int option_progress;
|
||||
static struct string_list option_config;
|
||||
static struct string_list option_reference;
|
||||
static const char *src_ref_prefix = "refs/heads/";
|
||||
|
||||
static int opt_parse_reference(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
@ -92,6 +93,8 @@ static struct option builtin_clone_options[] = {
|
||||
"path to git-upload-pack on the remote"),
|
||||
OPT_STRING(0, "depth", &option_depth, "depth",
|
||||
"create a shallow clone of that depth"),
|
||||
OPT_BOOL(0, "single-branch", &option_single_branch,
|
||||
"clone only one branch, HEAD or --branch"),
|
||||
OPT_STRING(0, "separate-git-dir", &real_git_dir, "gitdir",
|
||||
"separate git dir from working tree"),
|
||||
OPT_STRING_LIST('c', "config", &option_config, "key=value",
|
||||
@ -427,8 +430,28 @@ static struct ref *wanted_peer_refs(const struct ref *refs,
|
||||
struct ref *local_refs = head;
|
||||
struct ref **tail = head ? &head->next : &local_refs;
|
||||
|
||||
get_fetch_map(refs, refspec, &tail, 0);
|
||||
if (!option_mirror)
|
||||
if (option_single_branch) {
|
||||
struct ref *remote_head = NULL;
|
||||
|
||||
if (!option_branch)
|
||||
remote_head = guess_remote_head(head, refs, 0);
|
||||
else {
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
strbuf_addstr(&sb, src_ref_prefix);
|
||||
strbuf_addstr(&sb, option_branch);
|
||||
remote_head = find_ref_by_name(refs, sb.buf);
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
if (!remote_head && option_branch)
|
||||
warning(_("Could not find remote branch %s to clone."),
|
||||
option_branch);
|
||||
else
|
||||
get_fetch_map(remote_head, refspec, &tail, 0);
|
||||
} else
|
||||
get_fetch_map(refs, refspec, &tail, 0);
|
||||
|
||||
if (!option_mirror && !option_single_branch)
|
||||
get_fetch_map(refs, tag_refspec, &tail, 0);
|
||||
|
||||
return local_refs;
|
||||
@ -448,6 +471,21 @@ static void write_remote_refs(const struct ref *local_refs)
|
||||
clear_extra_refs();
|
||||
}
|
||||
|
||||
static void write_followtags(const struct ref *refs, const char *msg)
|
||||
{
|
||||
const struct ref *ref;
|
||||
for (ref = refs; ref; ref = ref->next) {
|
||||
if (prefixcmp(ref->name, "refs/tags/"))
|
||||
continue;
|
||||
if (!suffixcmp(ref->name, "^{}"))
|
||||
continue;
|
||||
if (!has_sha1_file(ref->old_sha1))
|
||||
continue;
|
||||
update_ref(msg, ref->name, ref->old_sha1,
|
||||
NULL, 0, DIE_ON_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
static int write_one_config(const char *key, const char *value, void *data)
|
||||
{
|
||||
return git_config_set_multivar(key, value ? value : "true", "^$", 0);
|
||||
@ -478,7 +516,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||
struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
|
||||
struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
|
||||
struct transport *transport = NULL;
|
||||
char *src_ref_prefix = "refs/heads/";
|
||||
int err = 0;
|
||||
|
||||
struct refspec *refspec;
|
||||
@ -498,6 +535,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||
usage_msg_opt(_("You must specify a repository to clone."),
|
||||
builtin_clone_usage, builtin_clone_options);
|
||||
|
||||
if (option_single_branch == -1)
|
||||
option_single_branch = option_depth ? 1 : 0;
|
||||
|
||||
if (option_mirror)
|
||||
option_bare = 1;
|
||||
|
||||
@ -645,6 +685,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||
if (option_depth)
|
||||
transport_set_option(transport, TRANS_OPT_DEPTH,
|
||||
option_depth);
|
||||
if (option_single_branch)
|
||||
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
|
||||
|
||||
transport_set_verbosity(transport, option_verbosity, option_progress);
|
||||
|
||||
@ -663,6 +705,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||
clear_extra_refs();
|
||||
|
||||
write_remote_refs(mapped_refs);
|
||||
if (option_single_branch)
|
||||
write_followtags(refs, reflog_msg.buf);
|
||||
|
||||
remote_head = find_ref_by_name(refs, "HEAD");
|
||||
remote_head_points_at =
|
||||
|
@ -114,8 +114,19 @@ pull_to_client 2nd "refs/heads/B" $((64*3))
|
||||
|
||||
pull_to_client 3rd "refs/heads/A" $((1*3))
|
||||
|
||||
test_expect_success 'single branch clone' '
|
||||
git clone --single-branch "file://$(pwd)/." singlebranch
|
||||
'
|
||||
|
||||
test_expect_success 'single branch object count' '
|
||||
GIT_DIR=singlebranch/.git git count-objects -v |
|
||||
grep "^in-pack:" > count.singlebranch &&
|
||||
echo "in-pack: 198" >expected &&
|
||||
test_cmp expected count.singlebranch
|
||||
'
|
||||
|
||||
test_expect_success 'clone shallow' '
|
||||
git clone --depth 2 "file://$(pwd)/." shallow
|
||||
git clone --no-single-branch --depth 2 "file://$(pwd)/." shallow
|
||||
'
|
||||
|
||||
test_expect_success 'clone shallow object count' '
|
||||
@ -248,4 +259,63 @@ test_expect_success 'clone shallow object count' '
|
||||
grep "^count: 52" count.shallow
|
||||
'
|
||||
|
||||
test_expect_success 'clone shallow without --no-single-branch' '
|
||||
git clone --depth 1 "file://$(pwd)/." shallow2
|
||||
'
|
||||
|
||||
test_expect_success 'clone shallow object count' '
|
||||
(
|
||||
cd shallow2 &&
|
||||
git count-objects -v
|
||||
) > count.shallow2 &&
|
||||
grep "^in-pack: 6" count.shallow2
|
||||
'
|
||||
|
||||
test_expect_success 'clone shallow with --branch' '
|
||||
git clone --depth 1 --branch A "file://$(pwd)/." shallow3
|
||||
'
|
||||
|
||||
test_expect_success 'clone shallow object count' '
|
||||
echo "in-pack: 12" > count3.expected &&
|
||||
GIT_DIR=shallow3/.git git count-objects -v |
|
||||
grep "^in-pack" > count3.actual &&
|
||||
test_cmp count3.expected count3.actual
|
||||
'
|
||||
|
||||
test_expect_success 'clone shallow with nonexistent --branch' '
|
||||
git clone --depth 1 --branch Z "file://$(pwd)/." shallow4 &&
|
||||
GIT_DIR=shallow4/.git git rev-parse HEAD >actual &&
|
||||
git rev-parse HEAD >expected &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'clone shallow with detached HEAD' '
|
||||
git checkout HEAD^ &&
|
||||
git clone --depth 1 "file://$(pwd)/." shallow5 &&
|
||||
git checkout - &&
|
||||
GIT_DIR=shallow5/.git git rev-parse HEAD >actual &&
|
||||
git rev-parse HEAD^ >expected &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'shallow clone pulling tags' '
|
||||
git tag -a -m A TAGA1 A &&
|
||||
git tag -a -m B TAGB1 B &&
|
||||
git tag TAGA2 A &&
|
||||
git tag TAGB2 B &&
|
||||
git clone --depth 1 "file://$(pwd)/." shallow6 &&
|
||||
|
||||
cat >taglist.expected <<\EOF &&
|
||||
TAGB1
|
||||
TAGB2
|
||||
EOF
|
||||
GIT_DIR=shallow6/.git git tag -l >taglist.actual &&
|
||||
test_cmp taglist.expected taglist.actual &&
|
||||
|
||||
echo "in-pack: 7" > count6.expected &&
|
||||
GIT_DIR=shallow6/.git git count-objects -v |
|
||||
grep "^in-pack" > count6.actual &&
|
||||
test_cmp count6.expected count6.actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Loading…
Reference in New Issue
Block a user