Skip to content

Commit d540b70

Browse files
Denton-Lgitster
authored andcommitted
merge: cleanup messages like commit
This change allows git-merge messages to be cleaned up with the commit.cleanup configuration or --cleanup option, just like how git-commit does it. We also give git-pull the option of --cleanup so that it can also take advantage of this change. Finally, add testing to ensure that messages are properly cleaned up. Note that some newlines that were added to the commit message were removed so that if a file were read via -F, it would be copied faithfully. Helped-by: Eric Sunshine <[email protected]> Signed-off-by: Phillip Wood <[email protected]> Signed-off-by: Denton Liu <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ca04dc9 commit d540b70

File tree

7 files changed

+128
-13
lines changed

7 files changed

+128
-13
lines changed

Documentation/merge-options.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ they run `git merge`. To make it easier to adjust such scripts to the
3232
updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
3333
set to `no` at the beginning of them.
3434

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.
38+
3539
--ff::
3640
When the merge resolves as a fast-forward, only update the branch
3741
pointer, without creating a merge commit. This is the default

builtin/merge.c

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "tag.h"
3939
#include "alias.h"
4040
#include "commit-reach.h"
41+
#include "wt-status.h"
4142

4243
#define DEFAULT_TWOHEAD (1<<0)
4344
#define DEFAULT_OCTOPUS (1<<1)
@@ -98,6 +99,9 @@ enum ff_type {
9899

99100
static enum ff_type fast_forward = FF_ALLOW;
100101

102+
static const char *cleanup_arg;
103+
static enum commit_msg_cleanup_mode cleanup_mode;
104+
101105
static int option_parse_message(const struct option *opt,
102106
const char *arg, int unset)
103107
{
@@ -249,6 +253,7 @@ static struct option builtin_merge_options[] = {
249253
N_("perform a commit if the merge succeeds (default)")),
250254
OPT_BOOL('e', "edit", &option_edit,
251255
N_("edit message before committing")),
256+
OPT_CLEANUP(&cleanup_arg),
252257
OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
253258
OPT_SET_INT_F(0, "ff-only", &fast_forward,
254259
N_("abort if fast-forward is not possible"),
@@ -612,6 +617,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
612617
return git_config_string(&pull_twohead, k, v);
613618
else if (!strcmp(k, "pull.octopus"))
614619
return git_config_string(&pull_octopus, k, v);
620+
else if (!strcmp(k, "commit.cleanup"))
621+
return git_config_string(&cleanup_arg, k, v);
615622
else if (!strcmp(k, "merge.renormalize"))
616623
option_renormalize = git_config_bool(k, v);
617624
else if (!strcmp(k, "merge.ff")) {
@@ -800,20 +807,33 @@ static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
800807
static const char merge_editor_comment[] =
801808
N_("Please enter a commit message to explain why this merge is necessary,\n"
802809
"especially if it merges an updated upstream into a topic branch.\n"
803-
"\n"
804-
"Lines starting with '%c' will be ignored, and an empty message aborts\n"
810+
"\n");
811+
812+
static const char scissors_editor_comment[] =
813+
N_("An empty message aborts the commit.\n");
814+
815+
static const char no_scissors_editor_comment[] =
816+
N_("Lines starting with '%c' will be ignored, and an empty message aborts\n"
805817
"the commit.\n");
806818

807819
static void write_merge_heads(struct commit_list *);
808820
static void prepare_to_commit(struct commit_list *remoteheads)
809821
{
810822
struct strbuf msg = STRBUF_INIT;
811823
strbuf_addbuf(&msg, &merge_msg);
812-
strbuf_addch(&msg, '\n');
813824
if (squash)
814825
BUG("the control must not reach here under --squash");
815-
if (0 < option_edit)
816-
strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
826+
if (0 < option_edit) {
827+
strbuf_addch(&msg, '\n');
828+
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
829+
wt_status_append_cut_line(&msg);
830+
strbuf_commented_addf(&msg, "\n");
831+
}
832+
strbuf_commented_addf(&msg, _(merge_editor_comment));
833+
strbuf_commented_addf(&msg, _(cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS ?
834+
scissors_editor_comment :
835+
no_scissors_editor_comment), comment_line_char);
836+
}
817837
if (signoff)
818838
append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
819839
write_merge_heads(remoteheads);
@@ -832,7 +852,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
832852
abort_commit(remoteheads, NULL);
833853

834854
read_merge_msg(&msg);
835-
strbuf_stripspace(&msg, 0 < option_edit);
855+
cleanup_message(&msg, cleanup_mode, 0);
836856
if (!msg.len)
837857
abort_commit(remoteheads, _("Empty commit message."));
838858
strbuf_release(&merge_msg);
@@ -880,7 +900,6 @@ static int finish_automerge(struct commit *head,
880900
parents = remoteheads;
881901
if (!head_subsumed || fast_forward == FF_NO)
882902
commit_list_insert(head, &parents);
883-
strbuf_addch(&merge_msg, '\n');
884903
prepare_to_commit(remoteheads);
885904
if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
886905
&result_commit, NULL, sign_commit))
@@ -1301,6 +1320,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
13011320
}
13021321
resolve_undo_clear();
13031322

1323+
if (option_edit < 0)
1324+
option_edit = default_edit_option();
1325+
1326+
cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit);
1327+
13041328
if (verbosity < 0)
13051329
show_diffstat = 0;
13061330

@@ -1386,9 +1410,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
13861410
fast_forward = FF_NO;
13871411
}
13881412

