Skip to content

Commit 2eb5469

Browse files
committed
Merge branch 'dg/local-mod-error-messages'
* dg/local-mod-error-messages: t7609: test merge and checkout error messages unpack_trees: group error messages by type merge-recursive: distinguish "removed" and "overwritten" messages merge-recursive: porcelain messages for checkout Turn unpack_trees_options.msgs into an array + enum Conflicts: t/t3400-rebase.sh
2 parents a0b6a9d + e935e62 commit 2eb5469

13 files changed

+340
-81
lines changed

Documentation/technical/api-tree-walking.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ information.
4242

4343
* `data` can be anything the `fn` callback would want to use.
4444

45+
* `show_all_errors` tells whether to stop at the first error or not.
46+
4547
Initializing
4648
------------
4749

builtin/checkout.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ static int merge_working_tree(struct checkout_opts *opts,
376376
topts.src_index = &the_index;
377377
topts.dst_index = &the_index;
378378

379-
topts.msgs.not_uptodate_file = "You have local changes to '%s'; cannot switch branches.";
379+
set_porcelain_error_msgs(topts.msgs, "checkout");
380380

381381
refresh_cache(REFRESH_QUIET);
382382

@@ -395,6 +395,7 @@ static int merge_working_tree(struct checkout_opts *opts,
395395
topts.dir = xcalloc(1, sizeof(*topts.dir));
396396
topts.dir->flags |= DIR_SHOW_IGNORED;
397397
topts.dir->exclude_per_dir = ".gitignore";
398+
topts.show_all_errors = 1;
398399
tree = parse_tree_indirect(old->commit ?
399400
old->commit->object.sha1 :
400401
(unsigned char *)EMPTY_TREE_SHA1_BIN);

builtin/merge.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,8 @@ int checkout_fast_forward(const unsigned char *head, const unsigned char *remote
704704
opts.verbose_update = 1;
705705
opts.merge = 1;
706706
opts.fn = twoway_merge;
707-
opts.msgs = get_porcelain_error_msgs();
707+
opts.show_all_errors = 1;
708+
set_porcelain_error_msgs(opts.msgs, "merge");
708709

709710
trees[nr_trees] = parse_tree_indirect(head);
710711
if (!trees[nr_trees++])

merge-recursive.c

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ static int git_merge_trees(int index_only,
179179
opts.fn = threeway_merge;
180180
opts.src_index = &the_index;
181181
opts.dst_index = &the_index;
182-
opts.msgs = get_porcelain_error_msgs();
182+
set_porcelain_error_msgs(opts.msgs, "merge");
183183

184184
init_tree_desc_from_tree(t+0, common);
185185
init_tree_desc_from_tree(t+1, head);
@@ -1173,26 +1173,48 @@ static int process_entry(struct merge_options *o,
11731173
return clean_merge;
11741174
}
11751175

1176-
struct unpack_trees_error_msgs get_porcelain_error_msgs(void)
1176+
void set_porcelain_error_msgs(const char **msgs, const char *cmd)
11771177
{
1178-
struct unpack_trees_error_msgs msgs = {
1179-
/* would_overwrite */
1180-
"Your local changes to '%s' would be overwritten by merge. Aborting.",
1181-
/* not_uptodate_file */
1182-
"Your local changes to '%s' would be overwritten by merge. Aborting.",
1183-
/* not_uptodate_dir */
1184-
"Updating '%s' would lose untracked files in it. Aborting.",
1185-
/* would_lose_untracked */
1186-
"Untracked working tree file '%s' would be %s by merge. Aborting",
1187-
/* bind_overlap -- will not happen here */
1188-
NULL,
1189-
};
1190-
if (advice_commit_before_merge) {
1191-
msgs.would_overwrite = msgs.not_uptodate_file =
1192-
"Your local changes to '%s' would be overwritten by merge. Aborting.\n"
1193-
"Please, commit your changes or stash them before you can merge.";
1194-
}
1195-
return msgs;
1178+
const char *msg;
1179+
char *tmp;
1180+
const char *cmd2 = strcmp(cmd, "checkout") ? cmd : "switch branches";
1181+
if (advice_commit_before_merge)
1182+
msg = "Your local changes to the following files would be overwritten by %s:\n%%s"
1183+
"Please, commit your changes or stash them before you can %s.";
1184+
else
1185+
msg = "Your local changes to the following files would be overwritten by %s:\n%%s";
1186+
tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen(cmd2) - 2);
1187+
sprintf(tmp, msg, cmd, cmd2);
1188+
msgs[ERROR_WOULD_OVERWRITE] = tmp;
1189+
msgs[ERROR_NOT_UPTODATE_FILE] = tmp;
1190+
1191+
msgs[ERROR_NOT_UPTODATE_DIR] =
1192+
"Updating the following directories would lose untracked files in it:\n%s";
1193+
1194+
if (advice_commit_before_merge)
1195+
msg = "The following untracked working tree files would be %s by %s:\n%%s"
1196+
"Please move or remove them before you can %s.";
1197+
else
1198+
msg = "The following untracked working tree files would be %s by %s:\n%%s";
1199+
tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen("removed") + strlen(cmd2) - 4);
1200+
sprintf(tmp, msg, "removed", cmd, cmd2);
1201+
msgs[ERROR_WOULD_LOSE_UNTRACKED_REMOVED] = tmp;
1202+
tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen("overwritten") + strlen(cmd2) - 4);
1203+
sprintf(tmp, msg, "overwritten", cmd, cmd2);
1204+
msgs[ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN] = tmp;
1205+
1206+
/*
1207+
* Special case: ERROR_BIND_OVERLAP refers to a pair of paths, we
1208+
* cannot easily display it as a list.
1209+
*/
1210+
msgs[ERROR_BIND_OVERLAP] = "Entry '%s' overlaps with '%s'. Cannot bind.";
1211+
1212+
msgs[ERROR_SPARSE_NOT_UPTODATE_FILE] =
1213+
"Cannot update sparse checkout: the following entries are not up-to-date:\n%s";
1214+
msgs[ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN] =
1215+
"The following Working tree files would be overwritten by sparse checkout update:\n%s";
1216+
msgs[ERROR_WOULD_LOSE_ORPHANED_REMOVED] =
1217+
"The following Working tree files would be removed by sparse checkout update:\n%s";
11961218
}
11971219

11981220
int merge_trees(struct merge_options *o,

merge-recursive.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ struct merge_options {
2323
struct string_list current_directory_set;
2424
};
2525

26-
/* Return a list of user-friendly error messages to be used by merge */
27-
struct unpack_trees_error_msgs get_porcelain_error_msgs(void);
26+
/*
27+
* Sets the list of user-friendly error messages to be used by the
28+
* command "cmd" (either merge or checkout)
29+
*/
30+
void set_porcelain_error_msgs(const char **msgs, const char *cmd);
2831

2932
/* merge_trees() but with recursive ancestor consolidation */
3033
int merge_recursive(struct merge_options *o,

t/t3030-merge-recursive.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ test_expect_success 'fail if the index has unresolved entries' '
294294
grep "You have not concluded your merge" out &&
295295
rm -f .git/MERGE_HEAD &&
296296
test_must_fail git merge "$c5" 2> out &&
297-
grep "Your local changes to .* would be overwritten by merge." out
297+
grep "Your local changes to the following files would be overwritten by merge:" out
298298
'
299299

300300
test_expect_success 'merge-recursive remove conflict' '

t/t3400-rebase.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ test_expect_success 'setup: recover' '
153153
test_expect_success 'Show verbose error when HEAD could not be detached' '
154154
>B &&
155155
test_must_fail git rebase topic 2>output.err >output.out &&
156-
grep "Untracked working tree file .B. would be overwritten" output.err
156+
grep "The following untracked working tree files would be overwritten by checkout:" output.err &&
157+
grep B output.err
157158
'
158159
rm -f B
159160

t/t3404-rebase-interactive.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,9 @@ test_expect_success 'abort with error when new base cannot be checked out' '
150150
git rm --cached file1 &&
151151
git commit -m "remove file in base" &&
152152
test_must_fail git rebase -i master > output 2>&1 &&
153-
grep "Untracked working tree file .file1. would be overwritten" \
153+
grep "The following untracked working tree files would be overwritten by checkout:" \
154154
output &&
155+
grep "file1" output &&
155156
! test -d .git/rebase-merge &&
156157
git reset --hard HEAD^
157158
'

t/t7609-merge-co-error-msgs.sh

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#!/bin/sh
2+
3+
test_description='unpack-trees error messages'
4+
5+
. ./test-lib.sh
6+
7+
8+
test_expect_success 'setup' '
9+
echo one >one &&
10+
git add one &&
11+
git commit -a -m First &&
12+
13+
git checkout -b branch &&
14+
echo two >two &&
15+
echo three >three &&
16+
echo four >four &&
17+
echo five >five &&
18+
git add two three four five &&
19+
git commit -m Second &&
20+
21+
git checkout master &&
22+
echo other >two &&
23+
echo other >three &&
24+
echo other >four &&
25+
echo other >five
26+
'
27+
28+
cat >expect <<\EOF
29+
error: The following untracked working tree files would be overwritten by merge:
30+
two
31+
three
32+
four
33+
five
34+
Please move or remove them before you can merge.
35+
EOF
36+
37+
test_expect_success 'untracked files overwritten by merge' '
38+
test_must_fail git merge branch 2>out &&
39+
test_cmp out expect
40+
'
41+
42+
cat >expect <<\EOF
43+
error: Your local changes to the following files would be overwritten by merge:
44+
two
45+
three
46+
four
47+
Please, commit your changes or stash them before you can merge.
48+
error: The following untracked working tree files would be overwritten by merge:
49+
five
50+
Please move or remove them before you can merge.
51+
EOF
52+
53+
test_expect_success 'untracked files or local changes ovewritten by merge' '
54+
git add two &&
55+
git add three &&
56+
git add four &&
57+
test_must_fail git merge branch 2>out &&
58+
test_cmp out expect
59+
'
60+
61+
cat >expect <<\EOF
62+
error: Your local changes to the following files would be overwritten by checkout:
63+
rep/two
64+
rep/one
65+
Please, commit your changes or stash them before you can switch branches.
66+
EOF
67+
68+
test_expect_success 'cannot switch branches because of local changes' '
69+
git add five &&
70+
mkdir rep &&
71+
echo one >rep/one &&
72+
echo two >rep/two &&
73+
git add rep/one rep/two &&
74+
git commit -m Fourth &&
75+
git checkout master &&
76+
echo uno >rep/one &&
77+
echo dos >rep/two &&
78+
test_must_fail git checkout branch 2>out &&
79+
test_cmp out expect
80+
'
81+
82+
cat >expect <<\EOF
83+
error: Your local changes to the following files would be overwritten by checkout:
84+
rep/two
85+
rep/one
86+
Please, commit your changes or stash them before you can switch branches.
87+
EOF
88+
89+
test_expect_success 'not uptodate file porcelain checkout error' '
90+
git add rep/one rep/two &&
91+
test_must_fail git checkout branch 2>out &&
92+
test_cmp out expect
93+
'
94+
95+
cat >expect <<\EOF
96+
error: Updating the following directories would lose untracked files in it:
97+
rep2
98+
rep
99+
100+
EOF
101+
102+
test_expect_success 'not_uptodate_dir porcelain checkout error' '
103+
git init uptodate &&
104+
cd uptodate &&
105+
mkdir rep &&
106+
mkdir rep2 &&
107+
touch rep/foo &&
108+
touch rep2/foo &&
109+
git add rep/foo rep2/foo &&
110+
git commit -m init &&
111+
git checkout -b branch &&
112+
git rm rep -r &&
113+
git rm rep2 -r &&
114+
>rep &&
115+
>rep2 &&
116+
git add rep rep2&&
117+
git commit -m "added test as a file" &&
118+
git checkout master &&
119+
>rep/untracked-file &&
120+
>rep2/untracked-file &&
121+
test_must_fail git checkout branch 2>out &&
122+
test_cmp out ../expect
123+
'
124+
125+
test_done

tree-walk.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "cache.h"
22
#include "tree-walk.h"
3+
#include "unpack-trees.h"
34
#include "tree.h"
45

56
static const char *get_mode(const char *str, unsigned int *modep)
@@ -310,6 +311,7 @@ static void free_extended_entry(struct tree_desc_x *t)
310311
int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
311312
{
312313
int ret = 0;
314+
int error = 0;
313315
struct name_entry *entry = xmalloc(n*sizeof(*entry));
314316
int i;
315317
struct tree_desc_x *tx = xcalloc(n, sizeof(*tx));
@@ -377,8 +379,11 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
377379
if (!mask)
378380
break;
379381
ret = info->fn(n, mask, dirmask, entry, info);
380-
if (ret < 0)
381-
break;
382+
if (ret < 0) {
383+
error = ret;
384+
if (!info->show_all_errors)
385+
break;
386+
}
382387
mask &= ret;
383388
ret = 0;
384389
for (i = 0; i < n; i++)
@@ -389,7 +394,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
389394
for (i = 0; i < n; i++)
390395
free_extended_entry(tx + i);
391396
free(tx);
392-
return ret;
397+
return error;
393398
}
394399

395400
static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char *result, unsigned *mode)

0 commit comments

Comments
 (0)