show, log: include conflict/warning messages in --remerge-diff headers
Conflicts such as modify/delete, rename/rename, or file/directory are not representable via content conflict markers, and the normal output messages notifying users about these were dropped with --remerge-diff. While we don't want these messages randomly shown before the commit and diff headers, we do want them to still be shown; include them as part of the diff headers instead. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Elijah Newren committed
Feb 2, 2022 at 02:37 UTC
20323d104ec389505e83b9376c8ecab94e852fb8
4 files changed
+206
log-tree.c
+51
@@ -19,6 +19,7 @@
19
#include "line-log.h"
20
#include "help.h"
21
#include "range-diff.h"
22
+#include "strmap.h"
23
24
static struct decoration name_decoration = { "object names" };
25
static int decoration_loaded;
@@ -907,6 +908,52 @@ static int do_diff_combined(struct rev_info *opt, struct commit *commit)
908
return !opt->loginfo;
909
}
910
911
+static void setup_additional_headers(struct diff_options *o,
912
+ struct strmap *all_headers)
913
+{
914
+ struct hashmap_iter iter;
915
+ struct strmap_entry *entry;
916
+
917
+ /*
918
+ * Make o->additional_path_headers contain the subset of all_headers
919
+ * that match o->pathspec. If there aren't any that match o->pathspec,
920
+ * then make o->additional_path_headers be NULL.
921
+ */
922
+
923
+ if (!o->pathspec.nr) {
924
+ o->additional_path_headers = all_headers;
925
+ return;
926
+ }
927
+
928
+ o->additional_path_headers = xmalloc(sizeof(struct strmap));
929
+ strmap_init_with_options(o->additional_path_headers, NULL, 0);
930
+ strmap_for_each_entry(all_headers, &iter, entry) {
931
+ if (match_pathspec(the_repository->index, &o->pathspec,
932
+ entry->key, strlen(entry->key),
933
+ 0 /* prefix */, NULL /* seen */,
934
+ 0 /* is_dir */))
935
+ strmap_put(o->additional_path_headers,
936
+ entry->key, entry->value);
937
+ }
938
+ if (!strmap_get_size(o->additional_path_headers)) {
939
+ strmap_clear(o->additional_path_headers, 0);
940
+ FREE_AND_NULL(o->additional_path_headers);
941
+ }
942
+}
943
+
944
+static void cleanup_additional_headers(struct diff_options *o)
945
+{
946
+ if (!o->pathspec.nr) {
947
+ o->additional_path_headers = NULL;
948
+ return;
949
+ }
950
+ if (!o->additional_path_headers)
951
+ return;
952
+
953
+ strmap_clear(o->additional_path_headers, 0);
954
+ FREE_AND_NULL(o->additional_path_headers);
955
+}
956
+
957
static int do_remerge_diff(struct rev_info *opt,
958
struct commit_list *parents,
959
struct object_id *oid,
@@ -924,6 +971,8 @@ static int do_remerge_diff(struct rev_info *opt,
971
/* Setup merge options */
972
init_merge_options(&o, the_repository);
973
o.show_rename_progress = 0;
974
+ o.record_conflict_msgs_as_headers = 1;
975
+ o.msg_header_prefix = "remerge";
976
977
ctx.abbrev = DEFAULT_ABBREV;
978
format_commit_message(parent1, "%h (%s)", &parent1_desc, &ctx);
@@ -940,10 +989,12 @@ static int do_remerge_diff(struct rev_info *opt,
989
merge_incore_recursive(&o, bases, parent1, parent2, &res);
990
991
/* Show the diff */
992
+ setup_additional_headers(&opt->diffopt, res.path_messages);
993
diff_tree_oid(&res.tree->object.oid, oid, "", &opt->diffopt);
994
log_tree_diff_flush(opt);
995
996
/* Cleanup */
997
+ cleanup_additional_headers(&opt->diffopt);
998
strbuf_release(&parent1_desc);
999
strbuf_release(&parent2_desc);
1000
merge_finalize(&o, &res);
merge-ort.c
+1
@@ -4585,6 +4585,7 @@ redo:
4585
trace2_region_leave("merge", "process_entries", opt->repo);
4586
4587
/* Set return values */
4588
+ result->path_messages = &opt->priv->output;
4589
result->tree = parse_tree_indirect(&working_tree_oid);
4590
/* existence of conflicted entries implies unclean */
4591
result->clean &= strmap_empty(&opt->priv->conflicted);
merge-ort.h
+10
@@ -5,6 +5,7 @@
5
6
struct commit;
7
struct tree;
8
+struct strmap;
9
10
struct merge_result {
11
/*
@@ -23,6 +24,15 @@ struct merge_result {
24
*/
25
struct tree *tree;
26
27
+ /*
28
+ * Special messages and conflict notices for various paths
29
+ *
30
+ * This is a map of pathnames to strbufs. It contains various
31
+ * warning/conflict/notice messages (possibly multiple per path)
32
+ * that callers may want to use.
33
+ */
34
+ struct strmap *path_messages;
35
+
36
/*
37
* Additional metadata used by merge_switch_to_result() or future calls
38
* to merge_incore_*(). Includes data needed to update the index (if
t/t4069-remerge-diff.sh
+144
@@ -60,6 +60,7 @@ test_expect_success 'remerge-diff with both a resolved conflict and an unrelated
60
git log -1 --oneline ab_resolution >tmp &&
61
cat <<-EOF >>tmp &&
62
diff --git a/numbers b/numbers
63
+ remerge CONFLICT (content): Merge conflict in numbers
64
index a1fb731..6875544 100644
65
--- a/numbers
66
+++ b/numbers
@@ -88,4 +89,147 @@ test_expect_success 'remerge-diff with both a resolved conflict and an unrelated
89
test_cmp expect actual
90
'
91
92
+test_expect_success 'setup non-content conflicts' '
93
+ git switch --orphan base &&
94
+
95
+ test_write_lines 1 2 3 4 5 6 7 8 9 >numbers &&
96
+ test_write_lines a b c d e f g h i >letters &&
97
+ test_write_lines in the way >content &&
98
+ git add numbers letters content &&
99
+ git commit -m base &&
100
+
101
+ git branch side1 &&
102
+ git branch side2 &&
103
+
104
+ git checkout side1 &&
105
+ test_write_lines 1 2 three 4 5 6 7 8 9 >numbers &&
106
+ git mv letters letters_side1 &&
107
+ git mv content file_or_directory &&
108
+ git add numbers &&
109
+ git commit -m side1 &&
110
+
111
+ git checkout side2 &&
112
+ git rm numbers &&
113
+ git mv letters letters_side2 &&
114
+ mkdir file_or_directory &&
115
+ echo hello >file_or_directory/world &&
116
+ git add file_or_directory/world &&
117
+ git commit -m side2 &&
118
+
119
+ git checkout -b resolution side1 &&
120
+ test_must_fail git merge side2 &&
121
+ test_write_lines 1 2 three 4 5 6 7 8 9 >numbers &&
122
+ git add numbers &&
123
+ git add letters_side1 &&
124
+ git rm letters &&
125
+ git rm letters_side2 &&
126
+ git add file_or_directory~HEAD &&
127
+ git mv file_or_directory~HEAD wanted_content &&
128
+ git commit -m resolved
129
+'
130
+
131
+test_expect_success 'remerge-diff with non-content conflicts' '
132
+ git log -1 --oneline resolution >tmp &&
133
+ cat <<-EOF >>tmp &&
134
+ diff --git a/file_or_directory~HASH (side1) b/wanted_content
135
+ similarity index 100%
136
+ rename from file_or_directory~HASH (side1)
137
+ rename to wanted_content
138
+ remerge CONFLICT (file/directory): directory in the way of file_or_directory from HASH (side1); moving it to file_or_directory~HASH (side1) instead.
139
+ diff --git a/letters b/letters
140
+ remerge CONFLICT (rename/rename): letters renamed to letters_side1 in HASH (side1) and to letters_side2 in HASH (side2).
141
+ diff --git a/letters_side2 b/letters_side2
142
+ deleted file mode 100644
143
+ index b236ae5..0000000
144
+ --- a/letters_side2
145
+ +++ /dev/null
146
+ @@ -1,9 +0,0 @@
147
+ -a
148
+ -b
149
+ -c
150
+ -d
151
+ -e
152
+ -f
153
+ -g
154
+ -h
155
+ -i
156
+ diff --git a/numbers b/numbers
157
+ remerge CONFLICT (modify/delete): numbers deleted in HASH (side2) and modified in HASH (side1). Version HASH (side1) of numbers left in tree.
158
+ EOF
159
+ # We still have some sha1 hashes above; rip them out so test works
160
+ # with sha256
161
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect &&
162
+
163
+ git show --oneline --remerge-diff resolution >tmp &&
164
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual &&
165
+ test_cmp expect actual
166
+'
167
+
168
+test_expect_success 'remerge-diff w/ diff-filter=U: all conflict headers, no diff content' '
169
+ git log -1 --oneline resolution >tmp &&
170
+ cat <<-EOF >>tmp &&
171
+ diff --git a/file_or_directory~HASH (side1) b/file_or_directory~HASH (side1)
172
+ remerge CONFLICT (file/directory): directory in the way of file_or_directory from HASH (side1); moving it to file_or_directory~HASH (side1) instead.
173
+ diff --git a/letters b/letters
174
+ remerge CONFLICT (rename/rename): letters renamed to letters_side1 in HASH (side1) and to letters_side2 in HASH (side2).
175
+ diff --git a/numbers b/numbers
176
+ remerge CONFLICT (modify/delete): numbers deleted in HASH (side2) and modified in HASH (side1). Version HASH (side1) of numbers left in tree.
177
+ EOF
178
+ # We still have some sha1 hashes above; rip them out so test works
179
+ # with sha256
180
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect &&
181
+
182
+ git show --oneline --remerge-diff --diff-filter=U resolution >tmp &&
183
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual &&
184
+ test_cmp expect actual
185
+'
186
+
187
+test_expect_success 'remerge-diff w/ diff-filter=R: relevant file + conflict header' '
188
+ git log -1 --oneline resolution >tmp &&
189
+ cat <<-EOF >>tmp &&
190
+ diff --git a/file_or_directory~HASH (side1) b/wanted_content
191
+ similarity index 100%
192
+ rename from file_or_directory~HASH (side1)
193
+ rename to wanted_content
194
+ remerge CONFLICT (file/directory): directory in the way of file_or_directory from HASH (side1); moving it to file_or_directory~HASH (side1) instead.
195
+ EOF
196
+ # We still have some sha1 hashes above; rip them out so test works
197
+ # with sha256
198
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect &&
199
+
200
+ git show --oneline --remerge-diff --diff-filter=R resolution >tmp &&
201
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual &&
202
+ test_cmp expect actual
203
+'
204
+
205
+test_expect_success 'remerge-diff w/ pathspec: limits to relevant file including conflict header' '
206
+ git log -1 --oneline resolution >tmp &&
207
+ cat <<-EOF >>tmp &&
208
+ diff --git a/letters b/letters
209
+ remerge CONFLICT (rename/rename): letters renamed to letters_side1 in HASH (side1) and to letters_side2 in HASH (side2).
210
+ diff --git a/letters_side2 b/letters_side2
211
+ deleted file mode 100644
212
+ index b236ae5..0000000
213
+ --- a/letters_side2
214
+ +++ /dev/null
215
+ @@ -1,9 +0,0 @@
216
+ -a
217
+ -b
218
+ -c
219
+ -d
220
+ -e
221
+ -f
222
+ -g
223
+ -h
224
+ -i
225
+ EOF
226
+ # We still have some sha1 hashes above; rip them out so test works
227
+ # with sha256
228
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect &&
229
+
230
+ git show --oneline --remerge-diff --full-history resolution -- "letters*" >tmp &&
231
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual &&
232
+ test_cmp expect actual
233
+'
234
+
235
test_done