Skip to content

Commit 71b3ef1

Browse files
committed
Merge branch 'mm/conflict-advice'
* mm/conflict-advice: Be more user-friendly when refusing to do something because of conflict. Conflicts: Documentation/config.txt advice.c advice.h
2 parents f922df8 + d38a30d commit 71b3ef1

File tree

9 files changed

+93
-13
lines changed

9 files changed

+93
-13
lines changed

Documentation/config.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ advice.*::
130130
Advice shown when linkgit:git-merge[1] refuses to
131131
merge to avoid overwritting local changes.
132132
Default: true.
133+
resolveConflict::
134+
Advices shown by various commands when conflicts
135+
prevent the operation from being performed.
136+
Default: true.
133137
implicitIdentity::
134138
Advice on how to set your identity configuration when
135139
your information is guessed from the system username and

advice.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
int advice_push_nonfastforward = 1;
44
int advice_status_hints = 1;
55
int advice_commit_before_merge = 1;
6+
int advice_resolve_conflict = 1;
67
int advice_implicit_identity = 1;
78

89
static struct {
@@ -12,6 +13,7 @@ static struct {
1213
{ "pushnonfastforward", &advice_push_nonfastforward },
1314
{ "statushints", &advice_status_hints },
1415
{ "commitbeforemerge", &advice_commit_before_merge },
16+
{ "resolveconflict", &advice_resolve_conflict },
1517
{ "implicitidentity", &advice_implicit_identity },
1618
};
1719

@@ -29,3 +31,17 @@ int git_default_advice_config(const char *var, const char *value)
2931

3032
return 0;
3133
}
34+
35+
void NORETURN die_resolve_conflict(const char *me)
36+
{
37+
if (advice_resolve_conflict)
38+
/*
39+
* Message used both when 'git commit' fails and when
40+
* other commands doing a merge do.
41+
*/
42+
die("'%s' is not possible because you have unmerged files.\n"
43+
"Please, fix them up in the work tree, and then use 'git add/rm <file>' as\n"
44+
"appropriate to mark resolution and make a commit, or use 'git commit -a'.", me);
45+
else
46+
die("'%s' is not possible because you have unmerged files.", me);
47+
}

advice.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
#ifndef ADVICE_H
22
#define ADVICE_H
33

4+
#include "git-compat-util.h"
5+
46
extern int advice_push_nonfastforward;
57
extern int advice_status_hints;
68
extern int advice_commit_before_merge;
9+
extern int advice_resolve_conflict;
710
extern int advice_implicit_identity;
811

912
int git_default_advice_config(const char *var, const char *value);
1013

14+
extern void NORETURN die_resolve_conflict(const char *me);
15+
1116
#endif /* ADVICE_H */

builtin-commit.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,16 @@ static void create_base_index(void)
258258
exit(128); /* We've already reported the error, finish dying */
259259
}
260260