1389-
if (option_edit < 0)
1390-
option_edit = default_edit_option();
1391-
13921413
if (!use_strategies) {
13931414
if (!remoteheads)
13941415
; /* already up-to-date */

builtin/pull.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "lockfile.h"
2525
#include "wt-status.h"
2626
#include "commit-reach.h"
27+
#include "sequencer.h"
2728

2829
enum rebase_type {
2930
REBASE_INVALID = -1,
@@ -101,6 +102,7 @@ static char *opt_signoff;
101102
static char *opt_squash;
102103
static char *opt_commit;
103104
static char *opt_edit;
105+
static char *cleanup_arg;
104106
static char *opt_ff;
105107
static char *opt_verify_signatures;
106108
static int opt_autostash = -1;
@@ -168,6 +170,7 @@ static struct option pull_options[] = {
168170
OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
169171
N_("edit message before committing"),
170172
PARSE_OPT_NOARG),
173+
OPT_CLEANUP(&cleanup_arg),
171174
OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
172175
N_("allow fast-forward"),
173176
PARSE_OPT_NOARG),
@@ -644,6 +647,8 @@ static int run_merge(void)
644647
argv_array_push(&args, opt_commit);
645648
if (opt_edit)
646649
argv_array_push(&args, opt_edit);
650+
if (cleanup_arg)
651+
argv_array_pushf(&args, "--cleanup=%s", cleanup_arg);
647652
if (opt_ff)
648653
argv_array_push(&args, opt_ff);
649654
if (opt_verify_signatures)
@@ -875,6 +880,13 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
875880

876881
argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
877882

883+
if (cleanup_arg)
884+
/*
885+
* this only checks the validity of cleanup_arg; we don't need
886+
* a valid value for use_editor
887+
*/
888+
get_cleanup_mode(cleanup_arg, 0);
889+
878890
parse_repo_refspecs(argc, argv, &repo, &refspecs);
879891

880892
if (!opt_ff)

t/t5521-pull-options.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ test_expect_success 'git pull -q -v' '
7777
test_must_be_empty out &&
7878
test -s err)
7979
'
80+
test_expect_success 'git pull --cleanup errors early on invalid argument' '
81+
mkdir clonedcleanup &&
82+
(cd clonedcleanup && git init &&
83+
test_must_fail git pull --cleanup invalid "../parent" >out 2>err &&
84+
test_must_be_empty out &&
85+
test -s err)
86+
'
87+
8088

