Merge branch 'bp/commit-p-editor' into maint

* bp/commit-p-editor:
  run-command: mark run_hook_with_custom_index as deprecated
  merge hook tests: fix and update tests
  merge: fix GIT_EDITOR override for commit hook
  commit: fix patch hunk editing with "commit -p -m"
  test patch hunk editing with "commit -p -m"
  merge hook tests: use 'test_must_fail' instead of '!'
  merge hook tests: fix missing '&&' in test
This commit is contained in:
Junio C Hamano
2014-04-08 12:07:06 -07:00
10 changed files with 137 additions and 39 deletions

View File

@ -53,10 +53,10 @@ struct checkout_opts {
static int post_checkout_hook(struct commit *old, struct commit *new, static int post_checkout_hook(struct commit *old, struct commit *new,
int changed) int changed)
{ {
return run_hook(NULL, "post-checkout", return run_hook_le(NULL, "post-checkout",
sha1_to_hex(old ? old->object.sha1 : null_sha1), sha1_to_hex(old ? old->object.sha1 : null_sha1),
sha1_to_hex(new ? new->object.sha1 : null_sha1), sha1_to_hex(new ? new->object.sha1 : null_sha1),
changed ? "1" : "0", NULL); changed ? "1" : "0", NULL);
/* "new" can be NULL when checking out from the index before /* "new" can be NULL when checking out from the index before
a commit exists. */ a commit exists. */

View File

@ -660,8 +660,8 @@ static int checkout(void)
commit_locked_index(lock_file)) commit_locked_index(lock_file))
die(_("unable to write new index file")); die(_("unable to write new index file"));
err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1), err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1),
sha1_to_hex(sha1), "1", NULL); sha1_to_hex(sha1), "1", NULL);
if (!err && option_recursive) if (!err && option_recursive)
err = run_command_v_opt(argv_submodule, RUN_GIT_CMD); err = run_command_v_opt(argv_submodule, RUN_GIT_CMD);

View File

@ -612,7 +612,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
/* This checks and barfs if author is badly specified */ /* This checks and barfs if author is badly specified */
determine_author_info(author_ident); determine_author_info(author_ident);
if (!no_verify && run_hook(index_file, "pre-commit", NULL)) if (!no_verify && run_commit_hook(use_editor, index_file, "pre-commit", NULL))
return 0; return 0;
if (squash_message) { if (squash_message) {
@ -866,8 +866,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
return 0; return 0;
} }
if (run_hook(index_file, "prepare-commit-msg", if (run_commit_hook(use_editor, index_file, "prepare-commit-msg",
git_path(commit_editmsg), hook_arg1, hook_arg2, NULL)) git_path(commit_editmsg), hook_arg1, hook_arg2, NULL))
return 0; return 0;
if (use_editor) { if (use_editor) {
@ -883,7 +883,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
} }
if (!no_verify && if (!no_verify &&
run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) { run_commit_hook(use_editor, index_file, "commit-msg", git_path(commit_editmsg), NULL)) {
return 0; return 0;
} }
@ -1067,8 +1067,6 @@ static int parse_and_validate_options(int argc, const char *argv[],
use_editor = 0; use_editor = 0;
if (0 <= edit_flag) if (0 <= edit_flag)
use_editor = edit_flag; use_editor = edit_flag;
if (!use_editor)
setenv("GIT_EDITOR", ":", 1);
/* Sanity check options */ /* Sanity check options */
if (amend && !current_head) if (amend && !current_head)
@ -1445,6 +1443,29 @@ static int run_rewrite_hook(const unsigned char *oldsha1,
return finish_command(&proc); return finish_command(&proc);
} }
int run_commit_hook(int editor_is_used, const char *index_file, const char *name, ...)
{
const char *hook_env[3] = { NULL };
char index[PATH_MAX];
va_list args;
int ret;
snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
hook_env[0] = index;
/*
* Let the hook know that no editor will be launched.
*/
if (!editor_is_used)
hook_env[1] = "GIT_EDITOR=:";
va_start(args, name);
ret = run_hook_ve(hook_env, name, args);
va_end(args);
return ret;
}
int cmd_commit(int argc, const char **argv, const char *prefix) int cmd_commit(int argc, const char **argv, const char *prefix)
{ {
static struct wt_status s; static struct wt_status s;
@ -1669,7 +1690,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
"not exceeded, and then \"git reset HEAD\" to recover.")); "not exceeded, and then \"git reset HEAD\" to recover."));
rerere(0); rerere(0);
run_hook(get_index_file(), "post-commit", NULL); run_commit_hook(use_editor, get_index_file(), "post-commit", NULL);
if (amend && !no_post_rewrite) { if (amend && !no_post_rewrite) {
struct notes_rewrite_cfg *cfg; struct notes_rewrite_cfg *cfg;
cfg = init_copy_notes_for_rewrite("amend"); cfg = init_copy_notes_for_rewrite("amend");

View File

@ -179,7 +179,7 @@ static int need_to_gc(void)
else if (!too_many_loose_objects()) else if (!too_many_loose_objects())
return 0; return 0;
if (run_hook(NULL, "pre-auto-gc", NULL)) if (run_hook_le(NULL, "pre-auto-gc", NULL))
return 0; return 0;
return 1; return 1;
} }

