return 0;
 }
 
+static int option_read_message(struct parse_opt_ctx_t *ctx,
+                              const struct option *opt, int unset)
+{
+       struct strbuf *buf = opt->value;
+       const char *arg;
+
+       if (unset)
+               BUG("-F cannot be negated");
+
+       if (ctx->opt) {
+               arg = ctx->opt;
+               ctx->opt = NULL;
+       } else if (ctx->argc > 1) {
+               ctx->argc--;
+               arg = *++ctx->argv;
+       } else
+               return opterror(opt, "requires a value", 0);
+
+       if (buf->len)
+               strbuf_addch(buf, '\n');
+       if (ctx->prefix && !is_absolute_path(arg))
+               arg = prefix_filename(ctx->prefix, arg);
+       if (strbuf_read_file(buf, arg, 0) < 0)
+               return error(_("could not read file '%s'"), arg);
+       have_message = 1;
+
+       return 0;
+}
+
 static struct strategy *get_strategy(const char *name)
 {
        int i;
        OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
                N_("merge commit message (for a non-fast-forward merge)"),
                option_parse_message),
+       { OPTION_LOWLEVEL_CALLBACK, 'F', "file", &merge_msg, N_("path"),
+               N_("read message from file"), PARSE_OPT_NONEG,
+               (parse_opt_cb *) option_read_message },
        OPT__VERBOSITY(&verbosity),
        OPT_BOOL(0, "abort", &abort_current_merge,
                N_("abort the current in-progress merge")),