diff --git a/Documentation/config/push.txt b/Documentation/config/push.txt
index 632033638c4..e32801e6c91 100644
--- a/Documentation/config/push.txt
+++ b/Documentation/config/push.txt
@@ -1,3 +1,14 @@
+push.autoSetupRemote::
+	If set to "true" assume `--set-upstream` on default push when no
+	upstream tracking exists for the current branch; this option
+	takes effect with push.default options 'simple', 'upstream',
+	and 'current'. It is useful if by default you want new branches
+	to be pushed to the default remote (like the behavior of
+	'push.default=current') and you also want the upstream tracking
+	to be set. Workflows most likely to benefit from this option are
+	'simple' central workflows where all branches are expected to
+	have the same name on the remote.
+
 push.default::
 	Defines the action `git push` should take if no refspec is
 	given (whether from the command-line, config, or elsewhere).
diff --git a/builtin/push.c b/builtin/push.c
index 447f91f5b47..86b44f8aa71 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -195,16 +195,32 @@ static const char message_detached_head_die[] =
 	   "\n"
 	   "    git push %s HEAD:<name-of-remote-branch>\n");
 
-static const char *get_upstream_ref(struct branch *branch, const char *remote_name)
+static const char *get_upstream_ref(int flags, struct branch *branch, const char *remote_name)
 {
-	if (!branch->merge_nr || !branch->merge || !branch->remote_name)
+	if (branch->merge_nr == 0 && (flags & TRANSPORT_PUSH_AUTO_UPSTREAM)) {
+		/* if missing, assume same; set_upstream will be defined later */
+		return branch->refname;
+	}
+
+	if (!branch->merge_nr || !branch->merge || !branch->remote_name) {
+		const char *advice_autosetup_maybe = "";
+		if (!(flags & TRANSPORT_PUSH_AUTO_UPSTREAM)) {
+			advice_autosetup_maybe = _("\n"
+					   "To have this happen automatically for "
+					   "branches without a tracking\n"
+					   "upstream, see 'push.autoSetupRemote' "
+					   "in 'git help config'.\n");
+		}
 		die(_("The current branch %s has no upstream branch.\n"
 		    "To push the current branch and set the remote as upstream, use\n"
 		    "\n"
-		    "    git push --set-upstream %s %s\n"),
+		    "    git push --set-upstream %s %s\n"
+		    "%s"),
 		    branch->name,
 		    remote_name,
-		    branch->name);
+		    branch->name,
+		    advice_autosetup_maybe);
+	}
 	if (branch->merge_nr != 1)
 		die(_("The current branch %s has multiple upstream branches, "
 		    "refusing to push."), branch->name);
@@ -212,7 +228,7 @@ static const char *get_upstream_ref(struct branch *branch, const char *remote_na
 	return branch->merge[0]->src;
 }
 
-static void setup_default_push_refspecs(struct remote *remote)
+static void setup_default_push_refspecs(int *flags, struct remote *remote)
 {
 	struct branch *branch;
 	const char *dst;
@@ -244,7 +260,7 @@ static void setup_default_push_refspecs(struct remote *remote)
 	case PUSH_DEFAULT_SIMPLE:
 		if (!same_remote)
 			break;
-		if (strcmp(branch->refname, get_upstream_ref(branch, remote->name)))
+		if (strcmp(branch->refname, get_upstream_ref(*flags, branch, remote->name)))
 			die_push_simple(branch, remote);
 		break;
 
@@ -254,13 +270,21 @@ static void setup_default_push_refspecs(struct remote *remote)
 			      "your current branch '%s', without telling me what to push\n"
 			      "to update which remote branch."),
 			    remote->name, branch->name);
-		dst = get_upstream_ref(branch, remote->name);
+		dst = get_upstream_ref(*flags, branch, remote->name);
 		break;
 
 	case PUSH_DEFAULT_CURRENT:
 		break;
 	}
 
+	/*
+	 * this is a default push - if auto-upstream is enabled and there is
+	 * no upstream defined, then set it (with options 'simple', 'upstream',
+	 * and 'current').
+	 */
+	if ((*flags & TRANSPORT_PUSH_AUTO_UPSTREAM) && branch->merge_nr == 0)
+		*flags |= TRANSPORT_PUSH_SET_UPSTREAM;
+
 	refspec_appendf(&rs, "%s:%s", branch->refname, dst);
 }
 
@@ -411,7 +435,7 @@ static int do_push(int flags,
 		if (remote->push.nr) {
 			push_refspec = &remote->push;
 		} else if (!(flags & TRANSPORT_PUSH_MIRROR))
-			setup_default_push_refspecs(remote);
+			setup_default_push_refspecs(&flags, remote);
 	}
 	errs = 0;
 	url_nr = push_url_of_remote(remote, &url);
@@ -482,6 +506,10 @@ static int git_push_config(const char *k, const char *v, void *cb)
 		else
 			*flags &= ~TRANSPORT_PUSH_FOLLOW_TAGS;
 		return 0;
+	} else if (!strcmp(k, "push.autosetupremote")) {
+		if (git_config_bool(k, v))
+			*flags |= TRANSPORT_PUSH_AUTO_UPSTREAM;
+		return 0;
 	} else if (!strcmp(k, "push.gpgsign")) {
 		const char *value;
 		if (!git_config_get_value("push.gpgsign", &value)) {
diff --git a/t/t5528-push-default.sh b/t/t5528-push-default.sh
index 0d6c9869ed3..284e20fefda 100755
--- a/t/t5528-push-default.sh
+++ b/t/t5528-push-default.sh
@@ -162,6 +162,20 @@ test_expect_success 'push from/to branch with tracking fails with nothing ' '
 	test_push_failure nothing
 '
 
+test_expect_success 'push from/to new branch succeeds with upstream if push.autoSetupRemote' '
+	git checkout -b new-branch-a &&
+	test_config push.autoSetupRemote true &&
+	test_config branch.new-branch-a.remote parent1 &&
+	test_push_success upstream new-branch-a
+'
+
+test_expect_success 'push from/to new branch succeeds with simple if push.autoSetupRemote' '
+	git checkout -b new-branch-c &&
+	test_config push.autoSetupRemote true &&
+	test_config branch.new-branch-c.remote parent1 &&
+	test_push_success simple new-branch-c
+'
+
 test_expect_success '"matching" fails if none match' '
 	git init --bare empty &&
 	test_must_fail git push empty : 2>actual &&
diff --git a/transport.h b/transport.h
index 12bc08fc339..b5bf7b3e704 100644
--- a/transport.h
+++ b/transport.h
@@ -145,6 +145,7 @@ struct transport {
 #define TRANSPORT_PUSH_OPTIONS			(1<<14)
 #define TRANSPORT_RECURSE_SUBMODULES_ONLY	(1<<15)
 #define TRANSPORT_PUSH_FORCE_IF_INCLUDES	(1<<16)
+#define TRANSPORT_PUSH_AUTO_UPSTREAM		(1<<17)
 
 int transport_summary_width(const struct ref *refs);
 
