merge: add scissors line on merge conflict

This fixes a bug where the scissors line is placed after the Conflicts: section, in the case where a merge conflict occurs and commit.cleanup = scissors. Next, if commit.cleanup = scissors is specified, don't produce a scissors line in commit if one already exists in the MERGE_MSG file. Helped-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Denton Liu <liu.denton@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Denton Liu committed Apr 17, 2019 at 11:23 UTC 1055997e2fc707a15baf232df2ac481055c14321
4 files changed +82 -7
Documentation/merge-options.txt
+5 -2
@@ -33,8 +33,11 @@ updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
33 set to `no` at the beginning of them.
34
35 --cleanup=<mode>::
36 - This option determines how the merge message will be cleaned up
37 - before commiting. See linkgit:git-commit[1] for more details.
36 + This option determines how the merge message will be cleaned up before
37 + commiting. See linkgit:git-commit[1] for more details. In addition, if
38 + the '<mode>' is given a value of `scissors`, scissors will be appended
39 + to `MERGE_MSG` before being passed on to the commit machinery in the
40 + case of a merge conflict.
41
42 --ff::
43 When the merge resolves as a fast-forward, only update the branch
builtin/commit.c
+17 -5
@@ -668,6 +668,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
668 const char *hook_arg2 = NULL;
669 int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
670 int old_display_comment_prefix;
671 + int merge_contains_scissors = 0;
672
673 /* This checks and barfs if author is badly specified */
674 determine_author_info(author_ident);
@@ -728,6 +729,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
729 strbuf_addbuf(&sb, &message);
730 hook_arg1 = "message";
731 } else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
732 + size_t merge_msg_start;
733 +
734 /*
735 * prepend SQUASH_MSG here if it exists and a
736 * "merge --squash" was originally performed
@@ -738,8 +741,16 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
741 hook_arg1 = "squash";
742 } else
743 hook_arg1 = "merge";
744 +
745 + merge_msg_start = sb.len;
746 if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0)
747 die_errno(_("could not read MERGE_MSG"));
748 +
749 + if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
750 + wt_status_locate_end(sb.buf + merge_msg_start,
751 + sb.len - merge_msg_start) <
752 + sb.len - merge_msg_start)
753 + merge_contains_scissors = 1;
754 } else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
755 if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
756 die_errno(_("could not read SQUASH_MSG"));
@@ -807,7 +818,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
818 struct ident_split ci, ai;
819
820 if (whence != FROM_COMMIT) {
810 - if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
821 + if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
822 + !merge_contains_scissors)
823 wt_status_add_cut_line(s->fp);
824 status_printf_ln(s, GIT_COLOR_NORMAL,
825 whence == FROM_MERGE
@@ -832,10 +844,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
844 _("Please enter the commit message for your changes."
845 " Lines starting\nwith '%c' will be ignored, and an empty"
846 " message aborts the commit.\n"), comment_line_char);
835 - else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
836 - whence == FROM_COMMIT)
837 - wt_status_add_cut_line(s->fp);
838 - else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
847 + else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
848 + if (whence == FROM_COMMIT && !merge_contains_scissors)
849 + wt_status_add_cut_line(s->fp);
850 + } else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
851 status_printf(s, GIT_COLOR_NORMAL,
852 _("Please enter the commit message for your changes."
853 " Lines starting\n"
builtin/merge.c
+14
@@ -920,6 +920,20 @@ static int suggest_conflicts(void)
920 filename = git_path_merge_msg(the_repository);
921 fp = xfopen(filename, "a");
922
923 + /*
924 + * We can't use cleanup_mode because if we're not using the editor,
925 + * get_cleanup_mode will return COMMIT_MSG_CLEANUP_SPACE instead, even
926 + * though the message is meant to be processed later by git-commit.
927 + * Thus, we will get the cleanup mode which is returned when we _are_
928 + * using an editor.
929 + */
930 + if (get_cleanup_mode(cleanup_arg, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
931 + fputc('\n', fp);
932 + wt_status_add_cut_line(fp);
933 + /* comments out the newline from append_conflicts_hint */
934 + fputc(comment_line_char, fp);
935 + }
936 +
937 append_conflicts_hint(&the_index, &msgbuf);
938 fputs(msgbuf.buf, fp);
939 strbuf_release(&msgbuf);
t/t7600-merge.sh
+46
@@ -246,6 +246,52 @@ test_expect_success 'merge --squash c3 with c7' '
246 test_cmp expect actual
247 '
248
249 +test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
250 + git config commit.cleanup scissors &&
251 + git reset --hard c3 &&
252 + test_must_fail git merge c7 &&
253 + cat result.9z >file &&
254 + git commit --no-edit -a &&
255 +
256 + cat >expect <<-\EOF &&
257 + Merge tag '"'"'c7'"'"'
258 +
259 + # ------------------------ >8 ------------------------
260 + # Do not modify or remove the line above.
261 + # Everything below it will be ignored.
262 + #
263 + # Conflicts:
264 + # file
265 + EOF
266 + git cat-file commit HEAD >raw &&
267 + sed -e '1,/^$/d' raw >actual &&
268 + test_i18ncmp expect actual
269 +'
270 +
271 +test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
272 + git config commit.cleanup scissors &&
273 + git reset --hard c3 &&
274 + test_must_fail git merge --squash c7 &&
275 + cat result.9z >file &&
276 + git commit --no-edit -a &&
277 +
278 + cat >expect <<-EOF &&
279 + Squashed commit of the following:
280 +
281 + $(git show -s c7)
282 +
283 + # ------------------------ >8 ------------------------
284 + # Do not modify or remove the line above.
285 + # Everything below it will be ignored.
286 + #
287 + # Conflicts:
288 + # file
289 + EOF
290 + git cat-file commit HEAD >raw &&
291 + sed -e '1,/^$/d' raw >actual &&
292 + test_i18ncmp expect actual
293 +'
294 +
295 test_debug 'git log --graph --decorate --oneline --all'
296
297 test_expect_success 'merge c1 with c2 and c3' '