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
This commit is contained in:
Junio C Hamano 2010-01-20 14:42:59 -08:00
commit 71b3ef11fa
9 changed files with 93 additions and 13 deletions

View File

@ -130,6 +130,10 @@ advice.*::
Advice shown when linkgit:git-merge[1] refuses to Advice shown when linkgit:git-merge[1] refuses to
merge to avoid overwritting local changes. merge to avoid overwritting local changes.
Default: true. Default: true.
resolveConflict::
Advices shown by various commands when conflicts
prevent the operation from being performed.
Default: true.
implicitIdentity:: implicitIdentity::
Advice on how to set your identity configuration when Advice on how to set your identity configuration when
your information is guessed from the system username and your information is guessed from the system username and

View File

@ -3,6 +3,7 @@
int advice_push_nonfastforward = 1; int advice_push_nonfastforward = 1;
int advice_status_hints = 1; int advice_status_hints = 1;
int advice_commit_before_merge = 1; int advice_commit_before_merge = 1;
int advice_resolve_conflict = 1;
int advice_implicit_identity = 1; int advice_implicit_identity = 1;
static struct { static struct {
@ -12,6 +13,7 @@ static struct {
{ "pushnonfastforward", &advice_push_nonfastforward }, { "pushnonfastforward", &advice_push_nonfastforward },
{ "statushints", &advice_status_hints }, { "statushints", &advice_status_hints },
{ "commitbeforemerge", &advice_commit_before_merge }, { "commitbeforemerge", &advice_commit_before_merge },
{ "resolveconflict", &advice_resolve_conflict },
{ "implicitidentity", &advice_implicit_identity }, { "implicitidentity", &advice_implicit_identity },
}; };
@ -29,3 +31,17 @@ int git_default_advice_config(const char *var, const char *value)
return 0; return 0;
} }
void NORETURN die_resolve_conflict(const char *me)
{
if (advice_resolve_conflict)
/*
* Message used both when 'git commit' fails and when
* other commands doing a merge do.
*/
die("'%s' is not possible because you have unmerged files.\n"
"Please, fix them up in the work tree, and then use 'git add/rm <file>' as\n"
"appropriate to mark resolution and make a commit, or use 'git commit -a'.", me);
else
die("'%s' is not possible because you have unmerged files.", me);
}

View File

@ -1,11 +1,16 @@
#ifndef ADVICE_H #ifndef ADVICE_H
#define ADVICE_H #define ADVICE_H
#include "git-compat-util.h"
extern int advice_push_nonfastforward; extern int advice_push_nonfastforward;
extern int advice_status_hints; extern int advice_status_hints;
extern int advice_commit_before_merge; extern int advice_commit_before_merge;
extern int advice_resolve_conflict;
extern int advice_implicit_identity; extern int advice_implicit_identity;
int git_default_advice_config(const char *var, const char *value); int git_default_advice_config(const char *var, const char *value);
extern void NORETURN die_resolve_conflict(const char *me);
#endif /* ADVICE_H */ #endif /* ADVICE_H */

View File

