On 5/23/2022 6:48 PM, Junio C Hamano wrote: > Derrick Stolee <derrickstolee@xxxxxxxxxx> writes: > >>> I suspect that is a situation that is not so uncommon. Working >>> inside a narrow cone of a wide tree, performing a merge would >>> hopefully allow many subtrees that are outside of the cones of our >>> interest merged without getting expanded at all (e.g. only the other >>> side touched these subtrees we are not working on, so their version >>> will become the merge result), while changes to some paths in the >>> cone of our interest may result in true conflicts represented as >>> cache entries at higher stages, needing conflict resolution >>> concluded with "git add". Having to expand these subtrees that we >>> managed to merge while still collapsed, only because we have >>> conflicts in some other parts of the tree, feels somewhat sad. >> >> You are correct that conflicts outside of the sparse-checkout cone will >> cause index expansion. That happens during the 'git merge' command, but >> the index will continue to fail to collapse as long as those conflicts >> still exist in the index. >> >> When there are conflicts like this during the merge, then the index >> expansion is not as large of a portion of the command as normal, because >> the conflict resolution also takes some time to compute. The commands >> afterwards do take longer purely because of the expanded index. > > I was imagining a situation more like "tech-writers only have > Documentation/ inside the cone of interest, attempt a pull from > somebody else, have conflicts inside Documentation/, but everything > else could be resolved cleanly without expanding the index". If the > puller's tree is based on the pristine upstream release tag, and the > pullee's tree is based on a slightly newer version of upstream > snapshot, everything that happened outside Documentation/ in their > trees would fast-forward, so such a merge wouldn't have to expand > directories like "builtin/" or "contrib/" in the index and instead > can merge at the tree level, right? > > On the other hand, ... > >> However, this state is also not as common as you might think. If a user >> has a sparse-checkout cone specified, then they are unlikely to change >> files outside of the sparse-checkout cone. They would not be the reason >> that those files have a conflict. The conflicts would exist only if they >> are merging branches that had conflicts outside of the cone. Typically, >> any merge of external changes like this are of the form of "git pull" or >> "git rebase", in which case the conflicts are still "local" to the >> developer's changes. > > ... you seem to be talking about the opposite case (e.g. in the > above paragraph), where a conflict happens outside the cone of > interest of the person who is making a merge. So, I am a bit > puzzled. Hm. We must be getting mixed up with each other. Let me try again from the beginning. When the conflict happens inside of the sparse-checkout cone, then the sparse index is not expanded. This is checked by the test 'sparse-index is not expanded: merge conflict in cone' in t1092. Most merges get to "fast forward" changes that are outside of the sparse-checkout cone because the only interesting changes that could lead to a conflict are those created by the current user (and hence within the sparse-checkout cone). So, the typical case of a tech writer only editing "Documentation/" should only see conflicts within "Documentation/". The case where we would see conflicts outside of the cone include cases where long-lived branches are being merged by someone with a small cone. I can imagine an automated process using an empty sparse-checkout cone to occasionally merge a "deployed" and a "develop" branch, and it gets conflicts when someone ships a hotfix directly to "deployed" without first going through "develop". Any conflict is likely to cause index expansion in this case. Let's re-introduce the patch section we are talking about: + if (pl && !pl->use_cone_patterns) { pl = NULL; + } else { + /* + * We might contract file entries into sparse-directory + * entries, and for that we will need the cache tree to + * be recomputed. + */ + cache_tree_free(&istate->cache_tree); + + /* + * If there is a problem creating the cache tree, then we + * need to expand to a full index since we cannot satisfy + * the current request as a sparse index. + */ + if (cache_tree_update(istate, WRITE_TREE_MISSING_OK)) + pl = NULL; + } If a user is in a conflict state and modifies their sparse-checkout cone, then we will hit this "recompute the cache-tree" state, fail, and cause full index expansion. I think that combination (have a conflict AND modify sparse-checkout cone) is rare enough to not optimize for (yet). Does that make the situation more clear? Thanks, -Stolee