diff --git a/builtin/clone.c b/builtin/clone.c
index 2a2a03bf76..0ab4494bcd 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -1393,6 +1393,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 			   branch_top.buf, reflog_msg.buf, transport,
 			   !is_local);
 
+	for (ref = mapped_refs; ref; ref = ref->next) {
+		if (ref->peer_ref &&
+		    !strcmp(ref->peer_ref->name,
+			    "refs/remotes/origin/suggested-hooks")) {
+			fprintf(stderr, _("The remote has suggested hooks in refs/remotes/origin/suggested-hooks.\n"
+					  "Run `git hook autoupdate` to download them, install them, and turn on automatic update of hooks.\n"));
+			break;
+		}
+	}
+
 	update_head(our_head_points_at, remote_head, reflog_msg.buf);
 
 	/*
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 769af53ca4..0618d1f091 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -28,6 +28,7 @@
 #include "promisor-remote.h"
 #include "commit-graph.h"
 #include "shallow.h"
+#include "hook.h"
 
 #define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
 
@@ -84,6 +85,7 @@ static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
 static int fetch_write_commit_graph = -1;
 static int stdin_refspecs = 0;
 static int negotiate_only;
+static int hook_autoupdate;
 
 static int git_fetch_config(const char *k, const char *v, void *cb)
 {
@@ -123,6 +125,11 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
 		return 0;
 	}
 
+	if (!strcmp(k, "hook.autoupdate")) {
+		hook_autoupdate = git_config_bool(k, v);
+		return 0;
+	}
+
 	return git_default_config(k, v, cb);
 }
 
@@ -1313,6 +1320,20 @@ static int consume_refs(struct transport *transport, struct ref *ref_map)
 				 ref_map);
 	transport_unlock_pack(transport);
 	trace2_region_leave("fetch", "consume_refs", the_repository);
+
+	if (hook_autoupdate) {
+		struct ref *ref;
+
+		for (ref = ref_map; ref; ref = ref->next) {
+			if (ref->peer_ref &&
+			    !strcmp(ref->peer_ref->name,
+				    "refs/remotes/origin/suggested-hooks")) {
+				hook_update_suggested();
+				break;
+			}
+		}
+	}
+
 	return ret;
 }
 
diff --git a/builtin/hook.c b/builtin/hook.c
index c79a961e80..26d657a48a 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -139,6 +139,13 @@ static int run(int argc, const char **argv, const char *prefix)
 	return rc;
 }
 
+static int autoupdate(int argc, const char **argv, const char *prefix)
+{
+	git_config_set("hook.autoupdate", "true");
+	hook_update_suggested();
+	return 0;
+}
+
 int cmd_hook(int argc, const char **argv, const char *prefix)
 {
 	const char *run_hookdir = NULL;
@@ -152,10 +159,6 @@ int cmd_hook(int argc, const char **argv, const char *prefix)
 	argc = parse_options(argc, argv, prefix, builtin_hook_options,
 			     builtin_hook_usage, PARSE_OPT_KEEP_UNKNOWN);
 
-	/* after the parse, we should have "<command> <hookname> <args...>" */
-	if (argc < 2)
-		usage_with_options(builtin_hook_usage, builtin_hook_options);
-
 	git_config(git_default_config, NULL);
 
 
@@ -185,6 +188,8 @@ int cmd_hook(int argc, const char **argv, const char *prefix)
 		return list(argc, argv, prefix);
 	if (!strcmp(argv[0], "run"))
 		return run(argc, argv, prefix);
+	if (!strcmp(argv[0], "autoupdate"))
+		return autoupdate(argc, argv, prefix);
 
 	usage_with_options(builtin_hook_usage, builtin_hook_options);
 }
diff --git a/hook.c b/hook.c
index 3ccacb72fa..5730e6e501 100644
--- a/hook.c
+++ b/hook.c
@@ -4,6 +4,12 @@
 #include "config.h"
 #include "run-command.h"
 #include "prompt.h"
