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

[PATCH 3/8] merge-ort: record the reason that we want a rename for a directory

From
Elijah Newren via GitGitGadget <gitgitgadget@gmail.com>
Date
Mar 13, 2021, 22:22 UTC
Message-ID
<05850cb49823ea9c6d6c7cfd3b4adbbc1c47abc6.1615674128.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.853.git.1615674128.gitgitgadget@gmail.com>
From: Elijah Newren <newren@gmail.com>

When one side of history renames a directory, and the other side of history added files to the old directory, directory rename detection is used to warn about the location of the added files so the user can move them to the old directory or keep them with the new one.

This sets up three different types of directories:
  * directories that had new files added to them
  * directories underneath a directory that had new files added to them
  * directories where no new files were added to it or any leading path

Save this information in dirs_removed; the next several commits will make use of this information.

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 diffcore-rename.c |  2 +-
 diffcore.h        |  7 +++++++
 merge-ort.c       | 41 ++++++++++++++++++++++++++++++++++++++---
 3 files changed, 46 insertions(+), 4 deletions(-)
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 6487825317ff..fafec66b29e9 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -667,7 +667,7 @@ static void cleanup_dir_rename_info(struct dir_rename_info *info,
 		const char *source_dir = entry->key;
 		struct strintmap *counts = entry->value;
 
-		if (!strintmap_contains(dirs_removed, source_dir)) {
+		if (!strintmap_get(dirs_removed, source_dir)) {
 			string_list_append(&to_remove, source_dir);
 			strintmap_clear(counts);
 			continue;
diff --git a/diffcore.h b/diffcore.h
index 4f168b385fde..d5a497b7a162 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -161,6 +161,13 @@ struct diff_filepair *diff_queue(struct diff_queue_struct *,
 				 struct diff_filespec *);
 void diff_q(struct diff_queue_struct *, struct diff_filepair *);
 
+/* dir_rename_relevance: the reason we want rename information for a dir */
+enum dir_rename_relevance {
+	NOT_RELEVANT = 0,
+	RELEVANT_FOR_ANCESTOR = 1,
+	RELEVANT_FOR_SELF = 2
+};
+
 void partial_clear_dir_rename_count(struct strmap *dir_rename_count);
 
 void diffcore_break(struct repository *, int);
diff --git a/merge-ort.c b/merge-ort.c
index 6fa670396ce4..e2606c73ad88 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -73,6 +73,10 @@ struct rename_info {
 
 	/*
 	 * dirs_removed: directories removed on a given side of history.
+	 *
+	 * The keys of dirs_removed[side] are the directories that were removed
+	 * on the given side of history.  The value of the strintmap for each
+	 * directory is a value from enum dir_rename_relevance.
 	 */
 	struct strintmap dirs_removed[3];
 
@@ -729,10 +733,41 @@ static void collect_rename_info(struct merge_options *opt,
 	if (dirmask == 1 || dirmask == 3 || dirmask == 5) {
 		/* absent_mask = 0x07 - dirmask; sides = absent_mask/2 */
 		unsigned sides = (0x07 - dirmask)/2;
+		unsigned relevance = (renames->dir_rename_mask == 0x07) ?
+					RELEVANT_FOR_ANCESTOR : NOT_RELEVANT;
+		/*
+		 * Record relevance of this directory.  However, note that
+		 * when collect_merge_info_callback() recurses into this
+		 * directory and calls collect_rename_info() on paths
+		 * within that directory, if we find a path that was added
+		 * to this directory on the other side of history, we will
+		 * upgrade this value to RELEVANT_FOR_SELF; see below.
+		 */
 		if (sides & 1)
-			strintmap_set(&renames->dirs_removed[1], fullname, 1);
+			strintmap_set(&renames->dirs_removed[1], fullname,
+				      relevance);
 		if (sides & 2)
-			strintmap_set(&renames->dirs_removed[2], fullname, 1);
+			strintmap_set(&renames->dirs_removed[2], fullname,
+				      relevance);
+	}
+
+	/*
+	 * Here's the block that potentially upgrades to RELEVANT_FOR_SELF.
+	 * When we run across a file added to a directory.  In such a case,
+	 * find the directory of the file and upgrade its relevance.
+	 */
+	if (renames->dir_rename_mask == 0x07 &&
+	    (filemask == 2 || filemask == 4)) {
+		/*
+		 * Need directory rename for parent directory on other side
+		 * of history from added file.  Thus
+		 *    side = (~filemask & 0x06) >> 1
+		 * or
+		 *    side = 3 - (filemask/2).
+		 */
+		unsigned side = 3 - (filemask >> 1);
+		strintmap_set(&renames->dirs_removed[side], dirname,
+			      RELEVANT_FOR_SELF);
 	}
 
 	if (filemask == 0 || filemask == 7)
@@ -3446,7 +3481,7 @@ static void merge_start(struct merge_options *opt, struct merge_result *result)
 	renames = &opt->priv->renames;
 	for (i = MERGE_SIDE1; i <= MERGE_SIDE2; i++) {
 		strintmap_init_with_options(&renames->dirs_removed[i],
-					    0, NULL, 0);
+					    NOT_RELEVANT, NULL, 0);
 		strmap_init_with_options(&renames->dir_rename_count[i],
 					 NULL, 1);
 		strmap_init_with_options(&renames->dir_renames[i],
-- 
gitgitgadget
Previous: Elijah Newren via GitGitGadgetNext: Derrick Stolee
Message 7 of 14 in “Optimization batch 10: avoid detecting even more irrelevant renames”
  1. 0/8 Optimization batch 10: avoid detecting even more irrelevant renamesElijah Newren via GitGitGadget, Mar 13, 2021
  2. 6/8 diffcore-rename: add computation of number of unknown renamesElijah Newren via GitGitGadget, Mar 13, 2021
  3. 4/8 diffcore-rename: only compute dir_rename_count for relevant directoriesElijah Newren via GitGitGadget, Mar 13, 2021
  4. 1/8 diffcore-rename: take advantage of "majority rules" to skip more renamesElijah Newren via GitGitGadget, Mar 13, 2021
  5. 5/8 diffcore-rename: check if we have enough renames for directories early onElijah Newren via GitGitGadget, Mar 13, 2021
  6. 2/8 merge-ort, diffcore-rename: tweak dirs_removed and relevant_source typeElijah Newren via GitGitGadget, Mar 13, 2021
  7. 3/8 merge-ort: record the reason that we want a rename for a directoryElijah Newren via GitGitGadget, Mar 13, 2021
  8. Derrick StoleeMar 15, 2021
  9. Elijah NewrenMar 15, 2021
  10. Junio C HamanoMar 28, 2021
  11. 8/8 diffcore-rename: determine which relevant_sources are no longer relevantElijah Newren via GitGitGadget, Mar 13, 2021
  12. 7/8 merge-ort: record the reason that we want a rename for a fileElijah Newren via GitGitGadget, Mar 13, 2021
  13. Derrick StoleeMar 15, 2021
  14. Elijah NewrenMar 15, 2021

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.