diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index 9de4dc5d66..8ec87ecb6b 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -8,7 +8,7 @@ git-commit - Record changes to the repository
 SYNOPSIS
 --------
 [verse]
-'git commit' [-a | --interactive | --patch] [--amend]
+'git commit' [-a | --interactive | --patch] [--amend | --reword]
 	   [(-c | -C | --fixup | --squash) <commit>] [-F <file> | -m <msg>]
 	   [--allow-empty] [--allow-empty-message] [--no-verify] [-e]
 	   [--reset-author] [--author=<author>] [--date=<date>]
@@ -99,7 +99,7 @@ OPTIONS
 	linkgit:git-rebase[1] for details.
 
 --reset-author::
-	When used with `-C`/`-c`/`--amend` options, or when committing
+	When used with `-C`/`-c`/`--amend`/`--reword` options, or when committing
 	after a conflicting cherry-pick, declare that the authorship of
 	the resulting commit now belongs to the committer. This also
 	renews the author timestamp.
@@ -229,6 +229,16 @@ variable (see linkgit:git-config[1]).
 	For example, `git commit --amend --no-edit` amends a commit
 	without changing its commit message.
 
+--reword::
+	Reword the commit message of the tip of the current branch by
+	replacing it with a new commit. The commit contents will be
+	unchanged even if there are staged changes. This is equivalent
+	to specifying `--amend --only --allow-empty` with no paths.
++
+You should understand the implications of rewriting history if you
+reword a commit that has already been published.  (See the "RECOVERING
+FROM UPSTREAM REBASE" section in linkgit:git-rebase[1].)
+
 --amend::
 	Replace the tip of the current branch by creating a new
 	commit. The recorded tree is prepared as usual (including
diff --git a/builtin/commit.c b/builtin/commit.c
index 5d91b13a5c..f7913f771a 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -107,6 +107,7 @@ static const char *author_message, *author_message_buffer;
 static char *edit_message, *use_message;
 static char *fixup_message, *squash_message;
 static int all, also, interactive, patch_interactive, only, amend, signoff;
+static int reword;
 static int edit_flag = -1; /* unspecified */
 static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
 static int config_commit_verbose = -1; /* unspecified */
@@ -1152,6 +1153,41 @@ static void finalize_deferred_config(struct wt_status *s)
 		s->ahead_behind_flags = AHEAD_BEHIND_FULL;
 }
 
+static void validate_reword_options(int argc, struct commit *current_head)
+{
+	if (!current_head)
+		die(_("You have nothing to reword."));
+	if (whence != FROM_COMMIT) {
+		if (whence == FROM_MERGE)
+			die(_("You are in the middle of a merge -- cannot "
+			      "reword."));
+		else if (is_from_cherry_pick(whence))
+			die(_("You are in the middle of a cherry-pick -- cannot"
+			      " reword."));
+		else if (is_from_rebase(whence))
+			die(_("You are in the middle of a rebase -- cannot "
+			      "reword."));
+	}
+	if (amend)
+		die(_("cannot combine --reword with --amend"));
+	if (argc)
+		die(_("cannot combine --reword with paths"));
+	if (interactive)
+		die(_("cannot combine --reword with --interactive"));
+	if (patch_interactive)
+		die(_("cannot combine --reword with --patch"));
+	if (all)
+		die(_("cannot combine --reword with --all"));
+	if (also)
+		die(_("cannot combine --reword with --include"));
+	if (only)
+		die(_("cannot combine --reword with --only"));
+	if (!edit_flag && !force_author && !force_date && !renew_authorship &&
+	    !use_message && !edit_message && !fixup_message &&
+	    !squash_message && !logfile && !have_option_m && !signoff)
+		die(_("cannot combine --reword with --no-edit"));
+}
+
 static int parse_and_validate_options(int argc, const char *argv[],
 				      const struct option *options,
 				      const char * const usage[],
@@ -1186,6 +1222,12 @@ static int parse_and_validate_options(int argc, const char *argv[],
 		else if (whence == FROM_REBASE_PICK)
 			die(_("You are in the middle of a rebase -- cannot amend."));
 	}
+	if (reword) {
+		validate_reword_options(argc, current_head);
+		amend = 1;
+		only = 1;
+		allow_empty = 1;
+	}
 	if (fixup_message && squash_message)
 		die(_("Options --squash and --fixup cannot be used together"));
 	if (use_message)
@@ -1208,7 +1250,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
 		use_message = "HEAD";
 	if (!use_message && !is_from_cherry_pick(whence) &&
 	    !is_from_rebase(whence) && renew_authorship)
-		die(_("--reset-author can be used only with -C, -c or --amend."));
+		die(_("--reset-author can be used only with -C, -c, --amend "
+		      "or --reword."));
 	if (use_message) {
 		use_message_buffer = read_commit_message(use_message);
 		if (!renew_authorship) {
@@ -1537,6 +1580,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 		OPT_BOOL('z', "null", &s.null_termination,
 			 N_("terminate entries with NUL")),
 		OPT_BOOL(0, "amend", &amend, N_("amend previous commit")),
+		OPT_BOOL(0, "reword", &reword, N_("reword the previous commit")),
 		OPT_BOOL(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")),
 		{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
 		OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
diff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh
index 110b4bf459..1ea65b426a 100755
--- a/t/t7501-commit-basic-functionality.sh
+++ b/t/t7501-commit-basic-functionality.sh
@@ -713,4 +713,60 @@ test_expect_success '--dry-run --short' '
 	git commit --dry-run --short
 '
 
+test_expect_success '--reword does not commit staged changes' '
+	echo changed >file &&
+	git add file &&
+	cat >expect <<-EOF &&
+	$(git log -1 --pretty=format:%B HEAD)
+
+	reworded
+	EOF
+	GIT_EDITOR="printf reworded >>" git commit --reword &&
+	git log -1 --pretty=format:%B >actual &&
+	test_cmp expect actual &&
+	test_cmp_rev HEAD@{1}^{tree} HEAD^{tree} &&
+	test_cmp_rev HEAD@{1}^ HEAD^ &&
+	git cat-file blob :file >actual &&
+	test_cmp file actual
+'
+
+test_reword_opt () {
+	test_expect_success C_LOCALE_OUTPUT "--reword incompatible with $1" "
+		echo 'fatal: cannot combine --reword with $1' >expect &&
+		test_must_fail git commit --reword $1 2>actual &&
+		test_cmp expect actual
+	"
+}
+
+for opt in --all --amend --include --interactive --only --patch --no-edit
+do
+	test_reword_opt $opt
+done
+
+test_expect_success C_LOCALE_OUTPUT '--reword with paths' '
+	echo "fatal: cannot combine --reword with paths" >expect &&
+	test_must_fail git commit --reword file 2>actual &&
+	test_cmp expect actual
+'
+
+test_reword_no_edit () {
+	test_expect_success "--reword $@ --no-edit" '
+		git commit --reword '"$@"' --no-edit
+	'
+}
+
+for opt in -mmessage -CHEAD^ -cHEAD --reset-author \
+		"--author=\"Commit Author <commit.author@example.com>\"" \
+		--date=yesterday --fixup=HEAD^ --squash=HEAD^ --signoff
+do
+	test_reword_no_edit "$opt"
+done
+
+test_expect_success '--reword -F' '
+	echo reworded >msg &&
+	git commit --reword -F msg --no-edit &&
+	git log -1 --pretty=format:%B >actual &&
+	test_cmp msg actual
+'
+
 test_done