@ -258,6 +258,16 @@ static void create_base_index(void)
exit(128); /* We've already reported the error, finish dying */ exit(128); /* We've already reported the error, finish dying */
} }
static void refresh_cache_or_die(int refresh_flags)
{
/*
* refresh_flags contains REFRESH_QUIET, so the only errors
* are for unmerged entries.
*/
if (refresh_cache(refresh_flags | REFRESH_IN_PORCELAIN))
die_resolve_conflict("commit");
}
static char *prepare_index(int argc, const char **argv, const char *prefix, int is_status) static char *prepare_index(int argc, const char **argv, const char *prefix, int is_status)
{ {
int fd; int fd;
@ -297,7 +307,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
if (all || (also && pathspec && *pathspec)) { if (all || (also && pathspec && *pathspec)) {
int fd = hold_locked_index(&index_lock, 1); int fd = hold_locked_index(&index_lock, 1);
add_files_to_cache(also ? prefix : NULL, pathspec, 0); add_files_to_cache(also ? prefix : NULL, pathspec, 0);
refresh_cache(refresh_flags); refresh_cache_or_die(refresh_flags);
if (write_cache(fd, active_cache, active_nr) || if (write_cache(fd, active_cache, active_nr) ||
close_lock_file(&index_lock)) close_lock_file(&index_lock))
die("unable to write new_index file"); die("unable to write new_index file");
@ -316,7 +326,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
*/ */
if (!pathspec || !*pathspec) { if (!pathspec || !*pathspec) {
fd = hold_locked_index(&index_lock, 1); fd = hold_locked_index(&index_lock, 1);
refresh_cache(refresh_flags); refresh_cache_or_die(refresh_flags);
if (write_cache(fd, active_cache, active_nr) || if (write_cache(fd, active_cache, active_nr) ||
commit_locked_index(&index_lock)) commit_locked_index(&index_lock))
die("unable to write new_index file"); die("unable to write new_index file");

View File

@ -849,11 +849,20 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
const char *best_strategy = NULL, *wt_strategy = NULL; const char *best_strategy = NULL, *wt_strategy = NULL;
struct commit_list **remotes = &remoteheads; struct commit_list **remotes = &remoteheads;
if (file_exists(git_path("MERGE_HEAD"))) if (read_cache_unmerged()) {
die("You have not concluded your merge. (MERGE_HEAD exists)"); die_resolve_conflict("merge");
if (read_cache_unmerged()) }
die("You are in the middle of a conflicted merge." if (file_exists(git_path("MERGE_HEAD"))) {
" (index unmerged)"); /*
* There is no unmerged entry, don't advise 'git
* add/rm <file>', just 'git commit'.
*/
if (advice_resolve_conflict)
die("You have not concluded your merge (MERGE_HEAD exists).\n"
"Please, commit your changes before you can merge.");
else
die("You have not concluded your merge (MERGE_HEAD exists).");
}
/* /*
* Check if we are _not_ on a detached HEAD, i.e. if there is a * Check if we are _not_ on a detached HEAD, i.e. if there is a

View File

@ -235,6 +235,19 @@ static struct tree *empty_tree(void)
return tree; return tree;
} }
static NORETURN void die_dirty_index(const char *me)
{
if (read_cache_unmerged()) {
die_resolve_conflict(me);
} else {
if (advice_commit_before_merge)
die("Your local changes would be overwritten by %s.\n"
"Please, commit your changes or stash them to proceed.", me);
else
die("Your local changes would be overwritten by %s.\n", me);
}
}
static int revert_or_cherry_pick(int argc, const char **argv) static int revert_or_cherry_pick(int argc, const char **argv)
{ {
unsigned char head[20]; unsigned char head[20];
@ -271,7 +284,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
if (get_sha1("HEAD", head)) if (get_sha1("HEAD", head))
die ("You do not have a valid HEAD"); die ("You do not have a valid HEAD");
if (index_differs_from("HEAD", 0)) if (index_differs_from("HEAD", 0))
die ("Dirty index: cannot %s", me); die_dirty_index(me);
} }
discard_cache(); discard_cache();

View File

@ -13,8 +13,29 @@ set_reflog_action "pull $*"
require_work_tree require_work_tree
cd_to_toplevel cd_to_toplevel
test -z "$(git ls-files -u)" ||
die "You are in the middle of a conflicted merge." die_conflict () {
git diff-index --cached --name-status -r --ignore-submodules HEAD --
if [ $(git config --bool --get advice.resolveConflict || echo true) = "true" ]; then
die "Pull is not possible because you have unmerged files.
Please, fix them up in the work tree, and then use 'git add/rm <file>'
as appropriate to mark resolution, or use 'git commit -a'."
else
die "Pull is not possible because you have unmerged files."
fi
}
die_merge () {
if [ $(git config --bool --get advice.resolveConflict || echo true) = "true" ]; then
die "You have not concluded your merge (MERGE_HEAD exists).
Please, commit your changes before you can merge."
else
die "You have not concluded your merge (MERGE_HEAD exists)."
fi
}
test -z "$(git ls-files -u)" || die_conflict
test -f "$GIT_DIR/MERGE_HEAD" && die_merge
strategy_args= diffstat= no_commit= squash= no_ff= ff_only= strategy_args= diffstat= no_commit= squash= no_ff= ff_only=
log_arg= verbosity= log_arg= verbosity=

View File

@ -276,11 +276,13 @@ test_expect_success 'fail if the index has unresolved entries' '
test_must_fail git merge "$c5" && test_must_fail git merge "$c5" &&
test_must_fail git merge "$c5" 2> out && test_must_fail git merge "$c5" 2> out &&
grep "not possible because you have unmerged files" out &&
git add -u &&
test_must_fail git merge "$c5" 2> out &&
grep "You have not concluded your merge" out && grep "You have not concluded your merge" out &&
rm -f .git/MERGE_HEAD && rm -f .git/MERGE_HEAD &&
test_must_fail git merge "$c5" 2> out && test_must_fail git merge "$c5" 2> out &&
grep "You are in the middle of a conflicted merge" out grep "Your local changes to .* would be overwritten by merge." out
' '
test_expect_success 'merge-recursive remove conflict' ' test_expect_success 'merge-recursive remove conflict' '

View File

@ -66,7 +66,7 @@ test_expect_success 'revert forbidden on dirty working tree' '
echo content >extra_file && echo content >extra_file &&
git add extra_file && git add extra_file &&
test_must_fail git revert HEAD 2>errors && test_must_fail git revert HEAD 2>errors &&
grep "Dirty index" errors grep "Your local changes would be overwritten by " errors
' '