Skip to content

Commit 92251b1

Browse files
committed
Merge branch 'nd/shallow-clone'
Fetching from a shallow-cloned repository used to be forbidden, primarily because the codepaths involved were not carefully vetted and we did not bother supporting such usage. This attempts to allow object transfer out of a shallow-cloned repository in a controlled way (i.e. the receiver become a shallow repository with truncated history). * nd/shallow-clone: (31 commits) t5537: fix incorrect expectation in test case 10 shallow: remove unused code send-pack.c: mark a file-local function static git-clone.txt: remove shallow clone limitations prune: clean .git/shallow after pruning objects clone: use git protocol for cloning shallow repo locally send-pack: support pushing from a shallow clone via http receive-pack: support pushing to a shallow clone via http smart-http: support shallow fetch/clone remote-curl: pass ref SHA-1 to fetch-pack as well send-pack: support pushing to a shallow clone receive-pack: allow pushes that update .git/shallow connected.c: add new variant that runs with --shallow-file add GIT_SHALLOW_FILE to propagate --shallow-file to subprocesses receive/send-pack: support pushing from a shallow clone receive-pack: reorder some code in unpack() fetch: add --update-shallow to accept refs that update .git/shallow upload-pack: make sure deepening preserves shallow roots fetch: support fetching from a shallow repository clone: support remote shallow repository ...
2 parents d8cf714 + 3b32a7c commit 92251b1

36 files changed

+1535
-168
lines changed

Documentation/config.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,6 +2030,10 @@ receive.updateserverinfo::
20302030
If set to true, git-receive-pack will run git-update-server-info
20312031
after receiving data from git-push and updating refs.
20322032

2033+
receive.shallowupdate::
2034+
If set to true, .git/shallow can be updated when new refs
2035+
require new shallow roots. Otherwise those refs are rejected.
2036+
20332037
remote.pushdefault::
20342038
The remote to push to by default. Overrides
20352039
`branch.<name>.remote` for all branches, and is overridden by

Documentation/fetch-options.txt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,18 @@
1414
branch history. Tags for the deepened commits are not fetched.
1515

1616
--unshallow::
17-
Convert a shallow repository to a complete one, removing all
18-
the limitations imposed by shallow repositories.
17+
If the source repository is complete, convert a shallow
18+
repository to a complete one, removing all the limitations
19+
imposed by shallow repositories.
20+
+
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.
1929

2030
ifndef::git-pull[]
2131
--dry-run::

Documentation/git-clone.txt

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,12 +181,7 @@ objects from the source repository into a pack in the cloned repository.
181181

182182
--depth <depth>::
183183
Create a 'shallow' clone with a history truncated to the
184-
specified number of revisions. A shallow repository has a
185-
number of limitations (you cannot clone or fetch from
186-
it, nor push from nor into it), but is adequate if you
187-
are only interested in the recent history of a large project
188-
with a long history, and would want to send in fixes
189-
as patches.
184+
specified number of revisions.
190185

191186
--[no-]single-branch::
192187
Clone only the history leading to the tip of a single branch,

Documentation/git-prune.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ objects unreachable from any of these head objects from the object database.
2424
In addition, it
2525
prunes the unpacked objects that are also found in packs by
2626
running 'git prune-packed'.
27+
It also removes entries from .git/shallow that are not reachable by
28+
any ref.
2729

2830
Note that unreachable, packed objects will remain. If this is
2931
not desired, see linkgit:git-repack[1].

Documentation/gitremote-helpers.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,13 @@ set by Git if the remote helper has the 'option' capability.
437437
'option check-connectivity' \{'true'|'false'\}::
438438
Request the helper to check connectivity of a clone.
439439

440+
'option cloning \{'true'|'false'\}::
441+
Notify the helper this is a clone request (i.e. the current
442+
repository is guaranteed empty).
443+
444+
'option update-shallow \{'true'|'false'\}::
445+
Allow to extend .git/shallow if the new refs require it.
446+
440447
SEE ALSO
441448
--------
442449
linkgit:git-remote[1]

Documentation/technical/pack-protocol.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ MUST peel the ref if it's an annotated tag.
161161

162162
----
163163
advertised-refs = (no-refs / list-of-refs)
164+
*shallow
164165
flush-pkt
165166

