'Git merge on sparse checkout workspace pulls all the other folder as well

I am facing a strange situation.

I did a sparse checkout ( Folder A ) from the repo for specific folder on my local branch. Suppose inside repo there are 3 folders in the root: A, B, and C.

repo: /A /B /C

When I do a git merge from local branch to pull source code from other branch it pull's the content from all the folders (A, B, and C) to my local. I was expecting only contents from A will be merged since sparse checkout is "ON".

Can you let me know how I can merge changes from other branch only contained in folder A.



Solution 1:[1]

It should be possible, but only with Git 2.36 (Q2 2022): "git read-tree"(man) has been made to be aware of the sparse-index feature.

See commit f27c170, commit ab81047, commit 7497039, commit 2c66a7c, commit 14bf38c, commit cc89331, commit 2c521b0, commit 287fd17 (01 Mar 2022) by Victoria Dye (vdye).
(Merged by Junio C Hamano -- gitster -- in commit 190f9bf, 16 Mar 2022)

read-tree: make two-way merge sparse-aware

Signed-off-by: Victoria Dye

Enable two-way merge with 'git read-tree'(man) without expanding the sparse index.
When in a sparse index, a two-way merge will trivially succeed as long as there are not changes to the same sparse directory in multiple trees (i.e., sparse directory-level "edit-edit" conflicts).
If there are such conflicts, the merge will fail despite the possibility that individual files could merge cleanly.

In order to resolve these "edit-edit" conflicts, "conflicted" sparse directories are - rather than rejected - merged by traversing their associated trees by OID.
For each child of the sparse directory:

  1. Files are merged as normal (see Documentation/git-read-tree.txt for details).
  2. Subdirectories are treated as sparse directories and merged in 'twoway_merge'. If there are no conflicts, they are merged according to the rules in Documentation/git-read-tree.txt; otherwise, the subdirectory is recursively traversed and merged.

This process allows sparse directories to be individually merged at the necessary depth without expanding a full index.


Regarding the comment:

The easier way I can think of is to git stash your changes.

Make sure to use Git 2.37 (Q3 2022): it teaches "git stash"(man) to work better with sparse index entries.

See commit 0f329b9, commit 874cf2a, commit 491df5f, commit cfde4cd, commit 3a58792, commit eae9370 (10 May 2022) by Victoria Dye (vdye).
(Merged by Junio C Hamano -- gitster -- in commit 5a9253c, 20 May 2022)

stash: integrate with sparse index

Signed-off-by: Victoria Dye

Enable sparse index in 'git stash'(man) by disabling 'command_requires_full_index'.

With sparse index enabled, some subcommands of 'stash' work without expanding the index, e.g., 'git stash', 'git stash list'(man), 'git stash drop'(man), etc.
Others ensure the index is expanded either directly (as in the case of 'git stash [pop|apply]'', where the call to 'merge_recursive_generic()' in 'do_apply_stash()' triggers the expansion), or in a command called internally by stash (e.g., 'git update-index'(man) in 'git stash -u'(man)).
So, in addition to enabling sparse index, add tests to 't1092' demonstrating which variants of 'git stash' expand the index, and which do not.

Finally, add the option to skip writing 'untracked.txt' in 'ensure_not_expanded', and use that option to successfully apply stashed untracked files without a conflict in 'untracked.txt'.

And:

stash: apply stash using 'merge_ort_nonrecursive()'

Signed-off-by: Victoria Dye

Update 'stash' to use 'merge_ort_nonrecursive()' to apply a stash to the current working tree.
When 'git stash apply'(man) was converted from its shell script implementation to a builtin in 8a0fc8d ("stash: convert apply to builtin", 2019-02-25, Git v2.22.0-rc0 -- merge listed in batch #6), 'merge_recursive_generic()' was used to merge a stash into the working tree as part of 'git stash'(man) (apply|pop)'.
However, with the single merge base used in 'do_apply_stash()', the commit wrapping done by 'merge_recursive_generic()' is not only unnecessary, but misleading (the real merge base is labeled "constructed merge base").
Therefore, a non-recursive merge of the working tree, stashed tree, and stash base tree is more appropriate.

There are two options for a non-recursive merge-then-update-worktree function: 'merge_trees()' and 'merge_ort_nonrecursive()'.
Use 'merge_ort_nonrecursive()' to align with the default merge strategy used by 'git merge'(man) (6a5fb96 ("Change default merge backend from recursive to ort", 2021-08-04, Git v2.34.0-rc0 -- merge listed in batch #2)) and, because merge-ort does not operate in-place on the index, avoid unnecessary index expansion.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1