fetch: add --update-shallow to accept refs that update .git/shallow

The same steps are done as in when --update-shallow is not given. The
only difference is we now add all shallow commits in "ours" and
"theirs" to .git/shallow (aka "step 8").

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Nguyễn Thái Ngọc Duy 2013-12-05 20:02:42 +07:00 committed by Junio C Hamano
parent 79d3a236c5
commit 48d25cae22
7 changed files with 79 additions and 1 deletions

View File

@ -21,6 +21,12 @@
If the source repository is shallow, fetch as much as possible so that If the source repository is shallow, fetch as much as possible so that
the current repository has the same history as the source repository. the current repository has the same history as the source repository.
--update-shallow::
By default when fetching from a shallow repository,
`git fetch` refuses refs that require updating
.git/shallow. This option updates .git/shallow and accept such
refs.
ifndef::git-pull[] ifndef::git-pull[]
--dry-run:: --dry-run::
Show what would be done, without making any changes. Show what would be done, without making any changes.

View File

@ -36,7 +36,7 @@ static int prune = -1; /* unspecified */
static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity; static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity;
static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT; static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
static int tags = TAGS_DEFAULT, unshallow; static int tags = TAGS_DEFAULT, unshallow, update_shallow;
static const char *depth; static const char *depth;
static const char *upload_pack; static const char *upload_pack;
static struct strbuf default_rla = STRBUF_INIT; static struct strbuf default_rla = STRBUF_INIT;
@ -104,6 +104,8 @@ static struct option builtin_fetch_options[] = {
{ OPTION_STRING, 0, "recurse-submodules-default", { OPTION_STRING, 0, "recurse-submodules-default",
&recurse_submodules_default, NULL, &recurse_submodules_default, NULL,
N_("default mode for recursion"), PARSE_OPT_HIDDEN }, N_("default mode for recursion"), PARSE_OPT_HIDDEN },
OPT_BOOL(0, "update-shallow", &update_shallow,
N_("accept refs that update .git/shallow")),
OPT_END() OPT_END()
}; };
@ -768,6 +770,8 @@ static struct transport *prepare_transport(struct remote *remote)
set_option(transport, TRANS_OPT_KEEP, "yes"); set_option(transport, TRANS_OPT_KEEP, "yes");
if (depth) if (depth)
set_option(transport, TRANS_OPT_DEPTH, depth); set_option(transport, TRANS_OPT_DEPTH, depth);
if (update_shallow)
set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes");
return transport; return transport;
} }

View File

@ -993,6 +993,33 @@ static void update_shallow(struct fetch_pack_args *args,
sha1_array_append(&ref, sought[i]->old_sha1); sha1_array_append(&ref, sought[i]->old_sha1);
si->ref = &ref; si->ref = &ref;
if (args->update_shallow) {
/*
* remote is also shallow, .git/shallow may be updated
* so all refs can be accepted. Make sure we only add
* shallow roots that are actually reachable from new
* refs.
*/
struct sha1_array extra = SHA1_ARRAY_INIT;
unsigned char (*sha1)[20] = si->shallow->sha1;
assign_shallow_commits_to_refs(si, NULL, NULL);
if (!si->nr_ours && !si->nr_theirs) {
sha1_array_clear(&ref);
return;
}
for (i = 0; i < si->nr_ours; i++)
sha1_array_append(&extra, sha1[si->ours[i]]);
for (i = 0; i < si->nr_theirs; i++)
sha1_array_append(&extra, sha1[si->theirs[i]]);
setup_alternate_shallow(&shallow_lock,
&alternate_shallow_file,
&extra);
commit_lock_file(&shallow_lock);
sha1_array_clear(&extra);
sha1_array_clear(&ref);
return;
}
/* /*
* remote is also shallow, check what ref is safe to update * remote is also shallow, check what ref is safe to update
* without updating .git/shallow * without updating .git/shallow

View File

@ -23,6 +23,7 @@ struct fetch_pack_args {
unsigned check_self_contained_and_connected:1; unsigned check_self_contained_and_connected:1;
unsigned self_contained_and_connected:1; unsigned self_contained_and_connected:1;
unsigned cloning:1; unsigned cloning:1;
unsigned update_shallow:1;
}; };
/* /*

View File

@ -141,4 +141,36 @@ EOF
) )
' '
test_expect_success 'fetch --update-shallow' '
(
cd shallow &&
git checkout master &&
commit 7 &&
git tag -m foo heavy-tag HEAD^ &&
git tag light-tag HEAD^:tracked
) &&
(
cd notshallow &&
git fetch --update-shallow ../shallow/.git refs/heads/*:refs/remotes/shallow/* &&
git fsck &&
git for-each-ref --sort=refname --format="%(refname)" >actual.refs &&
cat <<EOF >expect.refs &&
refs/remotes/shallow/master
refs/remotes/shallow/no-shallow
refs/tags/heavy-tag
refs/tags/light-tag
EOF
test_cmp expect.refs actual.refs &&
git log --format=%s shallow/master >actual &&
cat <<EOF >expect &&
7
6
5
4
3
EOF
test_cmp expect actual
)
'
test_done test_done

View File

@ -477,6 +477,9 @@ static int set_git_option(struct git_transport_options *opts,
} else if (!strcmp(name, TRANS_OPT_KEEP)) { } else if (!strcmp(name, TRANS_OPT_KEEP)) {
opts->keep = !!value; opts->keep = !!value;
return 0; return 0;
} else if (!strcmp(name, TRANS_OPT_UPDATE_SHALLOW)) {
opts->update_shallow = !!value;
return 0;
} else if (!strcmp(name, TRANS_OPT_DEPTH)) { } else if (!strcmp(name, TRANS_OPT_DEPTH)) {
if (!value) if (!value)
opts->depth = 0; opts->depth = 0;
@ -543,6 +546,7 @@ static int fetch_refs_via_pack(struct transport *transport,
args.check_self_contained_and_connected = args.check_self_contained_and_connected =
data->options.check_self_contained_and_connected; data->options.check_self_contained_and_connected;
args.cloning = transport->cloning; args.cloning = transport->cloning;
args.update_shallow = data->options.update_shallow;
if (!data->got_remote_heads) { if (!data->got_remote_heads) {
connect_setup(transport, 0, 0); connect_setup(transport, 0, 0);

View File

@ -11,6 +11,7 @@ struct git_transport_options {
unsigned followtags : 1; unsigned followtags : 1;
unsigned check_self_contained_and_connected : 1; unsigned check_self_contained_and_connected : 1;
unsigned self_contained_and_connected : 1; unsigned self_contained_and_connected : 1;
unsigned update_shallow : 1;
int depth; int depth;
const char *uploadpack; const char *uploadpack;
const char *receivepack; const char *receivepack;
@ -152,6 +153,9 @@ struct transport *transport_get(struct remote *, const char *);
/* Aggressively fetch annotated tags if possible */ /* Aggressively fetch annotated tags if possible */
#define TRANS_OPT_FOLLOWTAGS "followtags" #define TRANS_OPT_FOLLOWTAGS "followtags"
/* Accept refs that may update .git/shallow without --depth */
#define TRANS_OPT_UPDATE_SHALLOW "updateshallow"
/** /**
* Returns 0 if the option was used, non-zero otherwise. Prints a * Returns 0 if the option was used, non-zero otherwise. Prints a
* message to stderr if the option is not used. * message to stderr if the option is not used.