View File

@ -421,7 +421,7 @@ static void finish(struct commit *head_commit,
} }
/* Run a post-merge hook */ /* Run a post-merge hook */
run_hook(NULL, "post-merge", squash ? "1" : "0", NULL); run_hook_le(NULL, "post-merge", squash ? "1" : "0", NULL);
strbuf_release(&reflog_message); strbuf_release(&reflog_message);
} }
@ -821,8 +821,8 @@ static void prepare_to_commit(struct commit_list *remoteheads)
if (0 < option_edit) if (0 < option_edit)
strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char); strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
write_merge_msg(&msg); write_merge_msg(&msg);
if (run_hook(get_index_file(), "prepare-commit-msg", if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg",
git_path("MERGE_MSG"), "merge", NULL, NULL)) git_path("MERGE_MSG"), "merge", NULL))
abort_commit(remoteheads, NULL); abort_commit(remoteheads, NULL);
if (0 < option_edit) { if (0 < option_edit) {
if (launch_editor(git_path("MERGE_MSG"), NULL, NULL)) if (launch_editor(git_path("MERGE_MSG"), NULL, NULL))

View File

@ -304,4 +304,7 @@ extern void check_commit_signature(const struct commit* commit, struct signature
int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused); int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused);
LAST_ARG_MUST_BE_NULL
extern int run_commit_hook(int editor_is_used, const char *index_file, const char *name, ...);
#endif /* COMMIT_H */ #endif /* COMMIT_H */

View File

@ -760,13 +760,11 @@ char *find_hook(const char *name)
return path; return path;
} }
int run_hook(const char *index_file, const char *name, ...) int run_hook_ve(const char *const *env, const char *name, va_list args)
{ {
struct child_process hook; struct child_process hook;
struct argv_array argv = ARGV_ARRAY_INIT; struct argv_array argv = ARGV_ARRAY_INIT;
const char *p, *env[2]; const char *p;
char index[PATH_MAX];
va_list args;
int ret; int ret;
p = find_hook(name); p = find_hook(name);
@ -775,23 +773,45 @@ int run_hook(const char *index_file, const char *name, ...)
argv_array_push(&argv, p); argv_array_push(&argv, p);
va_start(args, name);
while ((p = va_arg(args, const char *))) while ((p = va_arg(args, const char *)))
argv_array_push(&argv, p); argv_array_push(&argv, p);
va_end(args);
memset(&hook, 0, sizeof(hook)); memset(&hook, 0, sizeof(hook));
hook.argv = argv.argv; hook.argv = argv.argv;
hook.env = env;
hook.no_stdin = 1; hook.no_stdin = 1;
hook.stdout_to_stderr = 1; hook.stdout_to_stderr = 1;
if (index_file) {
snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
env[0] = index;
env[1] = NULL;
hook.env = env;
}
ret = run_command(&hook); ret = run_command(&hook);
argv_array_clear(&argv); argv_array_clear(&argv);
return ret; return ret;
} }
int run_hook_le(const char *const *env, const char *name, ...)
{
va_list args;
int ret;
va_start(args, name);
ret = run_hook_ve(env, name, args);
va_end(args);
return ret;
}
int run_hook_with_custom_index(const char *index_file, const char *name, ...)
{
const char *hook_env[3] = { NULL };
char index[PATH_MAX];
va_list args;
int ret;
snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
hook_env[0] = index;
va_start(args, name);
ret = run_hook_ve(hook_env, name, args);
va_end(args);
return ret;
}

View File

