sequencer: run 'prepare-commit-msg' hook

Commit 356ee4659b ("sequencer: try to commit without forking 'git
commit'", 2017-11-24) forgot to run the 'prepare-commit-msg' hook when
creating the commit. Fix this by writing the commit message to a
different file and running the hook. Using a different file means that
if the commit is cancelled the original message file is
unchanged. Also move the checks for an empty commit so the order
matches 'git commit'.

Reported-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Helped-by: Ramsay Jones <ramsay@ramsayjones.plus.com>
Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Phillip Wood
2018-01-24 12:34:22 +00:00
committed by Junio C Hamano
parent 15cd6d3a25
commit 66618a50f9
4 changed files with 61 additions and 19 deletions

View File

@ -66,8 +66,6 @@ N_("If you wish to skip this commit, use:\n"
"Then \"git cherry-pick --continue\" will resume cherry-picking\n" "Then \"git cherry-pick --continue\" will resume cherry-picking\n"
"the remaining commits.\n"); "the remaining commits.\n");
static GIT_PATH_FUNC(git_path_commit_editmsg, "COMMIT_EDITMSG")
static const char *use_message_buffer; static const char *use_message_buffer;
static struct lock_file index_lock; /* real index */ static struct lock_file index_lock; /* real index */
static struct lock_file false_lock; /* used only for partial commits */ static struct lock_file false_lock; /* used only for partial commits */

View File