166167
no-refs = PKT-LINE(zero-id SP "capabilities^{}"
@@ -174,6 +175,8 @@ MUST peel the ref if it's an annotated tag.
174175
other-tip = obj-id SP refname LF
175176
other-peeled = obj-id SP refname "^{}" LF
176177

178+
shallow = PKT-LINE("shallow" SP obj-id)
179+
177180
capability-list = capability *(SP capability)
178181
capability = 1*(LC_ALPHA / DIGIT / "-" / "_")
179182
LC_ALPHA = %x61-7A
@@ -461,7 +464,9 @@ contain all the objects that the server will need to complete the new
461464
references.
462465

463466
----
464-
update-request = command-list [pack-file]
467+
update-request = *shallow command-list [pack-file]
468+
469+
shallow = PKT-LINE("shallow" SP obj-id)
465470

466471
command-list = PKT-LINE(command NUL capability-list LF)
467472
*PKT-LINE(command LF)

builtin/clone.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,12 @@ static int add_one_reference(struct string_list_item *item, void *cb_data)
252252
die(_("reference repository '%s' is not a local repository."),
253253
item->string);
254254

255+
if (!access(mkpath("%s/shallow", ref_git), F_OK))
256+
die(_("reference repository '%s' is shallow"), item->string);
257+
258+
if (!access(mkpath("%s/info/grafts", ref_git), F_OK))
259+
die(_("reference repository '%s' is grafted"), item->string);
260+
255261
strbuf_addf(&alternate, "%s/objects", ref_git);
256262
add_to_alternates_file(alternate.buf);
257263
strbuf_release(&alternate);
@@ -791,8 +797,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
791797
else
792798
repo = repo_name;
793799
is_local = option_local != 0 && path && !is_bundle;
794-
if (is_local && option_depth)
795-
warning(_("--depth is ignored in local clones; use file:// instead."));
800+
if (is_local) {
801+
if (option_depth)
802+
warning(_("--depth is ignored in local clones; use file:// instead."));
803+
if (!access(mkpath("%s/shallow", path), F_OK)) {
804+
if (option_local > 0)
805+
warning(_("source repository is shallow, ignoring --local"));
806+
is_local = 0;
807+
}
808+
}
796809
if (option_local > 0 && !is_local)
797810
warning(_("--local is ignored"));
798811

@@ -887,6 +900,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
887900

888901
remote = remote_get(option_origin);
889902
transport = transport_get(remote, remote->url[0]);
903+
transport->cloning = 1;
890904

891905
if (!transport->get_refs_list || (!is_local && !transport->fetch))
892906
die(_("Don't know how to clone %s"), transport->url);

builtin/fetch-pack.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "fetch-pack.h"
44
#include "remote.h"
55
#include "connect.h"
6+
#include "sha1-array.h"
67

78
static const char fetch_pack_usage[] =
89
"git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
@@ -13,6 +14,13 @@ static void add_sought_entry_mem(struct ref ***sought, int *nr, int *alloc,
1314
const char *name, int namelen)
1415
{
1516
struct ref *ref = xcalloc(1, sizeof(*ref) + namelen + 1);
17+
unsigned char sha1[20];
18+
19+
if (namelen > 41 && name[40] == ' ' && !get_sha1_hex(name, sha1)) {
20+
hashcpy(ref->old_sha1, sha1);
21+
name += 41;
22+
namelen -= 41;
23+
}
1624

1725
memcpy(ref->name, name, namelen);
1826
ref->name[namelen] = '\0';
@@ -39,6 +47,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
3947
char **pack_lockfile_ptr = NULL;
4048
struct child_process *conn;
4149
struct fetch_pack_args args;
50+
struct sha1_array shallow = SHA1_ARRAY_INIT;
4251

4352
packet_trace_identity("fetch-pack");
4453

@@ -110,6 +119,14 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
110119
args.check_self_contained_and_connected = 1;
111120
continue;
112121
}
122+
if (!strcmp("--cloning", arg)) {
123+
args.cloning = 1;
124+
continue;
125+
}
126+
if (!strcmp("--update-shallow", arg)) {
127+
args.update_shallow = 1;
128+
continue;
129+
}
113130
usage(fetch_pack_usage);
114131
}
115132

@@ -158,10 +175,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
158175
if (!conn)
159176
return args.diag_url ? 0 : 1;
160177
}
161-
get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL);
178+
get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL, &shallow);
162179

163-
ref = fetch_pack(&args, fd, conn, ref, dest,
164-
sought, nr_sought, pack_lockfile_ptr);
180+
ref = fetch_pack(&args, fd, conn, ref, dest, sought, nr_sought,
181+
&shallow, pack_lockfile_ptr);
165182
if (pack_lockfile) {
166183
printf("lock %s\n", pack_lockfile);
167184
fflush(stdout);

builtin/fetch.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ static int prune = -1; /* unspecified */
3636

3737
static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity;
3838
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;
4040
static const char *depth;
4141
static const char *upload_pack;
4242
static struct strbuf default_rla = STRBUF_INIT;
@@ -105,6 +105,8 @@ static struct option builtin_fetch_options[] = {
105105
{ OPTION_STRING, 0, "recurse-submodules-default",
106106
&recurse_submodules_default, NULL,
107107
N_("default mode for recursion"), PARSE_OPT_HIDDEN },
108+
OPT_BOOL(0, "update-shallow", &update_shallow,
109+
N_("accept refs that update .git/shallow")),
108110
OPT_END()
109111
};
110112

@@ -524,6 +526,8 @@ static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
524526
struct ref **rm = cb_data;
525527
struct ref *ref = *rm;
526528

529+
while (ref && ref->status == REF_STATUS_REJECT_SHALLOW)
530+
ref = ref->next;
527531
if (!ref)
528532
return -1; /* end of the list */
529533
*rm = ref->next;
@@ -570,6 +574,13 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
570574
struct ref *ref = NULL;
571575
const char *merge_status_marker = "";
572576

577+
if (rm->status == REF_STATUS_REJECT_SHALLOW) {
578+
if (want_status == FETCH_HEAD_MERGE)
579+
warning(_("reject %s because shallow roots are not allowed to be updated"),
580+
rm->peer_ref ? rm->peer_ref->name : rm->name);
581+
continue;
582+
}
583+
573584
commit = lookup_commit_reference_gently(rm->old_sha1, 1);
574585
if (!commit)
575586
rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
@@ -798,6 +809,8 @@ static struct transport *prepare_transport(struct remote *remote)
798809
set_option(transport, TRANS_OPT_KEEP, "yes");
799810
if (depth)
800811
set_option(transport, TRANS_OPT_DEPTH, depth);
812+
if (update_shallow)
813+
set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes");
801814
return transport;
802815
}
803816

builtin/gc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "run-command.h"
1717
#include "sigchain.h"
1818
#include "argv-array.h"
19+
#include "commit.h"
1920

2021
#define FAILED_RUN "failed to run %s"
2122

builtin/prune.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,5 +180,9 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
180180
s = mkpathdup("%s/pack", get_object_directory());
181181
remove_temporary_files(s);
182182
free(s);
183+
184+
if (is_repository_shallow())
185+
prune_shallow(show_only);
186+
183187
return 0;
184188
}

0 commit comments

Comments
 (0)