Skip to content

Commit 20323d1

Browse files
newrengitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 95433ee commit 20323d1

File tree

4 files changed

+206
-0
lines changed

4 files changed

+206
-0
lines changed

log-tree.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "line-log.h"
2020
#include "help.h"
2121
#include "range-diff.h"
22+
#include "strmap.h"
2223

2324
static struct decoration name_decoration = { "object names" };
2425
static int decoration_loaded;
@@ -907,6 +908,52 @@ static int do_diff_combined(struct rev_info *opt, struct commit *commit)
907908
return !opt->loginfo;
908909
}
909910

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+
910957
static int do_remerge_diff(struct rev_info *opt,
911958
struct commit_list *parents,
912959
struct object_id *oid,
@@ -924,6 +971,8 @@ static int do_remerge_diff(struct rev_info *opt,
924971
/* Setup merge options */
925972
init_merge_options(&o, the_repository);
926973
o.show_rename_progress = 0;
974+
o.record_conflict_msgs_as_headers = 1;
975+
o.msg_header_prefix = "remerge";
927976

928977
ctx.abbrev = DEFAULT_ABBREV;
929978
format_commit_message(parent1, "%h (%s)", &parent1_desc, &ctx);
@@ -940,10 +989,12 @@ static int do_remerge_diff(struct rev_info *opt,
940989
merge_incore_recursive(&o, bases, parent1, parent2, &res);
941990

942991
/* Show the diff */
992+
setup_additional_headers(&opt->diffopt, res.path_messages);
943993
diff_tree_oid(&res.tree->object.oid, oid, "", &opt->diffopt);
944994
log_tree_diff_flush(opt);
945995

946996
/* Cleanup */
997+
cleanup_additional_headers(&opt->diffopt);
947998
strbuf_release(&parent1_desc);
948999
strbuf_release(&parent2_desc);
9491000
merge_finalize(&o, &res);

merge-ort.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4585,6 +4585,7 @@ static void merge_ort_nonrecursive_internal(struct merge_options *opt,
45854585
trace2_region_leave("merge", "process_entries", opt->repo);
45864586

45874587
/* Set return values */
4588+
result->path_messages = &opt->priv->output;
45884589
result->tree = parse_tree_indirect(&working_tree_oid);
45894590
/* existence of conflicted entries implies unclean */
45904591
result->clean &= strmap_empty(&opt->priv->conflicted);

merge-ort.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
struct commit;
77
struct tree;
8+
struct strmap;
89

910
struct merge_result {
1011
/*
@@ -23,6 +24,15 @@ struct merge_result {
2324
*/
2425
struct tree *tree;
2526

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+
2636
/*
2737
* Additional metadata used by merge_switch_to_result() or future calls
2838
* to merge_incore_*(). Includes data needed to update the index (if

t/t4069-remerge-diff.sh

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ test_expect_success 'remerge-diff with both a resolved conflict and an unrelated
6060
git log -1 --oneline ab_resolution >tmp &&
6161
cat <<-EOF >>tmp &&
6262
diff --git a/numbers b/numbers
63+
remerge CONFLICT (content): Merge conflict in numbers
6364
index a1fb731..6875544 100644
6465
--- a/numbers
6566
+++ b/numbers
@@ -88,4 +89,147 @@ test_expect_success 'remerge-diff with both a resolved conflict and an unrelated
8889
test_cmp expect actual
8990
'
9091

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+
91235
test_done

0 commit comments

Comments
 (0)