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>
diff --git a/builtin/clone.c b/builtin/clone.c
index bbd169c..e1ad4df 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -48,6 +48,7 @@
 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 @@
 		    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 @@
 	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 @@
 
 	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 @@
 	transport_unlock_pack(transport);
 	transport_disconnect(transport);
 
+	if (option_dissociate)
+		dissociate_from_references();
+
 	junk_mode = JUNK_LEAVE_REPO;
 	err = checkout();