Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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
  ...
  • Loading branch information
Junio C Hamano committed Jan 17, 2014
2 parents d8cf714 + 3b32a7c commit 92251b1
Show file tree
Hide file tree
Showing 36 changed files with 1,535 additions and 168 deletions.
4 changes: 4 additions & 0 deletions Documentation/config.txt
Expand Up @@ -2030,6 +2030,10 @@ receive.updateserverinfo::
If set to true, git-receive-pack will run git-update-server-info
after receiving data from git-push and updating refs.

receive.shallowupdate::
If set to true, .git/shallow can be updated when new refs
require new shallow roots. Otherwise those refs are rejected.

remote.pushdefault::
The remote to push to by default. Overrides
`branch.<name>.remote` for all branches, and is overridden by
Expand Down
14 changes: 12 additions & 2 deletions Documentation/fetch-options.txt
Expand Up @@ -14,8 +14,18 @@
branch history. Tags for the deepened commits are not fetched.

--unshallow::
Convert a shallow repository to a complete one, removing all
the limitations imposed by shallow repositories.
If the source repository is complete, convert a shallow
repository to a complete one, removing all the limitations
imposed by shallow repositories.
+
If the source repository is shallow, fetch as much as possible so that
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[]
--dry-run::
Expand Down
7 changes: 1 addition & 6 deletions Documentation/git-clone.txt
Expand Up @@ -181,12 +181,7 @@ objects from the source repository into a pack in the cloned repository.

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

--[no-]single-branch::
Clone only the history leading to the tip of a single branch,
Expand Down
2 changes: 2 additions & 0 deletions Documentation/git-prune.txt
Expand Up @@ -24,6 +24,8 @@ objects unreachable from any of these head objects from the object database.
In addition, it
prunes the unpacked objects that are also found in packs by
running 'git prune-packed'.
It also removes entries from .git/shallow that are not reachable by
any ref.

Note that unreachable, packed objects will remain. If this is
not desired, see linkgit:git-repack[1].
Expand Down
7 changes: 7 additions & 0 deletions Documentation/gitremote-helpers.txt
Expand Up @@ -437,6 +437,13 @@ set by Git if the remote helper has the 'option' capability.
'option check-connectivity' \{'true'|'false'\}::
Request the helper to check connectivity of a clone.

'option cloning \{'true'|'false'\}::
Notify the helper this is a clone request (i.e. the current
repository is guaranteed empty).

'option update-shallow \{'true'|'false'\}::
Allow to extend .git/shallow if the new refs require it.

SEE ALSO
--------
linkgit:git-remote[1]
Expand Down
7 changes: 6 additions & 1 deletion Documentation/technical/pack-protocol.txt
Expand Up @@ -161,6 +161,7 @@ MUST peel the ref if it's an annotated tag.

----
advertised-refs = (no-refs / list-of-refs)
*shallow
flush-pkt

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

shallow = PKT-LINE("shallow" SP obj-id)

capability-list = capability *(SP capability)
capability = 1*(LC_ALPHA / DIGIT / "-" / "_")
LC_ALPHA = %x61-7A
Expand Down Expand Up @@ -461,7 +464,9 @@ contain all the objects that the server will need to complete the new
references.

----
update-request = command-list [pack-file]
update-request = *shallow command-list [pack-file]

shallow = PKT-LINE("shallow" SP obj-id)

command-list = PKT-LINE(command NUL capability-list LF)
*PKT-LINE(command LF)
Expand Down
18 changes: 16 additions & 2 deletions builtin/clone.c
Expand Up @@ -252,6 +252,12 @@ static int add_one_reference(struct string_list_item *item, void *cb_data)
die(_("reference repository '%s' is not a local repository."),
item->string);

if (!access(mkpath("%s/shallow", ref_git), F_OK))
die(_("reference repository '%s' is shallow"), item->string);

if (!access(mkpath("%s/info/grafts", ref_git), F_OK))
die(_("reference repository '%s' is grafted"), item->string);

strbuf_addf(&alternate, "%s/objects", ref_git);
add_to_alternates_file(alternate.buf);
strbuf_release(&alternate);
Expand Down Expand Up @@ -791,8 +797,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
else
repo = repo_name;
is_local = option_local != 0 && path && !is_bundle;
if (is_local && option_depth)
warning(_("--depth is ignored in local clones; use file:// instead."));
if (is_local) {
if (option_depth)
warning(_("--depth is ignored in local clones; use file:// instead."));
if (!access(mkpath("%s/shallow", path), F_OK)) {
if (option_local > 0)
warning(_("source repository is shallow, ignoring --local"));
is_local = 0;
}
}
if (option_local > 0 && !is_local)
warning(_("--local is ignored"));

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