@ -29,6 +29,8 @@
const char sign_off_header[] = "Signed-off-by: "; const char sign_off_header[] = "Signed-off-by: ";
static const char cherry_picked_prefix[] = "(cherry picked from commit "; static const char cherry_picked_prefix[] = "(cherry picked from commit ";
GIT_PATH_FUNC(git_path_commit_editmsg, "COMMIT_EDITMSG")
GIT_PATH_FUNC(git_path_seq_dir, "sequencer") GIT_PATH_FUNC(git_path_seq_dir, "sequencer")
static GIT_PATH_FUNC(git_path_todo_file, "sequencer/todo") static GIT_PATH_FUNC(git_path_todo_file, "sequencer/todo")
@ -888,6 +890,31 @@ void commit_post_rewrite(const struct commit *old_head,
run_rewrite_hook(&old_head->object.oid, new_head); run_rewrite_hook(&old_head->object.oid, new_head);
} }
static int run_prepare_commit_msg_hook(struct strbuf *msg, const char *commit)
{
struct argv_array hook_env = ARGV_ARRAY_INIT;
int ret;
const char *name;
name = git_path_commit_editmsg();
if (write_message(msg->buf, msg->len, name, 0))
return -1;
argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", get_index_file());
argv_array_push(&hook_env, "GIT_EDITOR=:");
if (commit)
ret = run_hook_le(hook_env.argv, "prepare-commit-msg", name,
"commit", commit, NULL);
else
ret = run_hook_le(hook_env.argv, "prepare-commit-msg", name,
"message", NULL);
if (ret)
ret = error(_("'prepare-commit-msg' hook failed"));
argv_array_clear(&hook_env);
return ret;
}
static const char implicit_ident_advice_noconfig[] = static const char implicit_ident_advice_noconfig[] =
N_("Your name and email address were configured automatically based\n" N_("Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n" "on your username and hostname. Please check that they are accurate.\n"
@ -1048,8 +1075,9 @@ static int try_to_commit(struct strbuf *msg, const char *author,
struct commit_list *parents = NULL; struct commit_list *parents = NULL;
struct commit_extra_header *extra = NULL; struct commit_extra_header *extra = NULL;
struct strbuf err = STRBUF_INIT; struct strbuf err = STRBUF_INIT;
struct strbuf amend_msg = STRBUF_INIT; struct strbuf commit_msg = STRBUF_INIT;
char *amend_author = NULL; char *amend_author = NULL;
const char *hook_commit = NULL;
enum commit_msg_cleanup_mode cleanup; enum commit_msg_cleanup_mode cleanup;
int res = 0; int res = 0;
@ -1066,8 +1094,9 @@ static int try_to_commit(struct strbuf *msg, const char *author,
const char *orig_message = NULL; const char *orig_message = NULL;
find_commit_subject(message, &orig_message); find_commit_subject(message, &orig_message);
msg = &amend_msg; msg = &commit_msg;
strbuf_addstr(msg, orig_message); strbuf_addstr(msg, orig_message);
hook_commit = "HEAD";
} }
author = amend_author = get_author(message); author = amend_author = get_author(message);
unuse_commit_buffer(current_head, message); unuse_commit_buffer(current_head, message);
@ -1081,16 +1110,6 @@ static int try_to_commit(struct strbuf *msg, const char *author,
commit_list_insert(current_head, &parents); commit_list_insert(current_head, &parents);
} }
cleanup = (flags & CLEANUP_MSG) ? COMMIT_MSG_CLEANUP_ALL :
opts->default_msg_cleanup;
if (cleanup != COMMIT_MSG_CLEANUP_NONE)
strbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);
if (!opts->allow_empty_message && message_is_empty(msg, cleanup)) {
res = 1; /* run 'git commit' to display error message */
goto out;
}
if (write_cache_as_tree(tree.hash, 0, NULL)) { if (write_cache_as_tree(tree.hash, 0, NULL)) {
res = error(_("git write-tree failed to write a tree")); res = error(_("git write-tree failed to write a tree"));
goto out; goto out;
@ -1103,6 +1122,30 @@ static int try_to_commit(struct strbuf *msg, const char *author,
goto out; goto out;
} }
if (find_hook("prepare-commit-msg")) {
res = run_prepare_commit_msg_hook(msg, hook_commit);
if (res)
goto out;
if (strbuf_read_file(&commit_msg, git_path_commit_editmsg(),
2048) < 0) {
res = error_errno(_("unable to read commit message "
"from '%s'"),
git_path_commit_editmsg());
goto out;
}
msg = &commit_msg;
}
cleanup = (flags & CLEANUP_MSG) ? COMMIT_MSG_CLEANUP_ALL :
opts->default_msg_cleanup;
if (cleanup != COMMIT_MSG_CLEANUP_NONE)
strbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);
if (!opts->allow_empty_message && message_is_empty(msg, cleanup)) {
res = 1; /* run 'git commit' to display error message */
goto out;
}
if (commit_tree_extended(msg->buf, msg->len, tree.hash, parents, if (commit_tree_extended(msg->buf, msg->len, tree.hash, parents,
oid->hash, author, opts->gpg_sign, extra)) { oid->hash, author, opts->gpg_sign, extra)) {
res = error(_("failed to write commit object")); res = error(_("failed to write commit object"));
@ -1121,7 +1164,7 @@ static int try_to_commit(struct strbuf *msg, const char *author,
out: out:
free_commit_extra_headers(extra); free_commit_extra_headers(extra);
strbuf_release(&err); strbuf_release(&err);
strbuf_release(&amend_msg); strbuf_release(&commit_msg);
free(amend_author); free(amend_author);
return res; return res;

View File

@ -1,6 +1,7 @@
#ifndef SEQUENCER_H #ifndef SEQUENCER_H
#define SEQUENCER_H #define SEQUENCER_H
const char *git_path_commit_editmsg(void);
const char *git_path_seq_dir(void); const char *git_path_seq_dir(void);
#define APPEND_SIGNOFF_DEDUP (1u << 0) #define APPEND_SIGNOFF_DEDUP (1u << 0)

View File

@ -252,10 +252,10 @@ test_rebase () {
' '
} }
test_rebase failure -i test_rebase success -i
test_rebase failure -p test_rebase success -p
test_expect_failure 'with hook (cherry-pick)' ' test_expect_success 'with hook (cherry-pick)' '
test_when_finished "git checkout -f master" && test_when_finished "git checkout -f master" &&
git checkout -B other b && git checkout -B other b &&
git cherry-pick rebase-1 && git cherry-pick rebase-1 &&
@ -310,7 +310,7 @@ test_expect_success 'with failing hook (merge)' '
' '
test_expect_failure C_LOCALE_OUTPUT 'with failing hook (cherry-pick)' ' test_expect_success C_LOCALE_OUTPUT 'with failing hook (cherry-pick)' '
test_when_finished "git checkout -f master" && test_when_finished "git checkout -f master" &&
git checkout -B other b && git checkout -B other b &&
test_must_fail git cherry-pick rebase-1 2>actual && test_must_fail git cherry-pick rebase-1 2>actual &&