Merge branch 'js/merge-edit-option'
* js/merge-edit-option: Teach merge the '[-e|--edit]' option Conflicts: builtin/merge.c
This commit is contained in:
commit
3dfbe68fc2
@ -7,6 +7,12 @@ With --no-commit perform the merge but pretend the merge
|
|||||||
failed and do not autocommit, to give the user a chance to
|
failed and do not autocommit, to give the user a chance to
|
||||||
inspect and further tweak the merge result before committing.
|
inspect and further tweak the merge result before committing.
|
||||||
|
|
||||||
|
--edit::
|
||||||
|
-e::
|
||||||
|
+
|
||||||
|
Invoke editor before committing successful merge to further
|
||||||
|
edit the default merge message.
|
||||||
|
|
||||||
--ff::
|
--ff::
|
||||||
--no-ff::
|
--no-ff::
|
||||||
Do not generate a merge commit if the merge resolved as
|
Do not generate a merge commit if the merge resolved as
|
||||||
|
109
builtin/merge.c
109
builtin/merge.c
@ -46,7 +46,7 @@ static const char * const builtin_merge_usage[] = {
|
|||||||
|
|
||||||
static int show_diffstat = 1, shortlog_len, squash;
|
static int show_diffstat = 1, shortlog_len, squash;
|
||||||
static int option_commit = 1, allow_fast_forward = 1;
|
static int option_commit = 1, allow_fast_forward = 1;
|
||||||
static int fast_forward_only;
|
static int fast_forward_only, option_edit;
|
||||||
static int allow_trivial = 1, have_message;
|
static int allow_trivial = 1, have_message;
|
||||||
static struct strbuf merge_msg;
|
static struct strbuf merge_msg;
|
||||||
static struct commit_list *remoteheads;
|
static struct commit_list *remoteheads;
|
||||||
@ -189,6 +189,8 @@ static struct option builtin_merge_options[] = {
|
|||||||
"create a single commit instead of doing a merge"),
|
"create a single commit instead of doing a merge"),
|
||||||
OPT_BOOLEAN(0, "commit", &option_commit,
|
OPT_BOOLEAN(0, "commit", &option_commit,
|
||||||
"perform a commit if the merge succeeds (default)"),
|
"perform a commit if the merge succeeds (default)"),
|
||||||
|
OPT_BOOLEAN('e', "edit", &option_edit,
|
||||||
|
"edit message before committing"),
|
||||||
OPT_BOOLEAN(0, "ff", &allow_fast_forward,
|
OPT_BOOLEAN(0, "ff", &allow_fast_forward,
|
||||||
"allow fast-forward (default)"),
|
"allow fast-forward (default)"),
|
||||||
OPT_BOOLEAN(0, "ff-only", &fast_forward_only,
|
OPT_BOOLEAN(0, "ff-only", &fast_forward_only,
|
||||||
@ -843,30 +845,54 @@ static void add_strategies(const char *string, unsigned attr)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_merge_msg(void)
|
static void write_merge_msg(struct strbuf *msg)
|
||||||
{
|
{
|
||||||
int fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666);
|
int fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
die_errno(_("Could not open '%s' for writing"),
|
die_errno(_("Could not open '%s' for writing"),
|
||||||
git_path("MERGE_MSG"));
|
git_path("MERGE_MSG"));
|
||||||
if (write_in_full(fd, merge_msg.buf, merge_msg.len) != merge_msg.len)
|
if (write_in_full(fd, msg->buf, msg->len) != msg->len)
|
||||||
die_errno(_("Could not write to '%s'"), git_path("MERGE_MSG"));
|
die_errno(_("Could not write to '%s'"), git_path("MERGE_MSG"));
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_merge_msg(void)
|
static void read_merge_msg(struct strbuf *msg)
|
||||||
{
|
{
|
||||||
strbuf_reset(&merge_msg);
|
strbuf_reset(msg);
|
||||||
if (strbuf_read_file(&merge_msg, git_path("MERGE_MSG"), 0) < 0)
|
if (strbuf_read_file(msg, git_path("MERGE_MSG"), 0) < 0)
|
||||||
die_errno(_("Could not read from '%s'"), git_path("MERGE_MSG"));
|
die_errno(_("Could not read from '%s'"), git_path("MERGE_MSG"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void run_prepare_commit_msg(void)
|
static void write_merge_state(void);
|
||||||
|
static void abort_commit(const char *err_msg)
|
||||||
{
|
{
|
||||||
write_merge_msg();
|
if (err_msg)
|
||||||
|
error("%s", err_msg);
|
||||||
|
fprintf(stderr,
|
||||||
|
_("Not committing merge; use 'git commit' to complete the merge.\n"));
|
||||||
|
write_merge_state();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prepare_to_commit(void)
|
||||||
|
{
|
||||||
|
struct strbuf msg = STRBUF_INIT;
|
||||||
|
strbuf_addbuf(&msg, &merge_msg);
|
||||||
|
strbuf_addch(&msg, '\n');
|
||||||
|
write_merge_msg(&msg);
|
||||||
run_hook(get_index_file(), "prepare-commit-msg",
|
run_hook(get_index_file(), "prepare-commit-msg",
|
||||||
git_path("MERGE_MSG"), "merge", NULL, NULL);
|
git_path("MERGE_MSG"), "merge", NULL, NULL);
|
||||||
read_merge_msg();
|
if (option_edit) {
|
||||||
|
if (launch_editor(git_path("MERGE_MSG"), NULL, NULL))
|
||||||
|
abort_commit(NULL);
|
||||||
|
}
|
||||||
|
read_merge_msg(&msg);
|
||||||
|
stripspace(&msg, option_edit);
|
||||||
|
if (!msg.len)
|
||||||
|
abort_commit(_("Empty commit message."));
|
||||||
|
strbuf_release(&merge_msg);
|
||||||
|
strbuf_addbuf(&merge_msg, &msg);
|
||||||
|
strbuf_release(&msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int merge_trivial(struct commit *head)
|
static int merge_trivial(struct commit *head)
|
||||||
@ -880,7 +906,7 @@ static int merge_trivial(struct commit *head)
|
|||||||
parent->next = xmalloc(sizeof(*parent->next));
|
parent->next = xmalloc(sizeof(*parent->next));
|
||||||
parent->next->item = remoteheads->item;
|
parent->next->item = remoteheads->item;
|
||||||
parent->next->next = NULL;
|
parent->next->next = NULL;
|
||||||
run_prepare_commit_msg();
|
prepare_to_commit();
|
||||||
commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
|
commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
|
||||||
finish(head, result_commit, "In-index merge");
|
finish(head, result_commit, "In-index merge");
|
||||||
drop_save();
|
drop_save();
|
||||||
@ -909,9 +935,9 @@ static int finish_automerge(struct commit *head,
|
|||||||
for (j = remoteheads; j; j = j->next)
|
for (j = remoteheads; j; j = j->next)
|
||||||
pptr = &commit_list_insert(j->item, pptr)->next;
|
pptr = &commit_list_insert(j->item, pptr)->next;
|
||||||
}
|
}
|
||||||
free_commit_list(remoteheads);
|
|
||||||
strbuf_addch(&merge_msg, '\n');
|
strbuf_addch(&merge_msg, '\n');
|
||||||
run_prepare_commit_msg();
|
prepare_to_commit();
|
||||||
|
free_commit_list(remoteheads);
|
||||||
commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL);
|
commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL);
|
||||||
strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
|
strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
|
||||||
finish(head, result_commit, buf.buf);
|
finish(head, result_commit, buf.buf);
|
||||||
@ -1018,6 +1044,36 @@ static int setup_with_upstream(const char ***argv)
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void write_merge_state(void)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct commit_list *j;
|
||||||
|
struct strbuf buf = STRBUF_INIT;
|
||||||
|
|
||||||
|
for (j = remoteheads; j; j = j->next)
|
||||||
|
strbuf_addf(&buf, "%s\n",
|
||||||
|
sha1_to_hex(j->item->object.sha1));
|
||||||
|
fd = open(git_path("MERGE_HEAD"), O_WRONLY | O_CREAT, 0666);
|
||||||
|
if (fd < 0)
|
||||||
|
die_errno(_("Could not open '%s' for writing"),
|
||||||
|
git_path("MERGE_HEAD"));
|
||||||
|
if (write_in_full(fd, buf.buf, buf.len) != buf.len)
|
||||||
|
die_errno(_("Could not write to '%s'"), git_path("MERGE_HEAD"));
|
||||||
|
close(fd);
|
||||||
|
strbuf_addch(&merge_msg, '\n');
|
||||||
|
write_merge_msg(&merge_msg);
|
||||||
|
fd = open(git_path("MERGE_MODE"), O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||||
|
if (fd < 0)
|
||||||
|
die_errno(_("Could not open '%s' for writing"),
|
||||||
|
git_path("MERGE_MODE"));
|
||||||
|
strbuf_reset(&buf);
|
||||||
|
if (!allow_fast_forward)
|
||||||
|
strbuf_addf(&buf, "no-ff");
|
||||||
|
if (write_in_full(fd, buf.buf, buf.len) != buf.len)
|
||||||
|
die_errno(_("Could not write to '%s'"), git_path("MERGE_MODE"));
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
int cmd_merge(int argc, const char **argv, const char *prefix)
|
int cmd_merge(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
unsigned char result_tree[20];
|
unsigned char result_tree[20];
|
||||||
@ -1423,33 +1479,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
|||||||
|
|
||||||
if (squash)
|
if (squash)
|
||||||
finish(head_commit, NULL, NULL);
|
finish(head_commit, NULL, NULL);
|
||||||
else {
|
else
|
||||||
int fd;
|
write_merge_state();
|
||||||
struct commit_list *j;
|
|
||||||
|
|
||||||
for (j = remoteheads; j; j = j->next)
|
|
||||||
strbuf_addf(&buf, "%s\n",
|
|
||||||
sha1_to_hex(j->item->object.sha1));
|
|
||||||
fd = open(git_path("MERGE_HEAD"), O_WRONLY | O_CREAT, 0666);
|
|
||||||
if (fd < 0)
|
|
||||||
die_errno(_("Could not open '%s' for writing"),
|
|
||||||
git_path("MERGE_HEAD"));
|
|
||||||
if (write_in_full(fd, buf.buf, buf.len) != buf.len)
|
|
||||||
die_errno(_("Could not write to '%s'"), git_path("MERGE_HEAD"));
|
|
||||||
close(fd);
|
|
||||||
strbuf_addch(&merge_msg, '\n');
|
|
||||||
write_merge_msg();
|
|
||||||
fd = open(git_path("MERGE_MODE"), O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
|
||||||
if (fd < 0)
|
|
||||||
die_errno(_("Could not open '%s' for writing"),
|
|
||||||
git_path("MERGE_MODE"));
|
|
||||||
strbuf_reset(&buf);
|
|
||||||
if (!allow_fast_forward)
|
|
||||||
strbuf_addf(&buf, "no-ff");
|
|
||||||
if (write_in_full(fd, buf.buf, buf.len) != buf.len)
|
|
||||||
die_errno(_("Could not write to '%s'"), git_path("MERGE_MODE"));
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (merge_was_ok) {
|
if (merge_was_ok) {
|
||||||
fprintf(stderr, _("Automatic merge went well; "
|
fprintf(stderr, _("Automatic merge went well; "
|
||||||
|
@ -643,4 +643,27 @@ test_expect_success 'amending no-ff merge commit' '
|
|||||||
|
|
||||||
test_debug 'git log --graph --decorate --oneline --all'
|
test_debug 'git log --graph --decorate --oneline --all'
|
||||||
|
|
||||||
|
cat >editor <<\EOF
|
||||||
|
#!/bin/sh
|
||||||
|
# Add a new message string that was not in the template
|
||||||
|
(
|
||||||
|
echo "Merge work done on the side branch c1"
|
||||||
|
echo
|
||||||
|
cat <"$1"
|
||||||
|
) >"$1.tmp" && mv "$1.tmp" "$1"
|
||||||
|
# strip comments and blank lines from end of message
|
||||||
|
sed -e '/^#/d' < "$1" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' > expected
|
||||||
|
EOF
|
||||||
|
chmod 755 editor
|
||||||
|
|
||||||
|
test_expect_success 'merge --no-ff --edit' '
|
||||||
|
git reset --hard c0 &&
|
||||||
|
EDITOR=./editor git merge --no-ff --edit c1 &&
|
||||||
|
verify_parents $c0 $c1 &&
|
||||||
|
git cat-file commit HEAD >raw &&
|
||||||
|
grep "work done on the side branch" raw &&
|
||||||
|
sed "1,/^$/d" >actual raw &&
|
||||||
|
test_cmp actual expected
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
Loading…
x
Reference in New Issue
Block a user