remote = remote_get(option_origin);
transport = transport_get(remote, remote->url[0]);
transport->cloning = 1;

if (!transport->get_refs_list || (!is_local && !transport->fetch))
die(_("Don't know how to clone %s"), transport->url);
Expand Down
23 changes: 20 additions & 3 deletions builtin/fetch-pack.c
Expand Up @@ -3,6 +3,7 @@
#include "fetch-pack.h"
#include "remote.h"
#include "connect.h"
#include "sha1-array.h"

static const char fetch_pack_usage[] =
"git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
Expand All @@ -13,6 +14,13 @@ static void add_sought_entry_mem(struct ref ***sought, int *nr, int *alloc,
const char *name, int namelen)
{
struct ref *ref = xcalloc(1, sizeof(*ref) + namelen + 1);
unsigned char sha1[20];

if (namelen > 41 && name[40] == ' ' && !get_sha1_hex(name, sha1)) {
hashcpy(ref->old_sha1, sha1);
name += 41;
namelen -= 41;
}

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

packet_trace_identity("fetch-pack");

Expand Down Expand Up @@ -110,6 +119,14 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
args.check_self_contained_and_connected = 1;
continue;
}
if (!strcmp("--cloning", arg)) {
args.cloning = 1;
continue;
}
if (!strcmp("--update-shallow", arg)) {
args.update_shallow = 1;
continue;
}
usage(fetch_pack_usage);
}

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

ref = fetch_pack(&args, fd, conn, ref, dest,
sought, nr_sought, pack_lockfile_ptr);
ref = fetch_pack(&args, fd, conn, ref, dest, sought, nr_sought,
&shallow, pack_lockfile_ptr);
if (pack_lockfile) {
printf("lock %s\n", pack_lockfile);
fflush(stdout);
Expand Down
15 changes: 14 additions & 1 deletion builtin/fetch.c
Expand Up @@ -36,7 +36,7 @@ static int prune = -1; /* unspecified */

static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity;
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 *upload_pack;
static struct strbuf default_rla = STRBUF_INIT;
Expand Down Expand Up @@ -105,6 +105,8 @@ static struct option builtin_fetch_options[] = {
{ OPTION_STRING, 0, "recurse-submodules-default",
&recurse_submodules_default, NULL,
N_("default mode for recursion"), PARSE_OPT_HIDDEN },
OPT_BOOL(0, "update-shallow", &update_shallow,
N_("accept refs that update .git/shallow")),
OPT_END()
};

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

while (ref && ref->status == REF_STATUS_REJECT_SHALLOW)
ref = ref->next;
if (!ref)
return -1; /* end of the list */
*rm = ref->next;
Expand Down Expand Up @@ -570,6 +574,13 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
struct ref *ref = NULL;
const char *merge_status_marker = "";

if (rm->status == REF_STATUS_REJECT_SHALLOW) {
if (want_status == FETCH_HEAD_MERGE)
warning(_("reject %s because shallow roots are not allowed to be updated"),
rm->peer_ref ? rm->peer_ref->name : rm->name);
continue;
}

commit = lookup_commit_reference_gently(rm->old_sha1, 1);
if (!commit)
rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
Expand Down Expand Up @@ -798,6 +809,8 @@ static struct transport *prepare_transport(struct remote *remote)
set_option(transport, TRANS_OPT_KEEP, "yes");
if (depth)
set_option(transport, TRANS_OPT_DEPTH, depth);
if (update_shallow)
set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes");
return transport;
}

Expand Down
1 change: 1 addition & 0 deletions builtin/gc.c
Expand Up @@ -16,6 +16,7 @@
#include "run-command.h"
#include "sigchain.h"
#include "argv-array.h"
#include "commit.h"

#define FAILED_RUN "failed to run %s"

Expand Down
4 changes: 4 additions & 0 deletions builtin/prune.c
Expand Up @@ -180,5 +180,9 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
s = mkpathdup("%s/pack", get_object_directory());
remove_temporary_files(s);
free(s);

if (is_repository_shallow())
prune_shallow(show_only);

return 0;
}

0 comments on commit 92251b1

Please sign in to comment.