@ -47,7 +47,12 @@ int run_command(struct child_process *);
extern char *find_hook(const char *name); extern char *find_hook(const char *name);
LAST_ARG_MUST_BE_NULL LAST_ARG_MUST_BE_NULL
extern int run_hook(const char *index_file, const char *name, ...); extern int run_hook_le(const char *const *env, const char *name, ...);
extern int run_hook_ve(const char *const *env, const char *name, va_list args);
LAST_ARG_MUST_BE_NULL
__attribute__((deprecated))
extern int run_hook_with_custom_index(const char *index_file, const char *name, ...);
#define RUN_COMMAND_NO_STDIN 1 #define RUN_COMMAND_NO_STDIN 1
#define RUN_GIT_CMD 2 /*If this is to be git sub-command */ #define RUN_GIT_CMD 2 /*If this is to be git sub-command */

View File

@ -134,14 +134,26 @@ test_expect_success 'with hook (-c)' '
test_expect_success 'with hook (merge)' ' test_expect_success 'with hook (merge)' '
head=`git rev-parse HEAD` && test_when_finished "git checkout -f master" &&
git checkout -b other HEAD@{1} && git checkout -B other HEAD@{1} &&
echo "more" >> file && echo "more" >>file &&
git add file && git add file &&
git commit -m other && git commit -m other &&
git checkout - && git checkout - &&
git merge other && git merge --no-ff other &&
test "`git log -1 --pretty=format:%s`" = merge test "`git log -1 --pretty=format:%s`" = "merge (no editor)"
'
test_expect_success 'with hook and editor (merge)' '
test_when_finished "git checkout -f master" &&
git checkout -B other HEAD@{1} &&
echo "more" >>file &&
git add file &&
git commit -m other &&
git checkout - &&
env GIT_EDITOR="\"\$FAKE_EDITOR\"" git merge --no-ff -e other &&
test "`git log -1 --pretty=format:%s`" = "merge"
' '
cat > "$HOOK" <<'EOF' cat > "$HOOK" <<'EOF'
@ -151,34 +163,37 @@ EOF
test_expect_success 'with failing hook' ' test_expect_success 'with failing hook' '
test_when_finished "git checkout -f master" &&
head=`git rev-parse HEAD` && head=`git rev-parse HEAD` &&
echo "more" >> file && echo "more" >> file &&
git add file && git add file &&
! GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head test_must_fail env GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head
' '
test_expect_success 'with failing hook (--no-verify)' ' test_expect_success 'with failing hook (--no-verify)' '
test_when_finished "git checkout -f master" &&
head=`git rev-parse HEAD` && head=`git rev-parse HEAD` &&
echo "more" >> file && echo "more" >> file &&
git add file && git add file &&
! GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify -c $head test_must_fail env GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify -c $head
' '
test_expect_success 'with failing hook (merge)' ' test_expect_success 'with failing hook (merge)' '
test_when_finished "git checkout -f master" &&
git checkout -B other HEAD@{1} && git checkout -B other HEAD@{1} &&
echo "more" >> file && echo "more" >> file &&
git add file && git add file &&
rm -f "$HOOK" && rm -f "$HOOK" &&
git commit -m other && git commit -m other &&
write_script "$HOOK" <<-EOF write_script "$HOOK" <<-EOF &&
exit 1 exit 1
EOF EOF
git checkout - && git checkout - &&
test_must_fail git merge other test_must_fail git merge --no-ff other
' '

34
t/t7514-commit-patch.sh Executable file
View File

@ -0,0 +1,34 @@
#!/bin/sh
test_description='hunk edit with "commit -p -m"'
. ./test-lib.sh
if ! test_have_prereq PERL
then
skip_all="skipping '$test_description' tests, perl not available"
test_done
fi
test_expect_success 'setup (initial)' '
echo line1 >file &&
git add file &&
git commit -m commit1
'
test_expect_success 'edit hunk "commit -p -m message"' '
test_when_finished "rm -f editor_was_started" &&
rm -f editor_was_started &&
echo more >>file &&
echo e | env GIT_EDITOR=": >editor_was_started" git commit -p -m commit2 file &&
test -r editor_was_started
'
test_expect_success 'edit hunk "commit --dry-run -p -m message"' '
test_when_finished "rm -f editor_was_started" &&
rm -f editor_was_started &&
echo more >>file &&
echo e | env GIT_EDITOR=": >editor_was_started" git commit -p -m commit3 file &&
test -r editor_was_started
'
test_done