summaryrefslogtreecommitdiff
path: root/transport.c
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2013-12-05 20:02:39 +0700
committerJunio C Hamano <gitster@pobox.com>2013-12-10 16:14:17 -0800
commitbeea4152d94cf7c77eeb6b226805b315d22b3a2f (patch)
treec1c74ba3462b4c8aa108f596aca6eeb3b4237246 /transport.c
parentf6486f07d25ab4f2f93483690acabb817b0729b8 (diff)
downloadgit-beea4152d94cf7c77eeb6b226805b315d22b3a2f.tar.gz
clone: support remote shallow repository
Cloning from a shallow repository does not follow the "8 steps for new .git/shallow" because if it does we need to get through step 6 for all refs. That means commit walking down to the bottom. Instead the rule to create .git/shallow is simpler and, more importantly, cheap: if a shallow commit is found in the pack, it's probably used (i.e. reachable from some refs), so we add it. Others are dropped. One may notice this method seems flawed by the word "probably". A shallow commit may not be reachable from any refs at all if it's attached to an object island (a group of objects that are not reachable by any refs). If that object island is not complete, a new fetch request may send more objects to connect it to some ref. At that time, because we incorrectly installed the shallow commit in this island, the user will not see anything after that commit (fsck is still ok). This is not desired. Given that object islands are rare (C Git never sends such islands for security reasons) and do not really harm the repository integrity, a tradeoff is made to surprise the user occasionally but work faster everyday. A new option --strict could be added later that follows exactly the 8 steps. "git prune" can also learn to remove dangling objects _and_ the shallow commits that are attached to them from .git/shallow. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'transport.c')
-rw-r--r--transport.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/transport.c b/transport.c
index 90453df9c6..91c466742e 100644
--- a/transport.c
+++ b/transport.c
@@ -456,6 +456,7 @@ struct git_transport_data {
int fd[2];
unsigned got_remote_heads : 1;
struct sha1_array extra_have;
+ struct sha1_array shallow;
};
static int set_git_option(struct git_transport_options *opts,
@@ -512,7 +513,9 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
connect_setup(transport, for_push, 0);
get_remote_heads(data->fd[0], NULL, 0, &refs,
- for_push ? REF_NORMAL : 0, &data->extra_have, NULL);
+ for_push ? REF_NORMAL : 0,
+ &data->extra_have,
+ transport->cloning ? &data->shallow : NULL);
data->got_remote_heads = 1;
return refs;
@@ -539,17 +542,19 @@ static int fetch_refs_via_pack(struct transport *transport,
args.depth = data->options.depth;
args.check_self_contained_and_connected =
data->options.check_self_contained_and_connected;
+ args.cloning = transport->cloning;
if (!data->got_remote_heads) {
connect_setup(transport, 0, 0);
get_remote_heads(data->fd[0], NULL, 0, &refs_tmp, 0,
- NULL, NULL);
+ NULL,
+ transport->cloning ? &data->shallow : NULL);
data->got_remote_heads = 1;
}
refs = fetch_pack(&args, data->fd, data->conn,
refs_tmp ? refs_tmp : transport->remote_refs,
- dest, to_fetch, nr_heads,
+ dest, to_fetch, nr_heads, &data->shallow,
&transport->pack_lockfile);
close(data->fd[0]);
close(data->fd[1]);