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>
Nguyễn Thái Ngọc Duy committed
Dec 5, 2013 at 20:02 UTC
48d25cae22667dfc2c31ad620172c0f0a3ac1490
7 files changed
+79
-1
Documentation/fetch-options.txt
+6
@@ -21,6 +21,12 @@
21
If the source repository is shallow, fetch as much as possible so that
22
the current repository has the same history as the source repository.
23
24
+--update-shallow::
25
+ By default when fetching from a shallow repository,
26
+ `git fetch` refuses refs that require updating
27
+ .git/shallow. This option updates .git/shallow and accept such
28
+ refs.
29
+
30
ifndef::git-pull[]
31
--dry-run::
32
Show what would be done, without making any changes.
builtin/fetch.c
+5
-1
@@ -36,7 +36,7 @@ static int prune = -1; /* unspecified */
36
37
static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity;
38
static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
39
-static int tags = TAGS_DEFAULT, unshallow;
39
+static int tags = TAGS_DEFAULT, unshallow, update_shallow;
40
static const char *depth;
41
static const char *upload_pack;
42
static struct strbuf default_rla = STRBUF_INIT;
@@ -104,6 +104,8 @@ static struct option builtin_fetch_options[] = {
104
{ OPTION_STRING, 0, "recurse-submodules-default",
105
&recurse_submodules_default, NULL,
106
N_("default mode for recursion"), PARSE_OPT_HIDDEN },
107
+ OPT_BOOL(0, "update-shallow", &update_shallow,
108
+ N_("accept refs that update .git/shallow")),
109
OPT_END()
110
};
111
@@ -768,6 +770,8 @@ static struct transport *prepare_transport(struct remote *remote)
770
set_option(transport, TRANS_OPT_KEEP, "yes");
771
if (depth)
772
set_option(transport, TRANS_OPT_DEPTH, depth);
773
+ if (update_shallow)
774
+ set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes");
775
return transport;
776
}
777
fetch-pack.c
+27
@@ -993,6 +993,33 @@ static void update_shallow(struct fetch_pack_args *args,
993
sha1_array_append(&ref, sought[i]->old_sha1);
994
si->ref = &ref;
995
996
+ if (args->update_shallow) {
997
+ /*
998
+ * remote is also shallow, .git/shallow may be updated
999
+ * so all refs can be accepted. Make sure we only add
1000
+ * shallow roots that are actually reachable from new
1001
+ * refs.
1002
+ */
1003
+ struct sha1_array extra = SHA1_ARRAY_INIT;
1004
+ unsigned char (*sha1)[20] = si->shallow->sha1;
1005
+ assign_shallow_commits_to_refs(si, NULL, NULL);
1006
+ if (!si->nr_ours && !si->nr_theirs) {
1007
+ sha1_array_clear(&ref);
1008
+ return;
1009
+ }
1010
+ for (i = 0; i < si->nr_ours; i++)
1011
+ sha1_array_append(&extra, sha1[si->ours[i]]);
1012
+ for (i = 0; i < si->nr_theirs; i++)
1013
+ sha1_array_append(&extra, sha1[si->theirs[i]]);
1014
+ setup_alternate_shallow(&shallow_lock,
1015
+ &alternate_shallow_file,
1016
+ &extra);
1017
+ commit_lock_file(&shallow_lock);
1018
+ sha1_array_clear(&extra);
1019
+ sha1_array_clear(&ref);
1020
+ return;
1021
+ }
1022
+
1023
/*
1024
* remote is also shallow, check what ref is safe to update
1025
* without updating .git/shallow
fetch-pack.h
+1
@@ -23,6 +23,7 @@ struct fetch_pack_args {
23
unsigned check_self_contained_and_connected:1;
24
unsigned self_contained_and_connected:1;
25
unsigned cloning:1;
26
+ unsigned update_shallow:1;
27
};
28
29
/*
t/t5537-fetch-shallow.sh
+32
@@ -141,4 +141,36 @@ EOF
141
)
142
'
143
144
+test_expect_success 'fetch --update-shallow' '
145
+ (
146
+ cd shallow &&
147
+ git checkout master &&
148
+ commit 7 &&
149
+ git tag -m foo heavy-tag HEAD^ &&
150
+ git tag light-tag HEAD^:tracked
151
+ ) &&
152
+ (
153
+ cd notshallow &&
154
+ git fetch --update-shallow ../shallow/.git refs/heads/*:refs/remotes/shallow/* &&
155
+ git fsck &&
156
+ git for-each-ref --sort=refname --format="%(refname)" >actual.refs &&
157
+ cat <<EOF >expect.refs &&
158
+refs/remotes/shallow/master
159
+refs/remotes/shallow/no-shallow
160
+refs/tags/heavy-tag
161
+refs/tags/light-tag
162
+EOF
163
+ test_cmp expect.refs actual.refs &&
164
+ git log --format=%s shallow/master >actual &&
165
+ cat <<EOF >expect &&
166
+7
167
+6
168
+5
169
+4
170
+3
171
+EOF
172
+ test_cmp expect actual
173
+ )
174
+'
175
+
176
test_done
transport.c
+4
@@ -477,6 +477,9 @@ static int set_git_option(struct git_transport_options *opts,
477
} else if (!strcmp(name, TRANS_OPT_KEEP)) {
478
opts->keep = !!value;
479
return 0;
480
+ } else if (!strcmp(name, TRANS_OPT_UPDATE_SHALLOW)) {
481
+ opts->update_shallow = !!value;
482
+ return 0;
483
} else if (!strcmp(name, TRANS_OPT_DEPTH)) {
484
if (!value)
485
opts->depth = 0;
@@ -543,6 +546,7 @@ static int fetch_refs_via_pack(struct transport *transport,
546
args.check_self_contained_and_connected =
547
data->options.check_self_contained_and_connected;
548
args.cloning = transport->cloning;
549
+ args.update_shallow = data->options.update_shallow;
550
551
if (!data->got_remote_heads) {
552
connect_setup(transport, 0, 0);
transport.h
+4
@@ -11,6 +11,7 @@ struct git_transport_options {
11
unsigned followtags : 1;
12
unsigned check_self_contained_and_connected : 1;
13
unsigned self_contained_and_connected : 1;
14
+ unsigned update_shallow : 1;
15
int depth;
16
const char *uploadpack;
17
const char *receivepack;
@@ -152,6 +153,9 @@ struct transport *transport_get(struct remote *, const char *);
153
/* Aggressively fetch annotated tags if possible */
154
#define TRANS_OPT_FOLLOWTAGS "followtags"
155
156
+/* Accept refs that may update .git/shallow without --depth */
157
+#define TRANS_OPT_UPDATE_SHALLOW "updateshallow"
158
+
159
/**
160
* Returns 0 if the option was used, non-zero otherwise. Prints a
161
* message to stderr if the option is not used.