diff options
author | Junio C Hamano <gitster@pobox.com> | 2014-10-14 23:38:52 +0400 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2014-10-16 01:34:45 +0400 |
commit | fb1d6dabce69bce3f28a7f442da990ef8df872ac (patch) | |
tree | e4b2b407ad99e4f8fafd38f0465cf93b5a943fbb | |
parent | 3c2dc76f015b4d52ef02a08c59a4546d00b475e1 (diff) |
clone: --dissociate option to mark that reference is only temporary
While use of the --reference option to borrow objects from an
existing local repository of the same project is an effective way to
reduce traffic when cloning a project over the network, it makes the
resulting "borrowing" repository dependent on the "borrowed"
repository. After running
git clone --reference=P $URL Q
the resulting repository Q will be broken if the borrowed repository
P disappears.
The way to allow the borrowed repository to be removed is to repack
the borrowing repository (i.e. run "git repack -a -d" in Q); while
power users may know it very well, it is not easily discoverable.
Teach a new "--dissociate" option to "git clone" to run this
repacking for the user.
Helped-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r-- | Documentation/git-clone.txt | 11 | ||||
-rw-r--r-- | builtin/clone.c | 20 | ||||
-rwxr-xr-x | t/t5700-clone-reference.sh | 17 |
3 files changed, 46 insertions, 2 deletions
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 0363d0039b..f1f2a3f7ea 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -12,7 +12,7 @@ SYNOPSIS 'git clone' [--template=<template_directory>] [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror] [-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>] - [--separate-git-dir <git dir>] + [--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--recursive | --recurse-submodules] [--] <repository> [<directory>] @@ -98,7 +98,14 @@ objects from the source repository into a pack in the cloned repository. require fewer objects to be copied from the repository being cloned, reducing network and local storage costs. + -*NOTE*: see the NOTE for the `--shared` option. +*NOTE*: see the NOTE for the `--shared` option, and also the +`--dissociate` option. + +--dissociate:: + Borrow the objects from reference repositories specified + with the `--reference` options only to reduce network + transfer and stop borrowing from them after a clone is made + by making necessary local copies of borrowed objects. --quiet:: -q:: diff --git a/builtin/clone.c b/builtin/clone.c index bbd169ceb4..e1ad4df41f 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -48,6 +48,7 @@ static int option_verbosity; static int option_progress = -1; static struct string_list option_config; static struct string_list option_reference; +static int option_dissociate; static int opt_parse_reference(const struct option *opt, const char *arg, int unset) { @@ -93,6 +94,8 @@ static struct option builtin_clone_options[] = { N_("create a shallow clone of that depth")), OPT_BOOL(0, "single-branch", &option_single_branch, N_("clone only one branch, HEAD or --branch")), + OPT_BOOL(0, "dissociate", &option_dissociate, + N_("use --reference only while cloning")), OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"), N_("separate git dir from working tree")), OPT_STRING_LIST('c', "config", &option_config, N_("key=value"), @@ -736,6 +739,16 @@ static void write_refspec_config(const char* src_ref_prefix, strbuf_release(&value); } +static void dissociate_from_references(void) +{ + static const char* argv[] = { "repack", "-a", "-d", NULL }; + + if (run_command_v_opt(argv, RUN_GIT_CMD|RUN_COMMAND_NO_STDIN)) + die(_("cannot repack to clean up")); + if (unlink(git_path("objects/info/alternates")) && errno != ENOENT) + die_errno(_("cannot unlink temporary alternates file")); +} + int cmd_clone(int argc, const char **argv, const char *prefix) { int is_bundle = 0, is_local; @@ -883,6 +896,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (option_reference.nr) setup_reference(); + else if (option_dissociate) { + warning(_("--dissociate given, but there is no --reference")); + option_dissociate = 0; + } fetch_pattern = value.buf; refspec = parse_fetch_refspec(1, &fetch_pattern); @@ -996,6 +1013,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix) transport_unlock_pack(transport); transport_disconnect(transport); + if (option_dissociate) + dissociate_from_references(); + junk_mode = JUNK_LEAVE_REPO; err = checkout(); diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh index 6537911a43..3e783fc450 100755 --- a/t/t5700-clone-reference.sh +++ b/t/t5700-clone-reference.sh @@ -198,4 +198,21 @@ test_expect_success 'clone using repo pointed at by gitfile as reference' ' test_cmp expected "$base_dir/O/.git/objects/info/alternates" ' +test_expect_success 'clone and dissociate from reference' ' + git init P && + ( + cd P && test_commit one + ) && + git clone P Q && + ( + cd Q && test_commit two + ) && + git clone --no-local --reference=P Q R && + git clone --no-local --reference=P --dissociate Q S && + # removing the reference P would corrupt R but not S + rm -fr P && + test_must_fail git -C R fsck && + git -C S fsck +' + test_done |