8189
test_expect_success 'git pull --force' '
8290
mkdir clonedoldstyle &&

t/t7604-merge-custom-message.sh

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,67 @@ test_expect_success 'merge --log appends to custom message' '
4949
test_cmp exp.log actual
5050
'
5151

52+
mesg_with_comment_and_newlines='
53+
# text
54+
55+
'
56+
57+
test_expect_success 'prepare file with comment line and trailing newlines' '
58+
printf "%s" "$mesg_with_comment_and_newlines" >expect
59+
'
60+
61+
test_expect_success 'cleanup commit messages (verbatim option)' '
62+
git reset --hard c1 &&
63+
git merge --cleanup=verbatim -F expect c2 &&
64+
git cat-file commit HEAD >raw &&
65+
sed -e "1,/^$/d" raw >actual &&
66+
test_cmp expect actual
67+
'
68+
69+
test_expect_success 'cleanup commit messages (whitespace option)' '
70+
git reset --hard c1 &&
71+
test_write_lines "" "# text" "" >text &&
72+
echo "# text" >expect &&
73+
git merge --cleanup=whitespace -F text c2 &&
74+
git cat-file commit HEAD >raw &&
75+
sed -e "1,/^$/d" raw >actual &&
76+
test_cmp expect actual
77+
'
78+
79+
test_expect_success 'cleanup merge messages (scissors option)' '
80+
git reset --hard c1 &&
81+
cat >text <<-\EOF &&
82+
83+
# to be kept
84+
85+
# ------------------------ >8 ------------------------
86+
# to be kept, too
87+
# ------------------------ >8 ------------------------
88+
to be removed
89+
# ------------------------ >8 ------------------------
90+
to be removed, too
91+
EOF
92+
93+
cat >expect <<-\EOF &&
94+
# to be kept
95+
96+
# ------------------------ >8 ------------------------
97+
# to be kept, too
98+
EOF
99+
git merge --cleanup=scissors -e -F text c2 &&
100+
git cat-file commit HEAD >raw &&
101+
sed -e "1,/^$/d" raw >actual &&
102+
test_cmp expect actual
103+
'
104+
105+
test_expect_success 'cleanup commit messages (strip option)' '
106+
git reset --hard c1 &&
107+
test_write_lines "" "# text" "sample" "" >text &&
108+
echo sample >expect &&
109+
git merge --cleanup=strip -F text c2 &&
110+
git cat-file commit HEAD >raw &&
111+
sed -e "1,/^$/d" raw >actual &&
112+
test_cmp expect actual
113+
'
114+
52115
test_done

wt-status.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,13 +1006,19 @@ size_t wt_status_locate_end(const char *s, size_t len)
10061006
return len;
10071007
}
10081008

1009-
void wt_status_add_cut_line(FILE *fp)
1009+
void wt_status_append_cut_line(struct strbuf *buf)
10101010
{
10111011
const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored.");
1012+
1013+
strbuf_commented_addf(buf, "%s", cut_line);
1014+
strbuf_add_commented_lines(buf, explanation, strlen(explanation));
1015+
}
1016+
1017+
void wt_status_add_cut_line(FILE *fp)
1018+
{
10121019
struct strbuf buf = STRBUF_INIT;
10131020

1014-
fprintf(fp, "%c %s", comment_line_char, cut_line);
1015-
strbuf_add_commented_lines(&buf, explanation, strlen(explanation));
1021+
wt_status_append_cut_line(&buf);
10161022
fputs(buf.buf, fp);
10171023
strbuf_release(&buf);
10181024
}

wt-status.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ struct wt_status {
129129
};
130130

131131
size_t wt_status_locate_end(const char *s, size_t len);
132+
void wt_status_append_cut_line(struct strbuf *buf);
132133
void wt_status_add_cut_line(FILE *fp);
133134
void wt_status_prepare(struct repository *r, struct wt_status *s);
134135
void wt_status_print(struct wt_status *s);

0 commit comments

Comments
 (0)