void wt_status_collect_changes_index (struct index_state *index, GList **results, SeafRepo *repo) { SeafFSManager *fs_mgr; SeafCommit *head; int pos = 0; DiffEntry *de; fs_mgr = repo->manager->seaf->fs_mgr; head = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, repo->version, repo->head->commit_id); if (!head) { seaf_warning ("Failed to get commit %s.\n", repo->head->commit_id); return; } mark_all_ce_unused (index); /* if repo is initial, we don't need to check index changes */ if (strncmp(EMPTY_SHA1, head->root_id, 40) != 0) { SeafDir *root; /* call diff_index to get status */ root = seaf_fs_manager_get_seafdir (fs_mgr, repo->id, repo->version, head->root_id); if (!root) { seaf_warning ("Failed to get root %s.\n", head->root_id); seaf_commit_unref (head); return; } if (diff_index(repo->id, repo->version, index, root, results) < 0) g_warning("diff index failed\n"); seaf_dir_free (root); seaf_commit_unref (head); return; } seaf_commit_unref (head); while (1) { struct cache_entry *ce = next_cache_entry(index, &pos); if (!ce || ce_stage(ce)) break; ce->ce_flags |= CE_UNPACKED; de = diff_entry_new (DIFF_TYPE_INDEX, DIFF_STATUS_ADDED, ce->sha1, ce->name); *results = g_list_prepend (*results, de); } }
static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, struct name_entry *names, struct traverse_info *info) { struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, }; struct unpack_trees_options *o = info->data; const struct name_entry *p = names; /* Find first entry with a real name (we could use "mask" too) */ while (!p->mode) p++; if (o->debug_unpack) debug_unpack_callback(n, mask, dirmask, names, info); /* Are we supposed to look at the index too? */ if (o->merge) { while (1) { int cmp; struct cache_entry *ce; if (o->diff_index_cached) ce = next_cache_entry(o); else ce = find_cache_entry(info, p); if (!ce) break; cmp = compare_entry(ce, info, p); if (cmp < 0) { if (unpack_index_entry(ce, o) < 0) return unpack_failed(o, NULL); continue; } if (!cmp) { if (ce_stage(ce)) { /* * If we skip unmerged index * entries, we'll skip this * entry *and* the tree * entries associated with it! */ if (o->skip_unmerged) { add_same_unmerged(ce, o); return mask; } } src[0] = ce; } break; } } if (unpack_nondirectories(n, mask, dirmask, src, names, info) < 0) return -1; if (o->merge && src[0]) { if (ce_stage(src[0])) mark_ce_used_same_name(src[0], o); else mark_ce_used(src[0], o); } /* Now handle any directories.. */ if (dirmask) { /* special case: "diff-index --cached" looking at a tree */ if (o->diff_index_cached && n == 1 && dirmask == 1 && S_ISDIR(names->mode)) { int matches; matches = cache_tree_matches_traversal(o->src_index->cache_tree, names, info); /* * Everything under the name matches; skip the * entire hierarchy. diff_index_cached codepath * special cases D/F conflicts in such a way that * it does not do any look-ahead, so this is safe. */ if (matches) { o->cache_bottom += matches; return mask; } } if (traverse_trees_recursive(n, dirmask, mask & ~dirmask, names, info) < 0) return -1; return mask; } return mask; }
/* * N-way merge "len" trees. Returns 0 on success, -1 on failure to manipulate the * resulting index, -2 on failure to reflect the changes to the work tree. * * CE_ADDED, CE_UNPACKED and CE_NEW_SKIP_WORKTREE are used internally */ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options *o) { int i, ret; static struct cache_entry *dfc; struct exclude_list el; if (len > MAX_UNPACK_TREES) die("unpack_trees takes at most %d trees", MAX_UNPACK_TREES); memset(&state, 0, sizeof(state)); state.base_dir = ""; state.force = 1; state.quiet = 1; state.refresh_cache = 1; state.istate = &o->result; memset(&el, 0, sizeof(el)); if (!core_apply_sparse_checkout || !o->update) o->skip_sparse_checkout = 1; if (!o->skip_sparse_checkout) { char *sparse = git_pathdup("info/sparse-checkout"); if (add_excludes_from_file_to_list(sparse, "", 0, &el, 0) < 0) o->skip_sparse_checkout = 1; else o->el = ⪙ free(sparse); } memset(&o->result, 0, sizeof(o->result)); o->result.initialized = 1; o->result.timestamp.sec = o->src_index->timestamp.sec; o->result.timestamp.nsec = o->src_index->timestamp.nsec; o->result.version = o->src_index->version; o->result.split_index = o->src_index->split_index; if (o->result.split_index) o->result.split_index->refcount++; hashcpy(o->result.sha1, o->src_index->sha1); o->merge_size = len; mark_all_ce_unused(o->src_index); /* * Sparse checkout loop #1: set NEW_SKIP_WORKTREE on existing entries */ if (!o->skip_sparse_checkout) mark_new_skip_worktree(o->el, o->src_index, 0, CE_NEW_SKIP_WORKTREE); if (!dfc) dfc = xcalloc(1, cache_entry_size(0)); o->df_conflict_entry = dfc; if (len) { const char *prefix = o->prefix ? o->prefix : ""; struct traverse_info info; setup_traverse_info(&info, prefix); info.fn = unpack_callback; info.data = o; info.show_all_errors = o->show_all_errors; info.pathspec = o->pathspec; if (o->prefix) { /* * Unpack existing index entries that sort before the * prefix the tree is spliced into. Note that o->merge * is always true in this case. */ while (1) { struct cache_entry *ce = next_cache_entry(o); if (!ce) break; if (ce_in_traverse_path(ce, &info)) break; if (unpack_index_entry(ce, o) < 0) goto return_failed; } } if (traverse_trees(len, t, &info) < 0) goto return_failed; } /* Any left-over entries in the index? */ if (o->merge) { while (1) { struct cache_entry *ce = next_cache_entry(o); if (!ce) break; if (unpack_index_entry(ce, o) < 0) goto return_failed; } } mark_all_ce_unused(o->src_index); if (o->trivial_merges_only && o->nontrivial_merge) { ret = unpack_failed(o, "Merge requires file-level merging"); goto done; } if (!o->skip_sparse_checkout) { int empty_worktree = 1; /* * Sparse checkout loop #2: set NEW_SKIP_WORKTREE on entries not in loop #1 * If the will have NEW_SKIP_WORKTREE, also set CE_SKIP_WORKTREE * so apply_sparse_checkout() won't attempt to remove it from worktree */ 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]; /* * Entries marked with CE_ADDED in merged_entry() do not have * verify_absent() check (the check is effectively disabled * because CE_NEW_SKIP_WORKTREE is set unconditionally). * * Do the real check now because we have had * correct CE_NEW_SKIP_WORKTREE */ if (ce->ce_flags & CE_ADDED && verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) { if (!o->show_all_errors) goto return_failed; ret = -1; } if (apply_sparse_checkout(&o->result, ce, o)) { if (!o->show_all_errors) goto return_failed; ret = -1; } 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) { ret = unpack_failed(o, "Sparse checkout leaves no entry on working directory"); goto done; } } o->src_index = NULL; ret = check_updates(o) ? (-2) : 0; if (o->dst_index) { if (!ret) { if (!o->result.cache_tree) o->result.cache_tree = cache_tree(); if (!cache_tree_fully_valid(o->result.cache_tree)) cache_tree_update(&o->result, WRITE_TREE_SILENT | WRITE_TREE_REPAIR); } discard_index(o->dst_index); *o->dst_index = o->result; } else { discard_index(&o->result); } done: clear_exclude_list(&el); 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); if (o->exiting_early) ret = 0; goto done; }