@matheusbsbs / matheus-bagliano / commits / 2431afbf1b
Fork 0

unpack-trees: move all skip-worktree checks back to unpack_trees()

Earlier, the will_have_skip_worktree() checks are done in various places, which makes it hard to traverse the index tree-alike, required by excluded_from_list(). This patch moves all the checks into two loops in unpack_trees(). Entries in index in this operation can be classified into two groups: ones already in index before unpack_trees() is called and ones added to index after traverse_trees() is called. In both groups, before checking file status on worktree, the future skip-worktree bit must be checked, so that if an entry will be outside worktree, worktree should not be checked. For the first group, the future skip-worktree bit is precomputed and stored as CE_NEW_SKIP_WORKTREE in the first loop before traverse_trees() is called so that *way_merge() function does not need to compute it again. For the second group, because we don't know what entries will be in this group until traverse_trees() finishes, operations that need future skip-worktree check is delayed until CE_NEW_SKIP_WORKTREE is computed in the second loop. CE_ADDED is used to mark entries in the second group. CE_ADDED and CE_NEW_SKIP_WORKTREE are temporary flags used in unpack_trees(). CE_ADDED is only used by add_to_index(), which should not be called while unpack_trees() is running. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Nov 27, 2010 at 13:24 UTC 2431afbf1b3b986245242218b909cd9f055ba65b
2 files changed +74 -9
cache.h
+1
@@ -181,6 +181,7 @@ struct cache_entry {
181 #define CE_CONFLICTED (1 << 23)
182
183 #define CE_UNPACKED (1 << 24)
184 +#define CE_NEW_SKIP_WORKTREE (1 << 25)
185
186 /*
187 * Extended on-disk flags
unpack-trees.c
+73 -9
@@ -258,7 +258,7 @@ static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_opt
258 {
259 int was_skip_worktree = ce_skip_worktree(ce);
260
261 - if (!ce_stage(ce) && will_have_skip_worktree(ce, o))
261 + if (ce->ce_flags & CE_NEW_SKIP_WORKTREE)
262 ce->ce_flags |= CE_SKIP_WORKTREE;
263 else
264 ce->ce_flags &= ~CE_SKIP_WORKTREE;
@@ -333,7 +333,7 @@ static void mark_all_ce_unused(struct index_state *index)
333 {
334 int i;
335 for (i = 0; i < index->cache_nr; i++)
336 - index->cache[i]->ce_flags &= ~CE_UNPACKED;
336 + index->cache[i]->ce_flags &= ~(CE_UNPACKED | CE_ADDED | CE_NEW_SKIP_WORKTREE);
337 }
338
339 static int locate_in_src_index(struct cache_entry *ce,
@@ -834,9 +834,34 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
834 return mask;
835 }
836
837 +/*
838 + * Set/Clear CE_NEW_SKIP_WORKTREE according to $GIT_DIR/info/sparse-checkout
839 + */
840 +static void mark_new_skip_worktree(struct exclude_list *el,
841 + struct index_state *the_index,
842 + int select_flag, int skip_wt_flag)
843 +{
844 + int i;
845 +
846 + for (i = 0; i < the_index->cache_nr; i++) {
847 + struct cache_entry *ce = the_index->cache[i];
848 +
849 + if (select_flag && !(ce->ce_flags & select_flag))
850 + continue;
851 +
852 + if (!ce_stage(ce) && will_have_skip_worktree(ce, o))
853 + ce->ce_flags |= skip_wt_flag;
854 + else
855 + ce->ce_flags &= ~skip_wt_flag;
856 + }
857 +}
858 +
859 +static int verify_absent(struct cache_entry *, enum unpack_trees_error_types, struct unpack_trees_options *);
860 /*
861 * N-way merge "len" trees. Returns 0 on success, -1 on failure to manipulate the
862 * resulting index, -2 on failure to reflect the changes to the work tree.
863 + *
864 + * CE_ADDED, CE_UNPACKED and CE_NEW_SKIP_WORKTREE are used internally
865 */
866 int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options *o)
867 {
@@ -869,6 +894,12 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
894 o->merge_size = len;
895 mark_all_ce_unused(o->src_index);
896
897 + /*
898 + * Sparse checkout loop #1: set NEW_SKIP_WORKTREE on existing entries
899 + */
900 + if (!o->skip_sparse_checkout)
901 + mark_new_skip_worktree(o->el, o->src_index, 0, CE_NEW_SKIP_WORKTREE);
902 +
903 if (!dfc)
904 dfc = xcalloc(1, cache_entry_size(0));
905 o->df_conflict_entry = dfc;
@@ -922,9 +953,29 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
953
954 if (!o->skip_sparse_checkout) {
955 int empty_worktree = 1;
925 - for (i = 0;i < o->result.cache_nr;i++) {
956 +
957 + /*
958 + * Sparse checkout loop #2: set NEW_SKIP_WORKTREE on entries not in loop #1
959 + * If the will have NEW_SKIP_WORKTREE, also set CE_SKIP_WORKTREE
960 + * so apply_sparse_checkout() won't attempt to remove it from worktree
961 + */
962 + mark_new_skip_worktree(o->el, &o->result, CE_ADDED, CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
963 +
964 + for (i = 0; i < o->result.cache_nr; i++) {
965 struct cache_entry *ce = o->result.cache[i];
966
967 + /*
968 + * Entries marked with CE_ADDED in merged_entry() do not have
969 + * verify_absent() check (the check is effectively disabled
970 + * because CE_NEW_SKIP_WORKTREE is set unconditionally).
971 + *
972 + * Do the real check now because we have had
973 + * correct CE_NEW_SKIP_WORKTREE
974 + */
975 + if (ce->ce_flags & CE_ADDED &&
976 + verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))
977 + return -1;
978 +
979 if (apply_sparse_checkout(ce, o)) {
980 ret = -1;
981 goto done;
@@ -1013,7 +1064,7 @@ static int verify_uptodate_1(struct cache_entry *ce,
1064 static int verify_uptodate(struct cache_entry *ce,
1065 struct unpack_trees_options *o)
1066 {
1016 - if (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))
1067 + if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
1068 return 0;
1069 return verify_uptodate_1(ce, o, ERROR_NOT_UPTODATE_FILE);
1070 }
@@ -1200,7 +1251,7 @@ static int verify_absent(struct cache_entry *ce,
1251 enum unpack_trees_error_types error_type,
1252 struct unpack_trees_options *o)
1253 {
1203 - if (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))
1254 + if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
1255 return 0;
1256 return verify_absent_1(ce, error_type, o);
1257 }
@@ -1222,10 +1273,23 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
1273 int update = CE_UPDATE;
1274
1275 if (!old) {
1276 + /*
1277 + * New index entries. In sparse checkout, the following
1278 + * verify_absent() will be delayed until after
1279 + * traverse_trees() finishes in unpack_trees(), then:
1280 + *
1281 + * - CE_NEW_SKIP_WORKTREE will be computed correctly
1282 + * - verify_absent() be called again, this time with
1283 + * correct CE_NEW_SKIP_WORKTREE
1284 + *
1285 + * verify_absent() call here does nothing in sparse
1286 + * checkout (i.e. o->skip_sparse_checkout == 0)
1287 + */
1288 + update |= CE_ADDED;
1289 + merge->ce_flags |= CE_NEW_SKIP_WORKTREE;
1290 +
1291 if (verify_absent(merge, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))
1292 return -1;
1227 - if (!o->skip_sparse_checkout && will_have_skip_worktree(merge, o))
1228 - update |= CE_SKIP_WORKTREE;
1293 invalidate_ce_path(merge, o);
1294 } else if (!(old->ce_flags & CE_CONFLICTED)) {
1295 /*
@@ -1241,8 +1305,8 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
1305 } else {
1306 if (verify_uptodate(old, o))
1307 return -1;
1244 - if (ce_skip_worktree(old))
1245 - update |= CE_SKIP_WORKTREE;
1308 + /* Migrate old flags over */
1309 + update |= old->ce_flags & (CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
1310 invalidate_ce_path(old, o);
1311 }
1312 } else {