Thread (10 messages) flat view 10 messages, 3 authors, 2016-06-15

Re: problem with cherry-picking a commit which comes before introducing a new submodule

From: Jonathan Nieder <hidden>
Date: 2016-06-15 22:50:22

Yaroslav Halchenko wrote [abbreviated]:
CONFLICT (file/directory): There is a directory with name frontiers/code in todonotloose. Adding frontiers/code as frontiers/code~HEAD
% git ls-files -u
160000 a2b5787 2   frontiers/code
% git diff-tree todonotloose
a00c497
:040000 040000 40427e3 c7ba910 M  poster-hbm2011_neurodebian
% git diff-tree todonotloose^ HEAD
:100644 100644 378e137 c39ced7 M  .gitmodules
:000000 040000 0000000 141dbc1 A  challenge-execpapers
:040000 040000 401fd66 ee190f0 M  frontiers
:040000 040000 26c884a ad3e829 M  sty
Here is what happens.

In the heart of merge_trees:

	/*
	 * If there are D/F conflicts, and the paths currently exist
	 * in the working copy as a file, remove them to make room
	 * for the corresponding directory.  Such paths will later be
	 * processed in process_df_entry() at the end.
	 *
	 * If the corresponding directory ends up being removed by the
	 * merge, then the file will be reinstated at that time;
	 * otherwise, if the file is not supposed to be removed by the
	 * merge, the contents of the file will be placed in another
	 * unique filename.
	 */
	make_room_for_directories_of_df_conflicts(o, entries);

In this case I suppose it is rather a directory/submodule conflict; in
any case, there are no regular files involved, so this logic does not
kick in and the directory is left alone.

Next comes rename handling, which is irrelevant for our purposes.

Next comes the per entry merge.

	/*
	 * Per entry merge.  D/F conflicts are deferred so files
	 * contained in such a directory can be resolved first.
	 */
	for (i = 0; i < entries->nr; i++) {
		const char *path = entries->items[i].string;
		struct stage_data *e = entries->items[i].util;
		if (!e->processed
			&& !process_entry(o, path, e))
			clean = 0;
	}

This is case B: "added in one" (like all directories, the
frontiers/code directory does not have an index entry, while the
submodule does have one).  Since that path is in the current directory
set, it is deferred for later processing.

Next comes the per entry merge for D/F conflicts (process_df_entry in
merge-recursive.c).  This is the case "directory -> (directory,
file)".  Unfortunately the check that the old and new directories
match is not implemented.  Even worse, git checks for a directory
(which was not moved out of the way before) and does not realize that
a submodule might be another reason for a directory in the worktree.
In any event, we get a spurious conflict.

Thanks, that was interesting (no patch yet, alas).
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help