summaryrefslogtreecommitdiff
path: root/unpack-trees.c
diff options
context:
space:
mode:
Diffstat (limited to 'unpack-trees.c')
-rw-r--r--unpack-trees.c203
1 files changed, 93 insertions, 110 deletions
diff --git a/unpack-trees.c b/unpack-trees.c
index 149bc5d358..f0ac24b9f5 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -16,7 +16,7 @@
* situation better. See how "git checkout" and "git merge" replaces
* them using setup_unpack_trees_porcelain(), for example.
*/
-const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
+static const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
/* ERROR_WOULD_OVERWRITE */
"Entry '%s' would be overwritten by merge. Cannot merge.",
@@ -102,21 +102,28 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
opts->unpack_rejects[i].strdup_strings = 1;
}
-static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
- unsigned int set, unsigned int clear)
+static void do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
+ unsigned int set, unsigned int clear)
{
- unsigned int size = ce_size(ce);
- struct cache_entry *new = xmalloc(size);
-
clear |= CE_HASHED | CE_UNHASHED;
if (set & CE_REMOVE)
set |= CE_WT_REMOVE;
+ ce->next = NULL;
+ ce->ce_flags = (ce->ce_flags & ~clear) | set;
+ add_index_entry(&o->result, ce,
+ ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
+}
+
+static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
+ unsigned int set, unsigned int clear)
+{
+ unsigned int size = ce_size(ce);
+ struct cache_entry *new = xmalloc(size);
+
memcpy(new, ce, size);
- new->next = NULL;
- new->ce_flags = (new->ce_flags & ~clear) | set;
- add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
+ do_add_entry(o, new, set, clear);
}
/*
@@ -159,7 +166,7 @@ static void display_error_msgs(struct unpack_trees_options *o)
string_list_clear(rejects, 0);
}
if (something_displayed)
- printf("Aborting\n");
+ fprintf(stderr, "Aborting\n");
}
/*
@@ -203,7 +210,7 @@ static int check_updates(struct unpack_trees_options *o)
if (ce->ce_flags & CE_WT_REMOVE) {
display_progress(progress, ++cnt);
- if (o->update)
+ if (o->update && !o->dry_run)
unlink_entry(ce);
continue;
}
@@ -217,7 +224,7 @@ static int check_updates(struct unpack_trees_options *o)
if (ce->ce_flags & CE_UPDATE) {
display_progress(progress, ++cnt);
ce->ce_flags &= ~CE_UPDATE;
- if (o->update) {
+ if (o->update && !o->dry_run) {
errs |= checkout_entry(ce, &state, NULL);
}
}
@@ -427,10 +434,6 @@ static int switch_cache_bottom(struct traverse_info *info)
return ret;
}
-static int fast_forward_merge(int n, unsigned long dirmask,
- struct name_entry *names,
- struct traverse_info *info);
-
static int traverse_trees_recursive(int n, unsigned long dirmask,
unsigned long df_conflicts,
struct name_entry *names,
@@ -442,19 +445,15 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
struct traverse_info newinfo;
struct name_entry *p;
- if (!df_conflicts) {
- int status = fast_forward_merge(n, dirmask, names, info);
- if (status)
- return status;
- }
p = names;
while (!p->mode)
p++;
newinfo = *info;
newinfo.prev = info;
+ newinfo.pathspec = info->pathspec;
newinfo.name = *p;
- newinfo.pathlen += tree_entry_len(p->path, p->sha1) + 1;
+ newinfo.pathlen += tree_entry_len(p) + 1;
newinfo.conflicts |= df_conflicts;
for (i = 0; i < n; i++, dirmask >>= 1) {
@@ -503,7 +502,7 @@ static int do_compare_entry(const struct cache_entry *ce, const struct traverse_
ce_len -= pathlen;
ce_name = ce->name + pathlen;
- len = tree_entry_len(n->path, n->sha1);
+ len = tree_entry_len(n);
return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode);
}
@@ -595,14 +594,14 @@ static int unpack_nondirectories(int n, unsigned long mask,
for (i = 0; i < n; i++)
if (src[i] && src[i] != o->df_conflict_entry)
- add_entry(o, src[i], 0, 0);
+ do_add_entry(o, src[i], 0, 0);
return 0;
}
static int unpack_failed(struct unpack_trees_options *o, const char *message)
{
discard_index(&o->result);
- if (!o->gently) {
+ if (!o->gently && !o->exiting_early) {
if (message)
return error("%s", message);
return -1;
@@ -634,7 +633,7 @@ static int find_cache_pos(struct traverse_info *info,
struct unpack_trees_options *o = info->data;
struct index_state *index = o->src_index;
int pfxlen = info->pathlen;
- int p_len = tree_entry_len(p->path, p->sha1);
+ int p_len = tree_entry_len(p);
for (pos = o->cache_bottom; pos < index->cache_nr; pos++) {
struct cache_entry *ce = index->cache[pos];
@@ -694,53 +693,6 @@ static struct cache_entry *find_cache_entry(struct traverse_info *info,
return NULL;
}
-static int fast_forward_merge(int n, unsigned long dirmask,
- struct name_entry *names,
- struct traverse_info *info)
-{
- int i;
- struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, };
- struct unpack_trees_options *o = info->data;
-
- /* merging two or more trees with an identical subdirectory? */
- if ((n < 2) || ((1UL << n) - 1) != dirmask ||
- !o->merge || o->reset || o->initial_checkout)
- return 0;
- for (i = 1; i < n; i++)
- if (hashcmp(names[i-1].sha1, names[i].sha1))
- return 0;
-
- /*
- * Instead of descending into the directory, keep the contents
- * of the current index.
- */
- while (1) {
- struct cache_entry *ce;
- ce = next_cache_entry(o);
- if (!ce)
- break;
- /* Is the entry still in that directory? */
- if (do_compare_entry(ce, info, names))
- break;
- /*
- * Note: we do not just run unpack_index_entry() here,
- * as the callback may want to compare what is in the
- * index with what are from the HEAD and the other tree
- * and reject the merge. We pretend that ancestors, the
- * HEAD and the other tree all have the same contents as
- * the current index, which is a lie, but it works.
- */
- for (i = 0; i < n + 1; i++)
- src[i] = ce;
- mark_ce_used(ce, o);
- if (call_unpack_fn(src, o) < 0)
- return unpack_failed(o, NULL);
- if (ce_stage(ce))
- mark_ce_used_same_name(ce, o);
- }
- return dirmask;
-}
-
static void debug_path(struct traverse_info *info)
{
if (info->prev) {
@@ -827,7 +779,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
if (unpack_nondirectories(n, mask, dirmask, src, names, info) < 0)
return -1;
- if (src[0]) {
+ if (o->merge && src[0]) {
if (ce_stage(src[0]))
mark_ce_used_same_name(src[0], o);
else
@@ -870,43 +822,45 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
return mask;
}
+static int clear_ce_flags_1(struct cache_entry **cache, int nr,
+ char *prefix, int prefix_len,
+ int select_mask, int clear_mask,
+ struct exclude_list *el, int defval);
+
/* Whole directory matching */
static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
char *prefix, int prefix_len,
char *basename,
int select_mask, int clear_mask,
- struct exclude_list *el)
+ struct exclude_list *el, int defval)
{
- struct cache_entry **cache_end = cache + nr;
+ struct cache_entry **cache_end;
int dtype = DT_DIR;
int ret = excluded_from_list(prefix, prefix_len, basename, &dtype, el);
prefix[prefix_len++] = '/';
- /* included, no clearing for any entries under this directory */
- if (!ret) {
- for (; cache != cache_end; cache++) {
- struct cache_entry *ce = *cache;
- if (strncmp(ce->name, prefix, prefix_len))
- break;
- }
- return nr - (cache_end - cache);
- }
+ /* If undecided, use matching result of parent dir in defval */
+ if (ret < 0)
+ ret = defval;
- /* excluded, clear all selected entries under this directory. */
- if (ret == 1) {
- for (; cache != cache_end; cache++) {
- struct cache_entry *ce = *cache;
- if (select_mask && !(ce->ce_flags & select_mask))
- continue;
- if (strncmp(ce->name, prefix, prefix_len))
- break;
- ce->ce_flags &= ~clear_mask;
- }
- return nr - (cache_end - cache);
+ for (cache_end = cache; cache_end != cache + nr; cache_end++) {
+ struct cache_entry *ce = *cache_end;
+ if (strncmp(ce->name, prefix, prefix_len))
+ break;
}
- return 0;
+ /*
+ * TODO: check el, if there are no patterns that may conflict
+ * with ret (iow, we know in advance the incl/excl
+ * decision for the entire directory), clear flag here without
+ * calling clear_ce_flags_1(). That function will call
+ * the expensive excluded_from_list() on every entry.
+ */
+ return clear_ce_flags_1(cache, cache_end - cache,
+ prefix, prefix_len,
+ select_mask, clear_mask,
+ el, ret);
}
/*
@@ -927,7 +881,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
static int clear_ce_flags_1(struct cache_entry **cache, int nr,
char *prefix, int prefix_len,
int select_mask, int clear_mask,
- struct exclude_list *el)
+ struct exclude_list *el, int defval)
{
struct cache_entry **cache_end = cache + nr;
@@ -938,7 +892,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,
while(cache != cache_end) {
struct cache_entry *ce = *cache;
const char *name, *slash;
- int len, dtype;
+ int len, dtype, ret;
if (select_mask && !(ce->ce_flags & select_mask)) {
cache++;
@@ -967,7 +921,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,
prefix, prefix_len + len,
prefix + prefix_len,
select_mask, clear_mask,
- el);
+ el, defval);
/* clear_c_f_dir eats a whole dir already? */
if (processed) {
@@ -978,13 +932,16 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,
prefix[prefix_len + len++] = '/';
cache += clear_ce_flags_1(cache, cache_end - cache,
prefix, prefix_len + len,
- select_mask, clear_mask, el);
+ select_mask, clear_mask, el, defval);
continue;
}
/* Non-directory */
dtype = ce_to_dtype(ce);
- if (excluded_from_list(ce->name, ce_namelen(ce), name, &dtype, el) > 0)
+ ret = excluded_from_list(ce->name, ce_namelen(ce), name, &dtype, el);
+ if (ret < 0)
+ ret = defval;
+ if (ret > 0)
ce->ce_flags &= ~clear_mask;
cache++;
}
@@ -999,7 +956,7 @@ static int clear_ce_flags(struct cache_entry **cache, int nr,
return clear_ce_flags_1(cache, nr,
prefix, 0,
select_mask, clear_mask,
- el);
+ el, 0);
}
/*
@@ -1091,6 +1048,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
info.fn = unpack_callback;
info.data = o;
info.show_all_errors = o->show_all_errors;
+ info.pathspec = o->pathspec;
if (o->prefix) {
/*
@@ -1140,6 +1098,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
*/
mark_new_skip_worktree(o->el, &o->result, CE_ADDED, CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
+ ret = 0;
for (i = 0; i < o->result.cache_nr; i++) {
struct cache_entry *ce = o->result.cache[i];
@@ -1152,19 +1111,30 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
* correct CE_NEW_SKIP_WORKTREE
*/
if (ce->ce_flags & CE_ADDED &&
- verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))
- return -1;
+ verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) {
+ if (!o->show_all_errors)
+ goto return_failed;
+ ret = -1;
+ }
if (apply_sparse_checkout(ce, o)) {
+ if (!o->show_all_errors)
+ goto return_failed;
ret = -1;
- goto done;
}
if (!ce_skip_worktree(ce))
empty_worktree = 0;
}
+ if (ret < 0)
+ goto return_failed;
+ /*
+ * Sparse checkout is meant to narrow down checkout area
+ * but it does not make sense to narrow down to empty working
+ * tree. This is usually a mistake in sparse checkout rules.
+ * Do not allow users to do that.
+ */
if (o->result.cache_nr && empty_worktree) {
- /* dubious---why should this fail??? */
ret = unpack_failed(o, "Sparse checkout leaves no entry on working directory");
goto done;
}
@@ -1184,6 +1154,8 @@ return_failed:
display_error_msgs(o);
mark_all_ce_unused(o->src_index);
ret = unpack_failed(o, NULL);
+ if (o->exiting_early)
+ ret = 0;
goto done;
}
@@ -1217,16 +1189,27 @@ static int verify_uptodate_1(struct cache_entry *ce,
{
struct stat st;
- if (o->index_only || (!((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) && (o->reset || ce_uptodate(ce))))
+ if (o->index_only)
+ return 0;
+
+ /*
+ * CE_VALID and CE_SKIP_WORKTREE cheat, we better check again
+ * if this entry is truly up-to-date because this file may be
+ * overwritten.
+ */
+ if ((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce))
+ ; /* keep checking */
+ else if (o->reset || ce_uptodate(ce))
return 0;
if (!lstat(ce->name, &st)) {
- unsigned changed = ie_match_stat(o->src_index, ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
+ int flags = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE;
+ unsigned changed = ie_match_stat(o->src_index, ce, &st, flags);
if (!changed)
return 0;
/*
* NEEDSWORK: the current default policy is to allow
- * submodule to be out of sync wrt the supermodule
+ * submodule to be out of sync wrt the superproject
* index. This needs to be tightened later for
* submodules that are marked to be automatically
* checked out.