+#include "commit.h"
+#include "object.h"
+#include "refs.h"
+#include "tree-walk.h"
+#include "tree.h"
+#include "streaming.h"
 
 /*
  * NEEDSWORK: Doesn't look like there is a list of all possible hooks;
@@ -515,3 +521,81 @@ int run_hooks(const char *hookname, struct run_hooks_opt *options)
 
 	return cb_data.rc;
 }
+
+static int is_hook(const char *filename)
+{
+	int i;
+
+	for (i = 0; i < hook_name_count; i++) {
+		if (!strcmp(filename, hook_name[i]))
+			return 1;
+	}
+	return 0;
+}
+
+void hook_update_suggested(void)
+{
+	struct object_id oid;
+	struct object *obj;
+	struct tree *tree;
+	struct tree_desc desc;
+	struct name_entry entry;
+	struct strbuf path = STRBUF_INIT;
+
+	if (read_ref("refs/remotes/origin/suggested-hooks", &oid)) {
+		warning(_("no such ref refs/remotes/origin/suggested-hooks, not updating hooks"));
+		return;
+	}
+
+	obj = parse_object(the_repository, &oid);
+	if (obj == NULL) {
+		warning(_("object pointed to by refs/remotes/origin/suggested-hooks '%s' does not exist"),
+			oid_to_hex(&oid));
+		return;
+	}
+	if (obj->type != OBJ_COMMIT) {
+		warning(_("object pointed to by refs/remotes/origin/suggested-hooks '%s' is not a commit"),
+			oid_to_hex(&oid));
+		return;
+	}
+
+	tree = get_commit_tree((struct commit *) obj);
+	if (parse_tree(tree)) {
+		warning(_("could not parse tree"));
+		return;
+	}
+
+	init_tree_desc(&desc, tree->buffer, tree->size);
+	while (tree_entry(&desc, &entry)) {
+		int fd;
+
+		if (!is_hook(entry.path)) {
+			warning(_("file '%s' is not a hook; ignoring"),
+				entry.path);
+			continue;
+		}
+		if (S_ISDIR(entry.mode) || S_ISGITLINK(entry.mode)) {
+			warning(_("file '%s' is not an ordinary file; ignoring"),
+				entry.path);
+			continue;
+		}
+
+		strbuf_reset(&path);
+		strbuf_git_path(&path, "hooks/%s", entry.path);
+		fd = open(path.buf, O_WRONLY | O_CREAT, 0755);
+		if (fd < 0) {
+			warning_errno(_("could not create file '%s'; skipping this hook"),
+				      path.buf);
+			continue;
+		}
+		if (stream_blob_to_fd(fd, &entry.oid, NULL, 1)) {
+			warning(_("could not write to file '%s'; skipping this hook"),
+				path.buf);
+			continue;
+		}
+		close(fd);
+	}
+	strbuf_release(&path);
+
+	return;
+}
diff --git a/hook.h b/hook.h
index d902166408..b0bfd3719b 100644
--- a/hook.h
+++ b/hook.h
@@ -140,3 +140,5 @@ int run_hooks(const char *hookname, struct run_hooks_opt *options);
 void free_hook(struct hook *ptr);
 /* Empties the list at 'head', calling 'free_hook()' on each entry */
 void clear_hook_list(struct list_head *head);
+
+void hook_update_suggested(void);
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index c0688467e7..21b96a4999 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -752,6 +752,42 @@ test_expect_success 'batch missing blob request does not inadvertently try to fe
 	git clone --filter=blob:limit=0 "file://$(pwd)/server" client
 '
 
+test_expect_success 'detect suggested hook branch during clone' '
+	rm -rf server client &&
+
+	test_create_repo server &&
+	echo "echo foo" >server/pre-commit &&
+	git -C server add pre-commit &&
+	test_commit -C server hook-and-not-hook &&
+	git -C server checkout -b suggested-hooks &&
+	git clone server client 2>err &&
+	test_i18ngrep "The remote has suggested hooks" err
+'
+
+test_expect_success 'autoupdate' '
+	git -C client hook autoupdate &&
+
+	# Check correct config written
+	git -C client config --local hook.autoupdate >actual &&
+	echo "true" >expect &&
+	test_cmp expect actual &&
+
+	# Check hook written
+	cat client/.git/hooks/pre-commit >actual &&
+	echo "echo foo" >expect &&
+	test_cmp expect actual &&
+
+	# Install new hook and fetch it
+	echo "echo bar" >server/pre-commit &&
+	git -C server commit -am "new hook" &&
+	git -C client fetch &&
+
+	# Check new hook written
+	cat client/.git/hooks/pre-commit >actual &&
+	echo "echo bar" >expect &&
+	test_cmp expect actual
+'
+
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
 
