git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 36/37] merge-recursive: Make room for directories in D/F conflicts

From
Elijah Newren <newren@gmail.com>
Date
Sep 20, 2010, 08:29 UTC
Message-ID
<1284971350-30590-37-git-send-email-newren@gmail.com>
In-Reply-To
<1284971350-30590-1-git-send-email-newren@gmail.com>

When there are unmerged entries present, make sure to check for D/F conflicts first and remove any files present in HEAD that would be in the way of creating files below the correspondingly named directory. Such files will be processed again at the end of the merge in process_df_entry(); at that time we will be able to tell if we need to and can reinstate the file, whether we need to place its contents in a different file due to the directory still being present, etc.

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 merge-recursive.c   |   58 +++++++++++++++++++++++++++++++++++++++++++++++++++
 t/t6020-merge-df.sh |    2 +-
 2 files changed, 59 insertions(+), 1 deletions(-)
diff --git a/merge-recursive.c b/merge-recursive.c
index 05da47c..821bed8 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -347,6 +347,63 @@ static struct string_list *get_unmerged(void)
 	return unmerged;
 }
 
+static void make_room_for_directories_of_df_conflicts(struct merge_options *o,
+						      struct string_list *entries)
+{
+	/* If there are D/F conflicts, and the paths currently exist
+	 * in the working copy as a file, we want to 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.
+	 *
+	 * NOTE: This function relies on the fact that entries for a
+	 * D/F conflict will appear adjacent in the index, with the
+	 * entries for the file appearing before entries for paths
+	 * below the corresponding directory.
+	 */
+	const char *last_file = NULL;
+	int last_len;
+	struct stage_data *last_e;
+	int i;
+
+	for (i = 0; i < entries->nr; i++) {
+		const char *path = entries->items[i].string;
+		int len = strlen(path);
+		struct stage_data *e = entries->items[i].util;
+
+		/*
+		 * Check if last_file & path correspond to a D/F conflict;
+		 * i.e. whether path is last_file+'/'+<something>.
+		 * If so, remove last_file to make room for path and friends.
+		 */
+		if (last_file &&
+		    len > last_len &&
+		    memcmp(path, last_file, last_len) == 0 &&
+		    path[last_len] == '/') {
+			output(o, 3, "Removing %s to make room for subdirectory; may re-add later.", last_file);
+			unlink(last_file);
+		}
+
+		/*
+		 * Determine whether path could exist as a file in the
+		 * working directory as a possible D/F conflict.  This
+		 * will only occur when it exists in stage 2 as a
+		 * file.
+		 */
+		if (S_ISREG(e->stages[2].mode) || S_ISLNK(e->stages[2].mode)) {
+			last_file = path;
+			last_len = len;
+			last_e = e;
+		} else {
+			last_file = NULL;
+		}
+	}
+}
+
 struct rename
 {
 	struct diff_filepair *pair;
@@ -1488,6 +1545,7 @@ int merge_trees(struct merge_options *o,
 		get_files_dirs(o, merge);
 
 		entries = get_unmerged();
+		make_room_for_directories_of_df_conflicts(o, entries);
 		re_head  = get_renames(o, head, common, head, merge, entries);
 		re_merge = get_renames(o, merge, common, head, merge, entries);
 		clean = process_renames(o, re_head, re_merge);
diff --git a/t/t6020-merge-df.sh b/t/t6020-merge-df.sh
index 7b1ce82..b129f1d 100755
--- a/t/t6020-merge-df.sh
+++ b/t/t6020-merge-df.sh
@@ -83,7 +83,7 @@ test_expect_success 'modify/delete + directory/file conflict' '
 	test -f letters~modify
 '
 
-test_expect_failure 'modify/delete + directory/file conflict; other way' '
+test_expect_success 'modify/delete + directory/file conflict; other way' '
 	git reset --hard &&
 	git clean -f &&
 	git checkout modify^0 &&
-- 
1.7.3.271.g16009
Previous: Elijah NewrenNext: Johannes Sixt
Message 43 of 46 in “Audit and fix corner case bugs in recursive merge”
  1. 00/37 Audit and fix corner case bugs in recursive mergeElijah Newren, Sep 20, 2010
  2. 01/37 t3030: Add a testcase for resolvable rename/add conflict with symlinksElijah Newren, Sep 20, 2010
  3. Johannes SixtSep 20, 2010
  4. Jakub NarebskiSep 20, 2010
  5. 02/37 merge-recursive: Restructure showing how to chain more process_* functionsElijah Newren, Sep 20, 2010
  6. 03/37 t6032: Add a test checking for excessive output from mergeElijah Newren, Sep 20, 2010
  7. 04/37 t6022: Add test combinations of {content conflict?, D/F conflict remains?}Elijah Newren, Sep 20, 2010
  8. 05/37 t6022: Add tests for reversing order of merges when D/F conflicts presentElijah Newren, Sep 20, 2010
  9. 06/37 t6022: Add tests with both rename source & dest involved in D/F conflictsElijah Newren, Sep 20, 2010
  10. 07/37 t6022: Add paired rename+D/F conflict: (two/file, one/file) -> (one, two)Elijah Newren, Sep 20, 2010
  11. 08/37 t6022: Add tests for rename/rename combined with D/F conflictsElijah Newren, Sep 20, 2010
  12. 09/37 t6020: Modernize style a bitElijah Newren, Sep 20, 2010
  13. Johannes SixtSep 20, 2010
  14. Elijah NewrenSep 20, 2010
  15. Junio C HamanoSep 22, 2010
  16. Elijah NewrenSep 22, 2010
  17. 10/37 t6020: Add a testcase for modify/delete + directory/file conflictElijah Newren, Sep 20, 2010
  18. 11/37 t6036: Test index and worktree state, not just that merge failsElijah Newren, Sep 20, 2010
  19. 12/37 t6036: Add a second testcase similar to the first but with content changesElijah Newren, Sep 20, 2010
  20. 13/37 t6036: Add testcase for undetected conflictElijah Newren, Sep 20, 2010
  21. 14/37 merge-recursive: Small code clarification -- variable name and commentsElijah Newren, Sep 20, 2010
  22. 15/37 merge-recursive: Rename conflict_rename_rename*() for clarityElijah Newren, Sep 20, 2010
  23. 16/37 merge-recursive: Nuke rename/directory conflict detectionElijah Newren, Sep 20, 2010
  24. 17/37 merge-recursive: Move rename/delete handling into dedicated functionElijah Newren, Sep 20, 2010
  25. 18/37 merge-recursive: Move delete/modify handling into dedicated functionElijah Newren, Sep 20, 2010
  26. 19/37 merge-recursive: Move process_entry's content merging into a functionElijah Newren, Sep 20, 2010
  27. 20/37 merge-recursive: New data structures for deferring of D/F conflictsElijah Newren, Sep 20, 2010
  28. 21/37 merge-recursive: New function to assist resolving renames in-core onlyElijah Newren, Sep 20, 2010
  29. 22/37 merge-recursive: Have process_entry() skip D/F or rename entriesElijah Newren, Sep 20, 2010
  30. 23/37 merge-recursive: Structure process_df_entry() to handle more casesElijah Newren, Sep 20, 2010
  31. 24/37 merge-recursive: Update conflict_rename_rename_1to2() call signatureElijah Newren, Sep 20, 2010
  32. 25/37 merge-recursive: Update merge_content() call signatureElijah Newren, Sep 20, 2010
  33. 26/37 merge-recursive: Avoid doubly merging rename/add conflict contentsElijah Newren, Sep 20, 2010
  34. 27/37 merge-recursive: Move handling of double rename of one file to twoElijah Newren, Sep 20, 2010
  35. 28/37 merge-recursive: Move handling of double rename of one file to other fileElijah Newren, Sep 20, 2010
  36. 29/37 merge-recursive: Delay handling of rename/delete conflictsElijah Newren, Sep 20, 2010
  37. 30/37 merge-recursive: Delay content merging for renamesElijah Newren, Sep 20, 2010
  38. 31/37 merge-recursive: Delay modify/delete conflicts if D/F conflict presentElijah Newren, Sep 20, 2010
  39. 32/37 conflict_rename_delete(): Check whether D/F conflicts are still presentElijah Newren, Sep 20, 2010
  40. 33/37 conflict_rename_rename_1to2(): Fix checks for presence of D/F conflictsElijah Newren, Sep 20, 2010
  41. 34/37 merge_content(): Check whether D/F conflicts are still presentElijah Newren, Sep 20, 2010
  42. 35/37 handle_delete_modify(): Check whether D/F conflicts are still presentElijah Newren, Sep 20, 2010
  43. 36/37 merge-recursive: Make room for directories in D/F conflictsElijah Newren, Sep 20, 2010
  44. Johannes SixtSep 20, 2010
  45. Elijah NewrenSep 20, 2010
  46. 37/37 merge-recursive: Remove redundant path clearing for D/F conflictsElijah Newren, Sep 20, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.