261+
static void refresh_cache_or_die(int refresh_flags)
262+
{
263+
/*
264+
* refresh_flags contains REFRESH_QUIET, so the only errors
265+
* are for unmerged entries.
266+
*/
267+
if (refresh_cache(refresh_flags | REFRESH_IN_PORCELAIN))
268+
die_resolve_conflict("commit");
269+
}
270+
261271
static char *prepare_index(int argc, const char **argv, const char *prefix, int is_status)
262272
{
263273
int fd;
@@ -297,7 +307,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
297307
if (all || (also && pathspec && *pathspec)) {
298308
int fd = hold_locked_index(&index_lock, 1);
299309
add_files_to_cache(also ? prefix : NULL, pathspec, 0);
300-
refresh_cache(refresh_flags);
310+
refresh_cache_or_die(refresh_flags);
301311
if (write_cache(fd, active_cache, active_nr) ||
302312
close_lock_file(&index_lock))
303313
die("unable to write new_index file");
@@ -316,7 +326,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
316326
*/
317327
if (!pathspec || !*pathspec) {
318328
fd = hold_locked_index(&index_lock, 1);
319-
refresh_cache(refresh_flags);
329+
refresh_cache_or_die(refresh_flags);
320330
if (write_cache(fd, active_cache, active_nr) ||
321331
commit_locked_index(&index_lock))
322332
die("unable to write new_index file");

builtin-merge.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -849,11 +849,20 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
849849
const char *best_strategy = NULL, *wt_strategy = NULL;
850850
struct commit_list **remotes = &remoteheads;
851851

852-
if (file_exists(git_path("MERGE_HEAD")))
853-
die("You have not concluded your merge. (MERGE_HEAD exists)");
854-
if (read_cache_unmerged())
855-
die("You are in the middle of a conflicted merge."
856-
" (index unmerged)");
852+
if (read_cache_unmerged()) {
853+
die_resolve_conflict("merge");
854+
}
855+
if (file_exists(git_path("MERGE_HEAD"))) {
856+
/*
857+
* There is no unmerged entry, don't advise 'git
858+
* add/rm <file>', just 'git commit'.
859+
*/
860+
if (advice_resolve_conflict)
861+
die("You have not concluded your merge (MERGE_HEAD exists).\n"
862+
"Please, commit your changes before you can merge.");
863+
else
864+
die("You have not concluded your merge (MERGE_HEAD exists).");
865+
}
857866

858867
/*
859868
* Check if we are _not_ on a detached HEAD, i.e. if there is a

builtin-revert.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,19 @@ static struct tree *empty_tree(void)
235235
return tree;
236236
}
237237

238+
static NORETURN void die_dirty_index(const char *me)
239+
{
240+
if (read_cache_unmerged()) {
241+
die_resolve_conflict(me);
242+
} else {
243+
if (advice_commit_before_merge)
244+
die("Your local changes would be overwritten by %s.\n"
245+
"Please, commit your changes or stash them to proceed.", me);
246+
else
247+
die("Your local changes would be overwritten by %s.\n", me);
248+
}
249+
}
250+
238251
static int revert_or_cherry_pick(int argc, const char **argv)
239252
{
240253
unsigned char head[20];
@@ -271,7 +284,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
271284
if (get_sha1("HEAD", head))
272285
die ("You do not have a valid HEAD");
273286
if (index_differs_from("HEAD", 0))
274-
die ("Dirty index: cannot %s", me);
287+
die_dirty_index(me);
275288
}
276289
discard_cache();
277290

git-pull.sh

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,29 @@ set_reflog_action "pull $*"
1313
require_work_tree
1414
cd_to_toplevel
1515

16-
test -z "$(git ls-files -u)" ||
17-
die "You are in the middle of a conflicted merge."
16+
17+
die_conflict () {
18+
git diff-index --cached --name-status -r --ignore-submodules HEAD --
19+
if [ $(git config --bool --get advice.resolveConflict || echo true) = "true" ]; then
20+
die "Pull is not possible because you have unmerged files.
21+
Please, fix them up in the work tree, and then use 'git add/rm <file>'
22+
as appropriate to mark resolution, or use 'git commit -a'."
23+
else
24+
die "Pull is not possible because you have unmerged files."
25+
fi
26+
}
27+
28+
die_merge () {
29+
if [ $(git config --bool --get advice.resolveConflict || echo true) = "true" ]; then
30+
die "You have not concluded your merge (MERGE_HEAD exists).
31+
Please, commit your changes before you can merge."
32+
else
33+
die "You have not concluded your merge (MERGE_HEAD exists)."
34+
fi
35+
}
36+
37+
test -z "$(git ls-files -u)" || die_conflict
38+
test -f "$GIT_DIR/MERGE_HEAD" && die_merge
1839

1940
strategy_args= diffstat= no_commit= squash= no_ff= ff_only=
2041
log_arg= verbosity=

t/t3030-merge-recursive.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,11 +276,13 @@ test_expect_success 'fail if the index has unresolved entries' '
276276
277277
test_must_fail git merge "$c5" &&
278278
test_must_fail git merge "$c5" 2> out &&
279+
grep "not possible because you have unmerged files" out &&
280+
git add -u &&
281+
test_must_fail git merge "$c5" 2> out &&
279282
grep "You have not concluded your merge" out &&
280283
rm -f .git/MERGE_HEAD &&
281284
test_must_fail git merge "$c5" 2> out &&
282-
grep "You are in the middle of a conflicted merge" out
283-
285+
grep "Your local changes to .* would be overwritten by merge." out
284286
'
285287

286288
test_expect_success 'merge-recursive remove conflict' '

t/t3501-revert-cherry-pick.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ test_expect_success 'revert forbidden on dirty working tree' '
6666
echo content >extra_file &&
6767
git add extra_file &&
6868
test_must_fail git revert HEAD 2>errors &&
69-
grep "Dirty index" errors
69+
grep "Your local changes would be overwritten by " errors
7070
7171
'
7272

0 commit comments

Comments
 (0)