/* * One-way merge. * * The rule is: * - take the stat information from stage0, take the data from stage1 */ int oneway_merge(const struct cache_entry * const *src, struct unpack_trees_options *o) { const struct cache_entry *old = src[0]; const struct cache_entry *a = src[1]; if (o->merge_size != 1) return error("Cannot do a oneway merge of %d trees", o->merge_size); if (!a || a == o->df_conflict_entry) return deleted_entry(old, old, o); if (old && same(old, a)) { int update = 0; if (o->reset && o->update && !ce_uptodate(old) && !ce_skip_worktree(old)) { struct stat st; if (lstat(old->name, &st) || ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE)) update |= CE_UPDATE; } add_entry(o, old, update, 0); return 0; } return merged_entry(a, old, o); }
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; }
/* * This gets called when there was no index entry for the tree entry 'dst', * but we found a file in the working tree that 'lstat()' said was fine, * and we're on a case-insensitive filesystem. * * See if we can find a case-insensitive match in the index that also * matches the stat information, and assume it's that other file! */ static int icase_exists(struct unpack_trees_options *o, const char *name, int len, struct stat *st) { const struct cache_entry *src; src = index_file_exists(o->src_index, name, len, 1); return src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE); }
/* * Has a file changed or has a submodule new commits or a dirty work tree? * * Return 1 when changes are detected, 0 otherwise. If the DIRTY_SUBMODULES * option is set, the caller does not only want to know if a submodule is * modified at all but wants to know all the conditions that are met (new * commits, untracked content and/or modified content). */ static int match_stat_with_submodule(struct diff_options *diffopt, const struct cache_entry *ce, struct stat *st, unsigned ce_option, unsigned *dirty_submodule) { int changed = ie_match_stat(diffopt->repo->index, ce, st, ce_option); if (S_ISGITLINK(ce->ce_mode)) { struct diff_flags orig_flags = diffopt->flags; if (!diffopt->flags.override_submodule_config) set_diffopt_flags_from_submodule_config(diffopt, ce->name); if (diffopt->flags.ignore_submodules) changed = 0; else if (!diffopt->flags.ignore_dirty_submodules && (!changed || diffopt->flags.dirty_submodules)) *dirty_submodule = is_submodule_modified(ce->name, diffopt->flags.ignore_untracked_in_submodules); diffopt->flags = orig_flags; } return changed; }
/* * When a CE gets turned into an unmerged entry, we * want it to be up-to-date */ static int verify_uptodate_1(const struct cache_entry *ce, struct unpack_trees_options *o, enum unpack_trees_error_types error_type) { struct stat st; 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)) { 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 superproject * index. This needs to be tightened later for * submodules that are marked to be automatically * checked out. */ if (S_ISGITLINK(ce->ce_mode)) return 0; errno = 0; } if (errno == ENOENT) return 0; return o->gently ? -1 : add_rejected_path(o, error_type, ce->name); }
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 = CACHE_DEF_INIT; 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 (S_ISGITLINK(ce->ce_mode)) continue; if (ce_uptodate(ce)) continue; if (ce_skip_worktree(ce)) continue; if (ce->ce_flags & CE_FSMONITOR_VALID) continue; if (!ce_path_match(index, ce, &p->pathspec, NULL)) 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|CE_MATCH_IGNORE_FSMONITOR)) continue; ce_mark_uptodate(ce); mark_fsmonitor_valid(ce); } while (--nr > 0); cache_def_clear(&cache); return NULL; }
void wt_status_collect_changes_worktree(struct index_state *index, GList **results, const char *worktree) { DiffEntry *de; int entries, i; GList *ignore_list = seaf_repo_load_ignore_files (worktree); entries = index->cache_nr; for (i = 0; i < entries; i++) { char *realpath; SeafStat st; struct cache_entry *ce = index->cache[i]; int changed = 0; if (ce_stage(ce)) { int mask = 0; mask |= 1 << ce_stage(ce); while (i < entries) { struct cache_entry *nce = index->cache[i]; if (strcmp(ce->name, nce->name)) break; mask |= 1 << ce_stage(nce); i++; } /* * Compensate for loop update */ i--; de = diff_entry_new (DIFF_TYPE_WORKTREE, DIFF_STATUS_UNMERGED, ce->sha1, ce->name); de->unmerge_state = diff_unmerged_state (mask); *results = g_list_prepend (*results, de); continue; } if (ce_uptodate(ce) || ce_skip_worktree(ce)) continue; realpath = g_build_path (PATH_SEPERATOR, worktree, ce->name, NULL); if (seaf_stat(realpath, &st) < 0) { if (errno != ENOENT && errno != ENOTDIR) changed = -1; else changed = 1; } if (changed) { if (changed < 0) { g_warning ("Faile to stat %s: %s\n", ce->name, strerror(errno)); g_free (realpath); continue; } if (ce->ce_ctime.sec == 0) { g_free (realpath); continue; } de = diff_entry_new (DIFF_TYPE_WORKTREE, DIFF_STATUS_DELETED, ce->sha1, ce->name); *results = g_list_prepend (*results, de); g_free (realpath); continue; } if (S_ISDIR (ce->ce_mode)) { g_free (realpath); continue; } /* Don't check changes to ignored files. * This can happen when a file is committed and then added to * ignore.txt. After that changes to this file will not committed, * and it should be ignored here. */ if (seaf_repo_check_ignore_file (ignore_list, realpath)) { g_free (realpath); continue; } g_free (realpath); changed = ie_match_stat (index, ce, &st, 0); if (!changed) { ce_mark_uptodate (ce); continue; } de = diff_entry_new (DIFF_TYPE_WORKTREE, DIFF_STATUS_MODIFIED, ce->sha1, ce->name); *results = g_list_prepend (*results, de); } seaf_repo_free_ignore_files (ignore_list); }
void wt_status_collect_changes_worktree(struct index_state *index, GList **results, const char *worktree, IgnoreFunc ignore_func) { DiffEntry *de; int entries, i; entries = index->cache_nr; for (i = 0; i < entries; i++) { char *realpath; struct stat st; struct cache_entry *ce = index->cache[i]; int changed = 0; if (ce_stage(ce)) { int mask = 0; mask |= 1 << ce_stage(ce); while (i < entries) { struct cache_entry *nce = index->cache[i]; if (strcmp(ce->name, nce->name)) break; mask |= 1 << ce_stage(nce); i++; } /* * Compensate for loop update */ i--; de = diff_entry_new (DIFF_TYPE_WORKTREE, DIFF_STATUS_UNMERGED, ce->sha1, ce->name); de->unmerge_state = diff_unmerged_state (mask); *results = g_list_prepend (*results, de); continue; } if (ce_uptodate(ce) || ce_skip_worktree(ce)) continue; realpath = g_build_path (PATH_SEPERATOR, worktree, ce->name, NULL); if (g_lstat(realpath, &st) < 0) { if (errno != ENOENT && errno != ENOTDIR) changed = -1; changed = 1; } if (changed) { if (changed < 0) { g_warning ("Faile to stat %s: %s\n", ce->name, strerror(errno)); g_free (realpath); continue; } de = diff_entry_new (DIFF_TYPE_WORKTREE, DIFF_STATUS_DELETED, ce->sha1, ce->name); *results = g_list_prepend (*results, de); g_free (realpath); continue; } if (S_ISDIR (ce->ce_mode)) { if (!S_ISDIR (st.st_mode) || !is_empty_dir (realpath, ignore_func)) { de = diff_entry_new (DIFF_TYPE_WORKTREE, DIFF_STATUS_DIR_DELETED, ce->sha1, ce->name); *results = g_list_prepend (*results, de); } g_free (realpath); continue; } g_free (realpath); changed = ie_match_stat (index, ce, &st, 0); if (!changed) { ce_mark_uptodate (ce); continue; } de = diff_entry_new (DIFF_TYPE_WORKTREE, DIFF_STATUS_MODIFIED, ce->sha1, ce->name); *results = g_list_prepend (*results, de); } }