author | Junio C Hamano <gitster@pobox.com> | |
Sun, 22 Aug 2010 06:26:46 +0000 (23:26 -0700) | ||
committer | Junio C Hamano <gitster@pobox.com> | |
Sun, 22 Aug 2010 06:26:46 +0000 (23:26 -0700) |
* 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
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
1 | 2 | |||
---|---|---|---|---|
builtin/checkout.c | patch | | diff1 | | diff2 | | blob | history |
merge-recursive.c | patch | | diff1 | | diff2 | | blob | history |
t/t3400-rebase.sh | patch | | diff1 | | diff2 | | blob | history |
t/t3404-rebase-interactive.sh | patch | | diff1 | | diff2 | | blob | history |
unpack-trees.c | patch | | diff1 | | diff2 | | blob | history |
diff --combined builtin/checkout.c
index 7f81120c728dce6fe712280f40583925eda264e3,894bb84db515b1b371cf356785dd1807ed1ec5ab..7250e5c23cee7deda557c16945373b59d99424ee
--- 1/builtin/checkout.c
--- 2/builtin/checkout.c
+++ b/builtin/checkout.c
int writeout_stage;
int writeout_error;
+ /* not set by parse_options */
+ int branch_exists;
+
const char *new_branch;
+ const char *new_branch_force;
const char *new_orphan_branch;
int new_branch_log;
enum branch_track track;
struct rev_info rev;
/* I think we want full paths, even if we're in a subdirectory. */
init_revisions(&rev, NULL);
- rev.abbrev = 0;
rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
if (diff_setup_done(&rev.diffopt) < 0)
die("diff_setup_done failed");
topts.src_index = &the_index;
topts.dst_index = &the_index;
- topts.msgs.not_uptodate_file = "You have local changes to '%s'; cannot switch branches.";
+ set_porcelain_error_msgs(topts.msgs, "checkout");
refresh_cache(REFRESH_QUIET);
topts.dir = xcalloc(1, sizeof(*topts.dir));
topts.dir->flags |= DIR_SHOW_IGNORED;
topts.dir->exclude_per_dir = ".gitignore";
+ topts.show_all_errors = 1;
tree = parse_tree_indirect(old->commit ?
old->commit->object.sha1 :
(unsigned char *)EMPTY_TREE_SHA1_BIN);
}
}
else
- create_branch(old->name, opts->new_branch, new->name, 0,
+ create_branch(old->name, opts->new_branch, new->name,
+ opts->new_branch_force ? 1 : 0,
opts->new_branch_log, opts->track);
new->name = opts->new_branch;
setup_branch_path(new);
if (old->path && !strcmp(new->path, old->path))
fprintf(stderr, "Already on '%s'\n",
new->name);
- else
+ else if (opts->new_branch)
fprintf(stderr, "Switched to%s branch '%s'\n",
- opts->new_branch ? " a new" : "",
+ opts->branch_exists ? " and reset" : " a new",
+ new->name);
+ else
+ fprintf(stderr, "Switched to branch '%s'\n",
new->name);
}
if (old->path && old->name) {
int dwim_new_local_branch = 1;
struct option options[] = {
OPT__QUIET(&opts.quiet),
- OPT_STRING('b', NULL, &opts.new_branch, "new branch", "branch"),
+ OPT_STRING('b', NULL, &opts.new_branch, "branch",
+ "create and checkout a new branch"),
+ OPT_STRING('B', NULL, &opts.new_branch_force, "branch",
+ "create/reset and checkout a branch"),
OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "log for new branch"),
OPT_SET_INT('t', "track", &opts.track, "track",
BRANCH_TRACK_EXPLICIT),
argc = parse_options(argc, argv, prefix, options, checkout_usage,
PARSE_OPT_KEEP_DASHDASH);
+ /* we can assume from now on new_branch = !new_branch_force */
+ if (opts.new_branch && opts.new_branch_force)
+ die("-B cannot be used with -b");
+
+ /* copy -B over to -b, so that we can just check the latter */
+ if (opts.new_branch_force)
+ opts.new_branch = opts.new_branch_force;
+
if (patch_mode && (opts.track > 0 || opts.new_branch
|| opts.new_branch_log || opts.merge || opts.force))
die ("--patch is incompatible with all other options");
if (opts.new_orphan_branch) {
if (opts.new_branch)
- die("--orphan and -b are mutually exclusive");
+ die("--orphan and -b|-B are mutually exclusive");
if (opts.track > 0)
die("--orphan cannot be used with -t");
opts.new_branch = opts.new_orphan_branch;
if (strbuf_check_branch_ref(&buf, opts.new_branch))
die("git checkout: we do not like '%s' as a branch name.",
opts.new_branch);
- if (!get_sha1(buf.buf, rev))
- die("git checkout: branch %s already exists", opts.new_branch);
+ if (!get_sha1(buf.buf, rev)) {
+ opts.branch_exists = 1;
+ if (!opts.new_branch_force)
+ die("git checkout: branch %s already exists",
+ opts.new_branch);
+ }
strbuf_release(&buf);
}
diff --combined merge-recursive.c
index 6cff9cdc86b1db7c4bd0a75175a77b2474417dfb,10392d9661180c368736e2a64d91fbca53dfae11..656e769b447f26247aa9672baf327a256b6bfeb1
--- 1/merge-recursive.c
--- 2/merge-recursive.c
+++ b/merge-recursive.c
if (parse_commit(commit) != 0)
printf("(bad commit)\n");
else {
- const char *s;
- int len;
- for (s = commit->buffer; *s; s++)
- if (*s == '\n' && s[1] == '\n') {
- s += 2;
- break;
- }
- for (len = 0; s[len] && '\n' != s[len]; len++)
- ; /* do nothing */
- printf("%.*s\n", len, s);
+ const char *title;
+ int len = find_commit_subject(commit->buffer, &title);
+ if (len)
+ printf("%.*s\n", len, title);
}
}
}
opts.fn = threeway_merge;
opts.src_index = &the_index;
opts.dst_index = &the_index;
- opts.msgs = get_porcelain_error_msgs();
+ set_porcelain_error_msgs(opts.msgs, "merge");
init_tree_desc_from_tree(t+0, common);
init_tree_desc_from_tree(t+1, head);
struct string_list *b_renames)
{
int clean_merge = 1, i, j;
- struct string_list a_by_dst = {NULL, 0, 0, 0}, b_by_dst = {NULL, 0, 0, 0};
+ struct string_list a_by_dst = STRING_LIST_INIT_NODUP;
+ struct string_list b_by_dst = STRING_LIST_INIT_NODUP;
const struct rename *sre;
for (i = 0; i < a_renames->nr; i++) {
return clean_merge;
}
- struct unpack_trees_error_msgs get_porcelain_error_msgs(void)
+ void set_porcelain_error_msgs(const char **msgs, const char *cmd)
{
- struct unpack_trees_error_msgs msgs = {
- /* would_overwrite */
- "Your local changes to '%s' would be overwritten by merge. Aborting.",
- /* not_uptodate_file */
- "Your local changes to '%s' would be overwritten by merge. Aborting.",
- /* not_uptodate_dir */
- "Updating '%s' would lose untracked files in it. Aborting.",
- /* would_lose_untracked */
- "Untracked working tree file '%s' would be %s by merge. Aborting",
- /* bind_overlap -- will not happen here */
- NULL,
- };
- if (advice_commit_before_merge) {
- msgs.would_overwrite = msgs.not_uptodate_file =
- "Your local changes to '%s' would be overwritten by merge. Aborting.\n"
- "Please, commit your changes or stash them before you can merge.";
- }
- return msgs;
+ const char *msg;
+ char *tmp;
+ const char *cmd2 = strcmp(cmd, "checkout") ? cmd : "switch branches";
+ if (advice_commit_before_merge)
+ msg = "Your local changes to the following files would be overwritten by %s:\n%%s"
+ "Please, commit your changes or stash them before you can %s.";
+ else
+ msg = "Your local changes to the following files would be overwritten by %s:\n%%s";
+ tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen(cmd2) - 2);
+ sprintf(tmp, msg, cmd, cmd2);
+ msgs[ERROR_WOULD_OVERWRITE] = tmp;
+ msgs[ERROR_NOT_UPTODATE_FILE] = tmp;
+
+ msgs[ERROR_NOT_UPTODATE_DIR] =
+ "Updating the following directories would lose untracked files in it:\n%s";
+
+ if (advice_commit_before_merge)
+ msg = "The following untracked working tree files would be %s by %s:\n%%s"
+ "Please move or remove them before you can %s.";
+ else
+ msg = "The following untracked working tree files would be %s by %s:\n%%s";
+ tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen("removed") + strlen(cmd2) - 4);
+ sprintf(tmp, msg, "removed", cmd, cmd2);
+ msgs[ERROR_WOULD_LOSE_UNTRACKED_REMOVED] = tmp;
+ tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen("overwritten") + strlen(cmd2) - 4);
+ sprintf(tmp, msg, "overwritten", cmd, cmd2);
+ msgs[ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN] = tmp;
+
+ /*
+ * Special case: ERROR_BIND_OVERLAP refers to a pair of paths, we
+ * cannot easily display it as a list.
+ */
+ msgs[ERROR_BIND_OVERLAP] = "Entry '%s' overlaps with '%s'. Cannot bind.";
+
+ msgs[ERROR_SPARSE_NOT_UPTODATE_FILE] =
+ "Cannot update sparse checkout: the following entries are not up-to-date:\n%s";
+ msgs[ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN] =
+ "The following Working tree files would be overwritten by sparse checkout update:\n%s";
+ msgs[ERROR_WOULD_LOSE_ORPHANED_REMOVED] =
+ "The following Working tree files would be removed by sparse checkout update:\n%s";
}
int merge_trees(struct merge_options *o,
diff --combined t/t3400-rebase.sh
index a19aeb6441cb29dc20478cf898b5f7767d770c94,45ef28281512e8f53eafc3cb23c1b99e0ef82c0f..349eebd54268c927249322dc22fc478869860f7c
--- 1/t/t3400-rebase.sh
--- 2/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
GIT_AUTHOR_EMAIL=bogus@email@address
export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
-test_expect_success \
- 'prepare repository with topic branches' \
- 'git config core.logAllRefUpdates true &&
- echo First > A &&
- git update-index --add A &&
- git commit -m "Add A." &&
- git checkout -b my-topic-branch &&
- echo Second > B &&
- git update-index --add B &&
- git commit -m "Add B." &&
- git checkout -f master &&
- echo Third >> A &&
- git update-index A &&
- git commit -m "Modify A." &&
- git checkout -b side my-topic-branch &&
- echo Side >> C &&
- git add C &&
- git commit -m "Add C" &&
- git checkout -b nonlinear my-topic-branch &&
- echo Edit >> B &&
- git add B &&
- git commit -m "Modify B" &&
- git merge side &&
- git checkout -b upstream-merged-nonlinear &&
- git merge master &&
- git checkout -f my-topic-branch &&
- git tag topic
+test_expect_success 'prepare repository with topic branches' '
+ git config core.logAllRefUpdates true &&
+ echo First >A &&
+ git update-index --add A &&
+ git commit -m "Add A." &&
+ git checkout -b force-3way &&
+ echo Dummy >Y &&
+ git update-index --add Y &&
+ git commit -m "Add Y." &&
+ git checkout -b filemove &&
+ git reset --soft master &&
+ mkdir D &&
+ git mv A D/A &&
+ git commit -m "Move A." &&
+ git checkout -b my-topic-branch master &&
+ echo Second >B &&
+ git update-index --add B &&
+ git commit -m "Add B." &&
+ git checkout -f master &&
+ echo Third >>A &&
+ git update-index A &&
+ git commit -m "Modify A." &&
+ git checkout -b side my-topic-branch &&
+ echo Side >>C &&
+ git add C &&
+ git commit -m "Add C" &&
+ git checkout -b nonlinear my-topic-branch &&
+ echo Edit >>B &&
+ git add B &&
+ git commit -m "Modify B" &&
+ git merge side &&
+ git checkout -b upstream-merged-nonlinear &&
+ git merge master &&
+ git checkout -f my-topic-branch &&
+ git tag topic
'
test_expect_success 'rebase on dirty worktree' '
- echo dirty >> A &&
- test_must_fail git rebase master'
+ echo dirty >>A &&
+ test_must_fail git rebase master
+'
test_expect_success 'rebase on dirty cache' '
- git add A &&
- test_must_fail git rebase master'
+ git add A &&
+ test_must_fail git rebase master
+'
test_expect_success 'rebase against master' '
- git reset --hard HEAD &&
- git rebase master'
+ git reset --hard HEAD &&
+ git rebase master
+'
test_expect_success 'rebase against master twice' '
- git rebase master >out &&
- grep "Current branch my-topic-branch is up to date" out
+ git rebase master >out &&
+ grep "Current branch my-topic-branch is up to date" out
'
test_expect_success 'rebase against master twice with --force' '
- git rebase --force-rebase master >out &&
- grep "Current branch my-topic-branch is up to date, rebase forced" out
+ git rebase --force-rebase master >out &&
+ grep "Current branch my-topic-branch is up to date, rebase forced" out
'
test_expect_success 'rebase against master twice from another branch' '
- git checkout my-topic-branch^ &&
- git rebase master my-topic-branch >out &&
- grep "Current branch my-topic-branch is up to date" out
+ git checkout my-topic-branch^ &&
+ git rebase master my-topic-branch >out &&
+ grep "Current branch my-topic-branch is up to date" out
'
test_expect_success 'rebase fast-forward to master' '
- git checkout my-topic-branch^ &&
- git rebase my-topic-branch >out &&
- grep "Fast-forwarded HEAD to my-topic-branch" out
+ git checkout my-topic-branch^ &&
+ git rebase my-topic-branch >out &&
+ grep "Fast-forwarded HEAD to my-topic-branch" out
'
-test_expect_success \
- 'the rebase operation should not have destroyed author information' \
- '! (git log | grep "Author:" | grep "<>")'
+test_expect_success 'the rebase operation should not have destroyed author information' '
+ ! (git log | grep "Author:" | grep "<>")
+'
-test_expect_success \
- 'the rebase operation should not have destroyed author information (2)' \
- "git log -1 | grep 'Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>'"
+test_expect_success 'the rebase operation should not have destroyed author information (2)' "
+ git log -1 |
+ grep 'Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>'
+"
test_expect_success 'HEAD was detached during rebase' '
- test $(git rev-parse HEAD@{1}) != $(git rev-parse my-topic-branch@{1})
+ test $(git rev-parse HEAD@{1}) != $(git rev-parse my-topic-branch@{1})
'
test_expect_success 'rebase after merge master' '
- git reset --hard topic &&
- git merge master &&
- git rebase master &&
- ! (git show | grep "^Merge:")
+ git reset --hard topic &&
+ git merge master &&
+ git rebase master &&
+ ! (git show | grep "^Merge:")
'
test_expect_success 'rebase of history with merges is linearized' '
- git checkout nonlinear &&
- test 4 = $(git rev-list master.. | wc -l) &&
- git rebase master &&
- test 3 = $(git rev-list master.. | wc -l)
+ git checkout nonlinear &&
+ test 4 = $(git rev-list master.. | wc -l) &&
+ git rebase master &&
+ test 3 = $(git rev-list master.. | wc -l)
'
-test_expect_success \
- 'rebase of history with merges after upstream merge is linearized' '
- git checkout upstream-merged-nonlinear &&
- test 5 = $(git rev-list master.. | wc -l) &&
- git rebase master &&
- test 3 = $(git rev-list master.. | wc -l)
+test_expect_success 'rebase of history with merges after upstream merge is linearized' '
+ git checkout upstream-merged-nonlinear &&
+ test 5 = $(git rev-list master.. | wc -l) &&
+ git rebase master &&
+ test 3 = $(git rev-list master.. | wc -l)
'
test_expect_success 'rebase a single mode change' '
- git checkout master &&
- echo 1 > X &&
- git add X &&
- test_tick &&
- git commit -m prepare &&
- git checkout -b modechange HEAD^ &&
- echo 1 > X &&
- git add X &&
- test_chmod +x A &&
- test_tick &&
- git commit -m modechange &&
- GIT_TRACE=1 git rebase master
+ git checkout master &&
+ echo 1 >X &&
+ git add X &&
+ test_tick &&
+ git commit -m prepare &&
+ git checkout -b modechange HEAD^ &&
+ echo 1 >X &&
+ git add X &&
+ test_chmod +x A &&
+ test_tick &&
+ git commit -m modechange &&
+ GIT_TRACE=1 git rebase master
+'
+
+test_expect_success 'rebase is not broken by diff.renames' '
+ git config diff.renames copies &&
+ test_when_finished "git config --unset diff.renames" &&
+ git checkout filemove &&
+ GIT_TRACE=1 git rebase force-3way
+'
+
+test_expect_success 'setup: recover' '
+ test_might_fail git rebase --abort &&
+ git reset --hard &&
+ git checkout modechange
'
test_expect_success 'Show verbose error when HEAD could not be detached' '
- : > B &&
- test_must_fail git rebase topic 2> output.err > output.out &&
- grep "The following untracked working tree files would be overwritten by checkout:" output.err &&
- grep B output.err
+ >B &&
+ test_must_fail git rebase topic 2>output.err >output.out &&
- grep "Untracked working tree file .B. would be overwritten" output.err
++ grep "The following untracked working tree files would be overwritten by checkout:" output.err &&
++ grep B output.err
'
rm -f B
test_expect_success 'dump usage when upstream arg is missing' '
- git checkout -b usage topic &&
- test_must_fail git rebase 2>error1 &&
- grep "[Uu]sage" error1 &&
- test_must_fail git rebase --abort 2>error2 &&
- grep "No rebase in progress" error2 &&
- test_must_fail git rebase --onto master 2>error3 &&
- grep "[Uu]sage" error3 &&
- ! grep "can.t shift" error3
+ git checkout -b usage topic &&
+ test_must_fail git rebase 2>error1 &&
+ grep "[Uu]sage" error1 &&
+ test_must_fail git rebase --abort 2>error2 &&
+ grep "No rebase in progress" error2 &&
+ test_must_fail git rebase --onto master 2>error3 &&
+ grep "[Uu]sage" error3 &&
+ ! grep "can.t shift" error3
'
test_expect_success 'rebase -q is quiet' '
- git checkout -b quiet topic &&
- git rebase -q master > output.out 2>&1 &&
- test ! -s output.out
+ git checkout -b quiet topic &&
+ git rebase -q master >output.out 2>&1 &&
+ test ! -s output.out
'
test_expect_success 'Rebase a commit that sprinkles CRs in' '
diff --combined t/t3404-rebase-interactive.sh
index 9f03ce699e8f4c3c654065deae675d1a7b259c74,0eb21cbdee6a5f5245bbd4d130f96c2c1b36de65..3af3f603fb2ad34368b4f53f523bdd71dffdf854
git rm --cached file1 &&
git commit -m "remove file in base" &&
test_must_fail git rebase -i master > output 2>&1 &&
- grep "Untracked working tree file .file1. would be overwritten" \
+ grep "The following untracked working tree files would be overwritten by checkout:" \
output &&
+ grep "file1" output &&
! test -d .git/rebase-merge &&
git reset --hard HEAD^
'
git commit -a -m "end with slash\\" &&
echo >>file1 &&
test_tick &&
+ git commit -a -m "something (\000) that looks like octal" &&
+ echo >>file1 &&
+ test_tick &&
+ git commit -a -m "something (\n) that looks like a newline" &&
+ echo >>file1 &&
+ test_tick &&
git commit -a -m "another commit"
'
test_expect_success 'rebase-i history with funny messages' '
git rev-list A..funny >expect &&
test_tick &&
- FAKE_LINES="1 2" git rebase -i A &&
+ FAKE_LINES="1 2 3 4" git rebase -i A &&
git rev-list A.. >actual &&
test_cmp expect actual
'
diff --combined unpack-trees.c
index f561d88156b827b15bad7dd4e00f944718149bd9,7b10f92fa4854f4b97ee67858467ca94e15cb0b3..62852aa7fb3fbd5e2d3ae1173d05deddba763d52
--- 1/unpack-trees.c
--- 2/unpack-trees.c
+++ b/unpack-trees.c
* Error messages expected by scripts out of plumbing commands such as
* read-tree. Non-scripted Porcelain is not required to use these messages
* and in fact are encouraged to reword them to better suit their particular
- * situation better. See how "git checkout" replaces not_uptodate_file to
- * explain why it does not allow switching between branches when you have
- * local changes, for example.
+ * situation better. See how "git checkout" and "git merge" replaces
+ * them using set_porcelain_error_msgs(), for example.
*/
- static struct unpack_trees_error_msgs unpack_plumbing_errors = {
- /* would_overwrite */
+ const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
+ /* ERROR_WOULD_OVERWRITE */
"Entry '%s' would be overwritten by merge. Cannot merge.",
- /* not_uptodate_file */
+ /* ERROR_NOT_UPTODATE_FILE */
"Entry '%s' not uptodate. Cannot merge.",
- /* not_uptodate_dir */
+ /* ERROR_NOT_UPTODATE_DIR */
"Updating '%s' would lose untracked files in it",
- /* would_lose_untracked */
- "Untracked working tree file '%s' would be %s by merge.",
+ /* ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN */
+ "Untracked working tree file '%s' would be overwritten by merge.",
- /* bind_overlap */
+ /* ERROR_WOULD_LOSE_UNTRACKED_REMOVED */
+ "Untracked working tree file '%s' would be removed by merge.",
+
+ /* ERROR_BIND_OVERLAP */
"Entry '%s' overlaps with '%s'. Cannot bind.",
- /* sparse_not_uptodate_file */
+ /* ERROR_SPARSE_NOT_UPTODATE_FILE */
"Entry '%s' not uptodate. Cannot update sparse checkout.",
- /* would_lose_orphaned */
- "Working tree file '%s' would be %s by sparse checkout update.",
+ /* ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN */
+ "Working tree file '%s' would be overwritten by sparse checkout update.",
+
+ /* ERROR_WOULD_LOSE_ORPHANED_REMOVED */
+ "Working tree file '%s' would be removed by sparse checkout update.",
};
- #define ERRORMSG(o,fld) \
- ( ((o) && (o)->msgs.fld) \
- ? ((o)->msgs.fld) \
- : (unpack_plumbing_errors.fld) )
+ #define ERRORMSG(o,type) \
+ ( ((o) && (o)->msgs[(type)]) \
+ ? ((o)->msgs[(type)]) \
+ : (unpack_plumbing_errors[(type)]) )
static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
unsigned int set, unsigned int clear)
add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
}
+ /*
+ * add error messages on path <path>
+ * corresponding to the type <e> with the message <msg>
+ * indicating if it should be display in porcelain or not
+ */
+ static int add_rejected_path(struct unpack_trees_options *o,
+ enum unpack_trees_error_types e,
+ const char *path)
+ {
+ struct rejected_paths_list *newentry;
+ int porcelain = o && (o)->msgs[e];
+ /*
+ * simply display the given error message if in plumbing mode
+ */
+ if (!porcelain)
+ o->show_all_errors = 0;
+ if (!o->show_all_errors)
+ return error(ERRORMSG(o, e), path);
+
+ /*
+ * Otherwise, insert in a list for future display by
+ * display_error_msgs()
+ */
+ newentry = xmalloc(sizeof(struct rejected_paths_list));
+ newentry->path = (char *)path;
+ newentry->next = o->unpack_rejects[e];
+ o->unpack_rejects[e] = newentry;
+ return -1;
+ }
+
+ /*
+ * free all the structures allocated for the error <e>
+ */
+ static void free_rejected_paths(struct unpack_trees_options *o,
+ enum unpack_trees_error_types e)
+ {
+ while (o->unpack_rejects[e]) {
+ struct rejected_paths_list *del = o->unpack_rejects[e];
+ o->unpack_rejects[e] = o->unpack_rejects[e]->next;
+ free(del);
+ }
+ free(o->unpack_rejects[e]);
+ }
+
+ /*
+ * display all the error messages stored in a nice way
+ */
+ static void display_error_msgs(struct unpack_trees_options *o)
+ {
+ int e;
+ int something_displayed = 0;
+ for (e = 0; e < NB_UNPACK_TREES_ERROR_TYPES; e++) {
+ if (o->unpack_rejects[e]) {
+ struct rejected_paths_list *rp;
+ struct strbuf path = STRBUF_INIT;
+ something_displayed = 1;
+ for (rp = o->unpack_rejects[e]; rp; rp = rp->next)
+ strbuf_addf(&path, "\t%s\n", rp->path);
+ error(ERRORMSG(o, e), path.buf);
+ strbuf_release(&path);
+ free_rejected_paths(o, e);
+ }
+ }
+ if (something_displayed)
+ printf("Aborting\n");
+ }
+
/*
* Unlink the last component and schedule the leading directories for
* removal, such that empty directories get removed.
}
static int verify_uptodate_sparse(struct cache_entry *ce, struct unpack_trees_options *o);
- static int verify_absent_sparse(struct cache_entry *ce, const char *action, struct unpack_trees_options *o);
+ static int verify_absent_sparse(struct cache_entry *ce, enum unpack_trees_error_types, struct unpack_trees_options *o);
static int will_have_skip_worktree(const struct cache_entry *ce, struct unpack_trees_options *o)
{
ce->ce_flags |= CE_WT_REMOVE;
}
if (was_skip_worktree && !ce_skip_worktree(ce)) {
- if (verify_absent_sparse(ce, "overwritten", o))
+ if (verify_absent_sparse(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))
return -1;
ce->ce_flags |= CE_UPDATE;
}
{
int i, ret, bottom;
struct tree_desc t[MAX_UNPACK_TREES];
+ void *buf[MAX_UNPACK_TREES];
struct traverse_info newinfo;
struct name_entry *p;
const unsigned char *sha1 = NULL;
if (dirmask & 1)
sha1 = names[i].sha1;
- fill_tree_descriptor(t+i, sha1);
+ buf[i] = fill_tree_descriptor(t+i, sha1);
}
bottom = switch_cache_bottom(&newinfo);
ret = traverse_trees(n, t, &newinfo);
restore_cache_bottom(&newinfo, bottom);
+
+ for (i = 0; i < n; i++)
+ free(buf[i]);
+
return ret;
}
setup_traverse_info(&info, prefix);
info.fn = unpack_callback;
info.data = o;
+ info.show_all_errors = o->show_all_errors;
if (o->prefix) {
/*
return ret;
return_failed:
+ if (o->show_all_errors)
+ display_error_msgs(o);
mark_all_ce_unused(o->src_index);
ret = unpack_failed(o, NULL);
goto done;
static int reject_merge(struct cache_entry *ce, struct unpack_trees_options *o)
{
- return error(ERRORMSG(o, would_overwrite), ce->name);
+ return add_rejected_path(o, ERROR_WOULD_OVERWRITE, ce->name);
}
static int same(struct cache_entry *a, struct cache_entry *b)
*/
static int verify_uptodate_1(struct cache_entry *ce,
struct unpack_trees_options *o,
- const char *error_msg)
+ enum unpack_trees_error_types error_type)
{
struct stat st;
if (errno == ENOENT)
return 0;
return o->gently ? -1 :
- error(error_msg, ce->name);
+ add_rejected_path(o, error_type, ce->name);
}
static int verify_uptodate(struct cache_entry *ce,
{
if (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))
return 0;
- return verify_uptodate_1(ce, o, ERRORMSG(o, not_uptodate_file));
+ return verify_uptodate_1(ce, o, ERROR_NOT_UPTODATE_FILE);
}
static int verify_uptodate_sparse(struct cache_entry *ce,
struct unpack_trees_options *o)
{
- return verify_uptodate_1(ce, o, ERRORMSG(o, sparse_not_uptodate_file));
+ return verify_uptodate_1(ce, o, ERROR_SPARSE_NOT_UPTODATE_FILE);
}
static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o)
* Currently, git does not checkout subprojects during a superproject
* checkout, so it is not going to overwrite anything.
*/
- static int verify_clean_submodule(struct cache_entry *ce, const char *action,
+ static int verify_clean_submodule(struct cache_entry *ce,
+ enum unpack_trees_error_types error_type,
struct unpack_trees_options *o)
{
return 0;
}
- static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
+ static int verify_clean_subdirectory(struct cache_entry *ce,
+ enum unpack_trees_error_types error_type,
struct unpack_trees_options *o)
{
/*
*/
if (!hashcmp(sha1, ce->sha1))
return 0;
- return verify_clean_submodule(ce, action, o);
+ return verify_clean_submodule(ce, error_type, o);
}
/*
i = read_directory(&d, pathbuf, namelen+1, NULL);
if (i)
return o->gently ? -1 :
- error(ERRORMSG(o, not_uptodate_dir), ce->name);
+ add_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name);
free(pathbuf);
return cnt;
}
* We do not want to remove or overwrite a working tree file that
* is not tracked, unless it is ignored.
*/
- static int verify_absent_1(struct cache_entry *ce, const char *action,
- struct unpack_trees_options *o,
- const char *error_msg)
+ static int verify_absent_1(struct cache_entry *ce,
+ enum unpack_trees_error_types error_type,
+ struct unpack_trees_options *o)
{
struct stat st;
* files that are in "foo/" we would lose
* them.
*/
- if (verify_clean_subdirectory(ce, action, o) < 0)
+ if (verify_clean_subdirectory(ce, error_type, o) < 0)
return -1;
return 0;
}
}
return o->gently ? -1 :
- error(ERRORMSG(o, would_lose_untracked), ce->name, action);
+ add_rejected_path(o, error_type, ce->name);
}
return 0;
}
- static int verify_absent(struct cache_entry *ce, const char *action,
+ static int verify_absent(struct cache_entry *ce,
+ enum unpack_trees_error_types error_type,
struct unpack_trees_options *o)
{
if (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))
return 0;
- return verify_absent_1(ce, action, o, ERRORMSG(o, would_lose_untracked));
+ return verify_absent_1(ce, error_type, o);
}
- static int verify_absent_sparse(struct cache_entry *ce, const char *action,
+ static int verify_absent_sparse(struct cache_entry *ce,
+ enum unpack_trees_error_types error_type,
struct unpack_trees_options *o)
{
- return verify_absent_1(ce, action, o, ERRORMSG(o, would_lose_orphaned));
+ enum unpack_trees_error_types orphaned_error = error_type;
+ if (orphaned_error == ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN)
+ orphaned_error = ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN;
+
+ return verify_absent_1(ce, orphaned_error, o);
}
static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
int update = CE_UPDATE;
if (!old) {
- if (verify_absent(merge, "overwritten", o))
+ if (verify_absent(merge, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))
return -1;
invalidate_ce_path(merge, o);
} else if (!(old->ce_flags & CE_CONFLICTED)) {
{
/* Did it exist in the index? */
if (!old) {
- if (verify_absent(ce, "removed", o))
+ if (verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_REMOVED, o))
return -1;
return 0;
}
if (index)
return deleted_entry(index, index, o);
if (ce && !head_deleted) {
- if (verify_absent(ce, "removed", o))
+ if (verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_REMOVED, o))
return -1;
}
return 0;
o->merge_size);
if (a && old)
return o->gently ? -1 :
- error(ERRORMSG(o, bind_overlap), a->name, old->name);
+ error(ERRORMSG(o, ERROR_BIND_OVERLAP), a->name, old->name);
if (!a)
return keep_entry(old, o);
else