static void checkout_all(const char *prefix, int prefix_length) { int i, errs = 0; struct cache_entry *last_ce = NULL; for (i = 0; i < active_nr ; i++) { struct cache_entry *ce = active_cache[i]; if (ce_stage(ce) != checkout_stage && (CHECKOUT_ALL != checkout_stage || !ce_stage(ce))) continue; if (prefix && *prefix && (ce_namelen(ce) <= prefix_length || memcmp(prefix, ce->name, prefix_length))) continue; if (last_ce && to_tempfile) { if (ce_namelen(last_ce) != ce_namelen(ce) || memcmp(last_ce->name, ce->name, ce_namelen(ce))) write_tempfile_record(last_ce->name, prefix); } if (checkout_entry(ce, &state, to_tempfile ? topath[ce_stage(ce)] : NULL) < 0) errs++; last_ce = ce; } if (last_ce && to_tempfile) write_tempfile_record(last_ce->name, prefix); if (errs) /* we have already done our error reporting. * exit with the same code as die(). */ exit(128); }
/* * 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(const struct cache_entry *ce, enum unpack_trees_error_types error_type, struct unpack_trees_options *o) { int len; struct stat st; if (o->index_only || o->reset || !o->update) return 0; len = check_leading_path(ce->name, ce_namelen(ce)); if (!len) return 0; else if (len > 0) { char path[PATH_MAX + 1]; memcpy(path, ce->name, len); path[len] = 0; if (lstat(path, &st)) return error("cannot stat '%s': %s", path, strerror(errno)); return check_ok_to_remove(path, len, DT_UNKNOWN, NULL, &st, error_type, o); } else if (lstat(ce->name, &st)) { if (errno != ENOENT) return error("cannot stat '%s': %s", ce->name, strerror(errno)); return 0; } else { return check_ok_to_remove(ce->name, ce_namelen(ce), ce_to_dtype(ce), ce, &st, error_type, o); } }
/* * Unlink the last component and schedule the leading directories for * removal, such that empty directories get removed. */ static void unlink_entry(const struct cache_entry *ce) { if (!check_leading_path(ce->name, ce_namelen(ce))) return; if (remove_or_warn(ce->ce_mode, ce->name)) return; schedule_dir_for_removal(ce->name, ce_namelen(ce)); }
/* * We call unpack_index_entry() with an unmerged cache entry * only in diff-index, and it wants a single callback. Skip * the other unmerged entry with the same name. */ static void mark_ce_used_same_name(struct cache_entry *ce, struct unpack_trees_options *o) { struct index_state *index = o->src_index; int len = ce_namelen(ce); int pos; for (pos = locate_in_src_index(ce, o); pos < index->cache_nr; pos++) { struct cache_entry *next = index->cache[pos]; if (len != ce_namelen(next) || memcmp(ce->name, next->name, len)) break; mark_ce_used(next, o); } }
static int unresolve_one(const char *path) { int namelen = strlen(path); int pos; int ret = 0; struct cache_entry *ce_2 = NULL, *ce_3 = NULL; /* See if there is such entry in the index. */ pos = cache_name_pos(path, namelen); if (pos < 0) { /* If there isn't, either it is unmerged, or * resolved as "removed" by mistake. We do not * want to do anything in the former case. */ pos = -pos-1; if (pos < active_nr) { struct cache_entry *ce = active_cache[pos]; if (ce_namelen(ce) == namelen && !memcmp(ce->name, path, namelen)) { fprintf(stderr, "%s: skipping still unmerged path.\n", path); goto free_return; } } } /* Grab blobs from given path from HEAD and MERGE_HEAD, * stuff HEAD version in stage #2, * stuff MERGE_HEAD version in stage #3. */ ce_2 = read_one_ent("our", head_sha1, path, namelen, 2); ce_3 = read_one_ent("their", merge_head_sha1, path, namelen, 3); if (!ce_2 || !ce_3) { ret = -1; goto free_return; } if (!hashcmp(ce_2->sha1, ce_3->sha1) && ce_2->ce_mode == ce_3->ce_mode) { fprintf(stderr, "%s: identical in both, skipping.\n", path); goto free_return; } remove_file_from_cache(path); if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) { error("%s: cannot add our version to the index.", path); ret = -1; goto free_return; } if (!add_cache_entry(ce_3, ADD_CACHE_OK_TO_ADD)) return 0; error("%s: cannot add their version to the index.", path); ret = -1; free_return: free(ce_2); free(ce_3); return ret; }
static void add_dir_entry(struct index_state *istate, struct cache_entry *ce) { /* Add reference to the directory entry (and parents if 0). */ struct dir_entry *dir = hash_dir_entry(istate, ce, ce_namelen(ce)); while (dir && !(dir->nr++)) dir = dir->parent; }
static void *preload_thread(void *_data) { int nr; struct thread_data *p = _data; struct index_state *index = p->index; struct cache_entry **cep = index->cache + p->offset; struct cache_def cache; memset(&cache, 0, sizeof(cache)); nr = p->nr; if (nr + p->offset > index->cache_nr) nr = index->cache_nr - p->offset; do { struct cache_entry *ce = *cep++; struct stat st; if (ce_stage(ce)) continue; if (ce_uptodate(ce)) continue; if (!ce_path_match(ce, p->pathspec)) continue; if (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce))) continue; if (lstat(ce->name, &st)) continue; if (ie_match_stat(index, ce, &st, CE_MATCH_RACY_IS_DIRTY)) continue; ce_mark_uptodate(ce); } while (--nr > 0); return NULL; }
/* * Take a union of paths in the index and the named tree (typically, "HEAD"), * and return the paths that match the given pattern in list. */ static int list_paths(struct string_list *list, const char *with_tree, const char *prefix, const char **pattern) { int i; char *m; if (!pattern) return 0; for (i = 0; pattern[i]; i++) ; m = xcalloc(1, i); if (with_tree) { char *max_prefix = common_prefix(pattern); overlay_tree_on_cache(with_tree, max_prefix ? max_prefix : prefix); free(max_prefix); } for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; struct string_list_item *item; if (ce->ce_flags & CE_UPDATE) continue; if (!match_pathspec(pattern, ce->name, ce_namelen(ce), 0, m)) continue; item = string_list_insert(list, ce->name); if (ce_skip_worktree(ce)) item->util = item; /* better a valid pointer than a fake one */ } return report_path_error(m, pattern, prefix); }
void gitmodules_config(void) { const char *work_tree = get_git_work_tree(); if (work_tree) { struct strbuf gitmodules_path = STRBUF_INIT; int pos; strbuf_addstr(&gitmodules_path, work_tree); strbuf_addstr(&gitmodules_path, "/.gitmodules"); if (read_cache() < 0) die("index file corrupt"); pos = cache_name_pos(".gitmodules", 11); if (pos < 0) { /* .gitmodules not found or isn't merged */ pos = -1 - pos; if (active_nr > pos) { /* there is a .gitmodules */ const struct cache_entry *ce = active_cache[pos]; if (ce_namelen(ce) == 11 && !memcmp(ce->name, ".gitmodules", 11)) gitmodules_is_unmerged = 1; } } if (!gitmodules_is_unmerged) git_config_from_file(submodule_config, gitmodules_path.buf, NULL); strbuf_release(&gitmodules_path); } }
static void treat_gitlinks(const char **pathspec) { int i; if (!pathspec || !*pathspec) return; for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (S_ISGITLINK(ce->ce_mode)) { int len = ce_namelen(ce), j; for (j = 0; pathspec[j]; j++) { int len2 = strlen(pathspec[j]); if (len2 <= len || pathspec[j][len] != '/' || memcmp(ce->name, pathspec[j], len)) continue; if (len2 == len + 1) /* strip trailing slash */ pathspec[j] = xstrndup(ce->name, len); else die ("Path '%s' is in submodule '%.*s'", pathspec[j], len, ce->name); } } } }
struct tree *write_tree_from_memory(struct merge_options *o) { struct tree *result = NULL; if (unmerged_cache()) { int i; fprintf(stderr, "BUG: There are unmerged index entries:\n"); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (ce_stage(ce)) fprintf(stderr, "BUG: %d %.*s", ce_stage(ce), (int)ce_namelen(ce), ce->name); } die("Bug in merge-recursive.c"); } if (!active_cache_tree) active_cache_tree = cache_tree(); if (!cache_tree_fully_valid(active_cache_tree) && cache_tree_update(active_cache_tree, active_cache, active_nr, 0, 0) < 0) die("error building trees"); result = lookup_tree(active_cache_tree->sha1); return result; }
struct tree *write_tree_from_memory(struct merge_options *o) { struct tree *result = NULL; if (unmerged_cache()) { int i; output(o, 0, "There are unmerged index entries:"); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (ce_stage(ce)) output(o, 0, "%d %.*s", ce_stage(ce), ce_namelen(ce), ce->name); } return NULL; } if (!active_cache_tree) active_cache_tree = cache_tree(); if (!cache_tree_fully_valid(active_cache_tree) && cache_tree_update(active_cache_tree, active_cache, active_nr, 0, 0) < 0) die("error building trees"); result = lookup_tree(active_cache_tree->sha1); return result; }
char *write_tree_from_memory(struct merge_options *o) { struct cache_tree *it; char root_id[41]; if (unmerged_index(o->index)) { int i; fprintf(stderr, "BUG: There are unmerged index entries:\n"); for (i = 0; i < o->index->cache_nr; i++) { struct cache_entry *ce = o->index->cache[i]; if (ce_stage(ce)) fprintf(stderr, "BUG: %d %.*s", ce_stage(ce), (int)ce_namelen(ce), ce->name); } g_assert(0); } /* if (!active_cache_tree) */ it = cache_tree(); if (cache_tree_update(it, o->index->cache, o->index->cache_nr, 0, 0, commit_trees_cb) < 0) { g_warning("error building trees"); cache_tree_free (&it); return NULL; } rawdata_to_hex(it->sha1, root_id, 20); cache_tree_free (&it); return g_strdup(root_id); }
/* * Has the work tree entity been removed? * * Return 1 if it was removed from the work tree, 0 if an entity to be * compared with the cache entry ce still exists (the latter includes * the case where a directory that is not a submodule repository * exists for ce that is a submodule -- it is a submodule that is not * checked out). Return negative for an error. */ static int check_removed(const struct cache_entry *ce, struct stat *st) { if (lstat(ce->name, st) < 0) { if (errno != ENOENT && errno != ENOTDIR) return -1; return 1; } if (has_symlink_leading_path(ce->name, ce_namelen(ce))) return 1; if (S_ISDIR(st->st_mode)) { unsigned char sub[20]; /* * If ce is already a gitlink, we can have a plain * directory (i.e. the submodule is not checked out), * or a checked out submodule. Either case this is not * a case where something was removed from the work tree, * so we will return 0. * * Otherwise, if the directory is not a submodule * repository, that means ce which was a blob turned into * a directory --- the blob was removed! */ if (!S_ISGITLINK(ce->ce_mode) && resolve_gitlink_ref(ce->name, "HEAD", sub)) return 1; } return 0; }
static int do_compare_entry(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n) { int len, pathlen, ce_len; const char *ce_name; int cmp; /* * If we have not precomputed the traverse path, it is quicker * to avoid doing so. But if we have precomputed it, * it is quicker to use the precomputed version. */ if (!info->traverse_path) return do_compare_entry_piecewise(ce, info, n); cmp = strncmp(ce->name, info->traverse_path, info->pathlen); if (cmp) return cmp; pathlen = info->pathlen; ce_len = ce_namelen(ce); if (ce_len < pathlen) return -1; ce_len -= pathlen; ce_name = ce->name + pathlen; len = tree_entry_len(n); return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode); }
static int handle_cache(const char *path, unsigned char *sha1, const char *output) { mmfile_t mmfile[3]; mmbuffer_t result = {NULL, 0}; struct cache_entry *ce; int pos, len, i, hunk_no; struct rerere_io_mem io; int marker_size = ll_merge_marker_size(path); /* * Reproduce the conflicted merge in-core */ len = strlen(path); pos = cache_name_pos(path, len); if (0 <= pos) return -1; pos = -pos - 1; for (i = 0; i < 3; i++) { enum object_type type; unsigned long size; mmfile[i].size = 0; mmfile[i].ptr = NULL; if (active_nr <= pos) break; ce = active_cache[pos++]; if (ce_namelen(ce) != len || memcmp(ce->name, path, len) || ce_stage(ce) != i + 1) break; mmfile[i].ptr = read_sha1_file(ce->sha1, &type, &size); mmfile[i].size = size; } for (i = 0; i < 3; i++) { if (!mmfile[i].ptr && !mmfile[i].size) mmfile[i].ptr = xstrdup(""); } ll_merge(&result, path, &mmfile[0], &mmfile[1], "ours", &mmfile[2], "theirs", 0); for (i = 0; i < 3; i++) free(mmfile[i].ptr); memset(&io, 0, sizeof(io)); io.io.getline = rerere_mem_getline; if (output) io.io.output = fopen(output, "w"); else io.io.output = NULL; strbuf_init(&io.input, 0); strbuf_attach(&io.input, result.ptr, result.size, result.size); hunk_no = handle_path(sha1, (struct rerere_io *)&io, marker_size); strbuf_release(&io.input); if (io.io.output) fclose(io.io.output); return hunk_no; }
static void add_same_unmerged(const struct cache_entry *ce, struct unpack_trees_options *o) { struct index_state *index = o->src_index; int len = ce_namelen(ce); int pos = index_name_pos(index, ce->name, len); if (0 <= pos) die("programming error in a caller of mark_ce_used_same_name"); for (pos = -pos - 1; pos < index->cache_nr; pos++) { struct cache_entry *next = index->cache[pos]; if (len != ce_namelen(next) || memcmp(ce->name, next->name, len)) break; add_entry(o, next, 0, 0); mark_ce_used(next, o); } }
static int unlink_entry (struct cache_entry *ce, struct unpack_trees_options *o) { char path[SEAF_PATH_MAX]; SeafStat st; int base_len = strlen(o->base); int len = ce_namelen(ce); int offset; if (!len) { g_warning ("entry name should not be empty.\n"); return -1; } snprintf (path, SEAF_PATH_MAX, "%s/%s", o->base, ce->name); if (!S_ISDIR(ce->ce_mode)) { /* file doesn't exist in work tree */ if (seaf_stat (path, &st) < 0 || !S_ISREG(st.st_mode)) { return 0; } /* file has been changed. */ if (!o->reset && (ce->ce_ctime.sec != st.st_ctime || ce->ce_mtime.sec != st.st_mtime)) { g_warning ("File %s is changed. Skip removing the file.\n", path); return -1; } /* first unlink the file. */ if (g_unlink (path) < 0) { g_warning ("Failed to remove %s: %s.\n", path, strerror(errno)); return -1; } } else { if (seaf_remove_empty_dir (path) < 0) return -1; } /* then remove all empty directories upwards. */ offset = base_len + len; do { if (path[offset] == '/') { path[offset] = '\0'; int ret = g_rmdir (path); if (ret < 0 && errno == ENOTEMPTY) { break; } else if (ret < 0) { g_warning ("Failed to remove %s: %s.\n", path, strerror(errno)); return -1; } } } while (--offset > base_len); return 0; }
static int locate_in_src_index(const struct cache_entry *ce, struct unpack_trees_options *o) { struct index_state *index = o->src_index; int len = ce_namelen(ce); int pos = index_name_pos(index, ce->name, len); if (pos < 0) pos = -1 - pos; return pos; }
static void hash_index_entry(struct index_state *istate, struct cache_entry *ce) { if (ce->ce_flags & CE_HASHED) return; ce->ce_flags |= CE_HASHED; hashmap_entry_init(ce, memihash(ce->name, ce_namelen(ce))); hashmap_add(&istate->name_hash, ce); if (ignore_case) add_dir_entry(istate, ce); }
/* * The tree traversal is looking at name p. If we have a matching entry, * return it. If name p is a directory in the index, do not return * anything, as we will want to match it when the traversal descends into * the directory. */ static int find_cache_pos(struct traverse_info *info, const struct name_entry *p) { int pos; 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); for (pos = o->cache_bottom; pos < index->cache_nr; pos++) { const struct cache_entry *ce = index->cache[pos]; const char *ce_name, *ce_slash; int cmp, ce_len; if (ce->ce_flags & CE_UNPACKED) { /* * cache_bottom entry is already unpacked, so * we can never match it; don't check it * again. */ if (pos == o->cache_bottom) ++o->cache_bottom; continue; } if (!ce_in_traverse_path(ce, info)) continue; ce_name = ce->name + pfxlen; ce_slash = strchr(ce_name, '/'); if (ce_slash) ce_len = ce_slash - ce_name; else ce_len = ce_namelen(ce) - pfxlen; cmp = name_compare(p->path, p_len, ce_name, ce_len); /* * Exact match; if we have a directory we need to * delay returning it. */ if (!cmp) return ce_slash ? -2 - pos : pos; if (0 < cmp) continue; /* keep looking */ /* * ce_name sorts after p->path; could it be that we * have files under p->path directory in the index? * E.g. ce_name == "t-i", and p->path == "t"; we may * have "t/a" in the index. */ if (p_len < ce_len && !memcmp(ce_name, p->path, p_len) && ce_name[p_len] < '/') continue; /* keep looking */ break; } return -1; }
/* * This removes all trivial merges that don't change the tree * and collapses them to state 0. * * _Any_ other merge is left to user policy. That includes "both * created the same file", and "both removed the same file" - which are * trivial, but the user might still want to _note_ it. */ static struct cache_entry *merge_entries(struct cache_entry *a, struct cache_entry *b, struct cache_entry *c) { int len = ce_namelen(a); /* * Are they all the same filename? We won't do * any name merging */ if (ce_namelen(b) != len || ce_namelen(c) != len || memcmp(a->name, b->name, len) || memcmp(a->name, c->name, len)) return NULL; /* * Ok, all three entries describe the same * filename, but maybe the contents or file * mode have changed? * * The trivial cases end up being the ones where two * out of three files are the same: * - both destinations the same, trivially take either * - one of the destination versions hasn't changed, * take the other. * * The "all entries exactly the same" case falls out as * a special case of any of the "two same" cases. * * Here "a" is "original", and "b" and "c" are the two * trees we are merging. */ if (same(b,c)) return c; if (same(a,b)) return c; if (same(a,c)) return b; return NULL; }
static int compare_entry(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n) { int cmp = do_compare_entry(ce, info, n); if (cmp) return cmp; /* * Even if the beginning compared identically, the ce should * compare as bigger than a directory leading up to it! */ return ce_namelen(ce) > traverse_path_len(info, n); }
static int show_modified(struct rev_info *revs, const struct cache_entry *old_entry, const struct cache_entry *new_entry, int report_missing, int cached, int match_missing) { unsigned int mode, oldmode; const struct object_id *oid; unsigned dirty_submodule = 0; if (get_stat_data(new_entry, &oid, &mode, cached, match_missing, &dirty_submodule, &revs->diffopt) < 0) { if (report_missing) diff_index_show_file(revs, "-", old_entry, &old_entry->oid, 1, old_entry->ce_mode, 0); return -1; } if (revs->combine_merges && !cached && (!oideq(oid, &old_entry->oid) || !oideq(&old_entry->oid, &new_entry->oid))) { struct combine_diff_path *p; int pathlen = ce_namelen(new_entry); p = xmalloc(combine_diff_path_size(2, pathlen)); p->path = (char *) &p->parent[2]; p->next = NULL; memcpy(p->path, new_entry->name, pathlen); p->path[pathlen] = 0; p->mode = mode; oidclr(&p->oid); memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent)); p->parent[0].status = DIFF_STATUS_MODIFIED; p->parent[0].mode = new_entry->ce_mode; oidcpy(&p->parent[0].oid, &new_entry->oid); p->parent[1].status = DIFF_STATUS_MODIFIED; p->parent[1].mode = old_entry->ce_mode; oidcpy(&p->parent[1].oid, &old_entry->oid); show_combined_diff(p, 2, revs->dense_combined_merges, revs); free(p); return 0; } oldmode = old_entry->ce_mode; if (mode == oldmode && oideq(oid, &old_entry->oid) && !dirty_submodule && !revs->diffopt.flags.find_copies_harder) return 0; diff_change(&revs->diffopt, oldmode, mode, &old_entry->oid, oid, 1, !is_null_oid(oid), old_entry->name, 0, dirty_submodule); return 0; }
static void show_ce_entry(const char *tag, struct cache_entry *ce) { int len = prefix_len; int offset = prefix_offset; if (len >= ce_namelen(ce)) die("git ls-files: internal error - cache entry not superset of prefix"); if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), len, ps_matched)) return; if (tag && *tag && show_valid_bit && (ce->ce_flags & CE_VALID)) { static char alttag[4]; memcpy(alttag, tag, 3); if (isalpha(tag[0])) alttag[0] = tolower(tag[0]); else if (tag[0] == '?') alttag[0] = '!'; else { alttag[0] = 'v'; alttag[1] = tag[0]; alttag[2] = ' '; alttag[3] = 0; } tag = alttag; } if (!show_stage) { fputs(tag, stdout); } else { printf("%s%06o %s %d\t", tag, ce->ce_mode, abbrev ? find_unique_abbrev(ce->sha1,abbrev) : sha1_to_hex(ce->sha1), ce_stage(ce)); } write_name_quoted(ce->name + offset, stdout, line_terminator); }
static int ce_in_traverse_path(const struct cache_entry *ce, const struct traverse_info *info) { if (!info->prev) return 1; if (do_compare_entry(ce, info->prev, &info->name)) return 0; /* * If ce (blob) is the same name as the path (which is a tree * we will be descending into), it won't be inside it. */ return (info->pathlen < ce_namelen(ce)); }
static void diff_stages(int stage1, int stage2) { int i = 0; while (i < active_nr) { struct cache_entry *ce, *stages[4] = { NULL, }; struct cache_entry *one, *two; const char *name; int len; ce = active_cache[i]; len = ce_namelen(ce); name = ce->name; for (;;) { int stage = ce_stage(ce); stages[stage] = ce; if (active_nr <= ++i) break; ce = active_cache[i]; if (ce_namelen(ce) != len || memcmp(name, ce->name, len)) break; } one = stages[stage1]; two = stages[stage2]; if (!one && !two) continue; if (!one) diff_addremove(&diff_options, '+', ntohl(two->ce_mode), two->sha1, name, NULL); else if (!two) diff_addremove(&diff_options, '-', ntohl(one->ce_mode), one->sha1, name, NULL); else if (memcmp(one->sha1, two->sha1, 20) || (one->ce_mode != two->ce_mode) || diff_options.find_copies_harder) diff_change(&diff_options, ntohl(one->ce_mode), ntohl(two->ce_mode), one->sha1, two->sha1, name, NULL); } }
static int do_reupdate(int ac, const char **av, const char *prefix, int prefix_length) { /* Read HEAD and run update-index on paths that are * merged and already different between index and HEAD. */ int pos; int has_head = 1; struct pathspec pathspec; parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD, prefix, av + 1); if (read_ref("HEAD", &head_oid)) /* If there is no HEAD, that means it is an initial * commit. Update everything in the index. */ has_head = 0; redo: for (pos = 0; pos < active_nr; pos++) { const struct cache_entry *ce = active_cache[pos]; struct cache_entry *old = NULL; int save_nr; char *path; if (ce_stage(ce) || !ce_path_match(&the_index, ce, &pathspec, NULL)) continue; if (has_head) old = read_one_ent(NULL, &head_oid, ce->name, ce_namelen(ce), 0); if (old && ce->ce_mode == old->ce_mode && !oidcmp(&ce->oid, &old->oid)) { discard_cache_entry(old); continue; /* unchanged */ } /* Be careful. The working tree may not have the * path anymore, in which case, under 'allow_remove', * or worse yet 'allow_replace', active_nr may decrease. */ save_nr = active_nr; path = xstrdup(ce->name); update_one(path); free(path); discard_cache_entry(old); if (save_nr != active_nr) goto redo; } clear_pathspec(&pathspec); return 0; }
static int matches_pathspec(struct cache_entry *ce, char **spec, int cnt) { int i; int namelen = ce_namelen(ce); for (i = 0; i < cnt; i++) { int speclen = strlen(spec[i]); if (! strncmp(spec[i], ce->name, speclen) && speclen <= namelen && (ce->name[speclen] == 0 || ce->name[speclen] == '/')) return 1; } return 0; }
void unmerge_index(struct index_state *istate, const char **pathspec) { int i; if (!istate->resolve_undo) return; for (i = 0; i < istate->cache_nr; i++) { struct cache_entry *ce = istate->cache[i]; if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL)) continue; i = unmerge_index_entry_at(istate, i); } }