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

[PATCH v4 3/4] Allow hiding renames of individual files involved in a directory rename.

From
Yann Dirson <ydirson@altern.org>
Date
Oct 3, 2010, 20:42 UTC
Message-ID
<1286138529-6780-4-git-send-email-ydirson@altern.org>
In-Reply-To
<1286138529-6780-3-git-send-email-ydirson@altern.org>
From: Yann Dirson <ydirson@free.fr>

Once --detect-dir-renames has identified groups of bulk-moved files, and then the --hide-dir-rename-details flag hides those of the individual renames which carry no other information (further name change, or content changes).

This makes it much easier to a human reader to spot content changes
in a commit that also moves a whole subtree.
---
 diff.c            |    7 +++++
 diff.h            |    3 ++
 diffcore-rename.c |   67 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 diffcore.h        |    1 +
 4 files changed, 75 insertions(+), 3 deletions(-)
diff --git a/diff.c b/diff.c
index 47ef7ea..2731c33 100644
--- a/diff.c
+++ b/diff.c
@@ -3193,6 +3193,13 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
 		if (!options->detect_rename)
 			options->detect_rename = DIFF_DETECT_RENAME;
 	}
+	else if (!strcmp(arg, "--hide-dir-rename-details")) {
+		DIFF_OPT_SET(options, HIDE_DIR_RENAME_DETAILS);
+		if (!DIFF_OPT_TST(options, DETECT_DIR_RENAMES))
+			DIFF_OPT_SET(options, DETECT_DIR_RENAMES);
+		if (!options->detect_rename)
+			options->detect_rename = DIFF_DETECT_RENAME;
+	}
 	else if (!strcmp(arg, "--follow"))
 		DIFF_OPT_SET(options, FOLLOW_RENAMES);
 	else if (!strcmp(arg, "--color"))
diff --git a/diff.h b/diff.h
index 40c548d..ae1e2e7 100644
--- a/diff.h
+++ b/diff.h
@@ -79,6 +79,7 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data)
 #define DIFF_OPT_IGNORE_DIRTY_SUBMODULES (1 << 26)
 #define DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG (1 << 27)
 #define DIFF_OPT_DETECT_DIR_RENAMES  (1 << 28)
+#define DIFF_OPT_HIDE_DIR_RENAME_DETAILS (1 << 29)
 
 #define DIFF_OPT_TST(opts, flag)    ((opts)->flags & DIFF_OPT_##flag)
 #define DIFF_OPT_SET(opts, flag)    ((opts)->flags |= DIFF_OPT_##flag)
@@ -268,6 +269,8 @@ extern void diffcore_fix_diff_index(struct diff_options *);
 "                try unchanged files as candidate for copy detection.\n" \
 "  --detect-dir-renames\n" \
 "                detect wholesale directory renames.\n" \
+"  --hide-dir-rename-details\n" \
+"                hide renames of individual files in a directory rename.\n" \
 "  -l<n>         limit rename attempts up to <n> paths.\n" \
 "  -O<file>      reorder diffs according to the <file>.\n" \
 "  -S<string>    find filepair whose only one side contains the string.\n" \
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 06a8b6c..89e0b53 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -452,6 +452,34 @@ struct diff_dir_rename {
 	struct diff_dir_rename* next;
 };
 
+/*
+ * Marks as such file_rename if it is made uninteresting by dir_rename.
+ * Returns -1 if the file_rename is outside of the range in which given
+ * renames concerned by dir_rename are to be found (ie. end of loop),
+ * 0 otherwise.
+ */
+static int maybe_mark_uninteresting(struct diff_rename_dst* file_rename,
+				    struct diff_dir_rename* dir_rename,
+				    int one_len, int two_len)
+{
+	if (!file_rename->pair) /* file add */
+		return 0;
+	if (strncmp(file_rename->two->path,
+		    dir_rename->two->path, two_len))
+		return -1;
+	if (strncmp(file_rename->pair->one->path,
+		    dir_rename->one->path, one_len) ||
+	    !basename_same(file_rename->pair->one, file_rename->two) ||
+	    file_rename->pair->score != MAX_SCORE)
+		return 0;
+
+	file_rename->pair->uninteresting_rename = 1;
+	fprintf (stderr, "[DBG] %s* -> %s* makes %s -> %s uninteresting\n",
+		dir_rename->one->path, dir_rename->two->path,
+		file_rename->pair->one->path, file_rename->two->path);
+	return 0;
+}
+
 // FIXME: prevent possible overflow
 /*
  * Copy dirname of src into dst, suitable to append a filename without
@@ -497,7 +525,7 @@ static const char* copy_dirname(char* dst, const char* src)
  * FIXME: ideas to consider under-threshold moves as part of bulk move ?
  */
 static struct diff_dir_rename* factorization_candidates = NULL;
-static void diffcore_factorize_renames(void)
+static void diffcore_factorize_renames(int opt_hide_renames)
 {
 	char one_parent_path[PATH_MAX], two_parent_path[PATH_MAX];
 	int i;
@@ -616,6 +644,38 @@ static void diffcore_factorize_renames(void)
 		/* all checks ok, we keep that entry */
 	}
 
+	if (opt_hide_renames) {
+		// flag as "uninteresting" those candidates hidden by dir move
+		struct diff_dir_rename* candidate;
+		for (candidate=factorization_candidates;
+		     candidate; candidate = candidate->next) {
+			int two_idx, i, one_len, two_len;
+			if (candidate->discarded)
+				continue;
+
+			// bisect to any entry within candidate dst dir
+			struct diff_rename_dst* two_sample =
+				locate_rename_dst_dir(candidate->two);
+			if (!two_sample) {
+				die ("PANIC: %s candidate of rename not in target tree (from %s)\n",
+				     candidate->two->path, candidate->one->path);
+			}
+			two_idx = two_sample - rename_dst;
+
+			// now remove extraneous 100% files inside.
+			one_len = strlen(candidate->one->path);
+			two_len = strlen(candidate->two->path);
+			for (i = two_idx; i < rename_dst_nr; i++)
+				if (maybe_mark_uninteresting (rename_dst+i, candidate,
+							      one_len, two_len) < 0)
+					break;
+			for (i = two_idx-1; i >= 0; i--)
+				if (maybe_mark_uninteresting (rename_dst+i, candidate,
+							      one_len, two_len) < 0)
+					break;
+		}
+	}
+
 	return;
 }
 
@@ -788,7 +848,7 @@ void diffcore_rename(struct diff_options *options)
 
 	/* Now possibly factorize those renames and copies. */
 	if (DIFF_OPT_TST(options, DETECT_DIR_RENAMES))
-		diffcore_factorize_renames();
+		diffcore_factorize_renames(DIFF_OPT_TST(options, HIDE_DIR_RENAME_DETAILS));
 
 	DIFF_QUEUE_CLEAR(&outq);
 
@@ -821,7 +881,8 @@ void diffcore_rename(struct diff_options *options)
 			struct diff_rename_dst *dst =
 				locate_rename_dst(p->two, 0);
 			if (dst && dst->pair) {
-				diff_q(&outq, dst->pair);
+				if (!dst->pair->uninteresting_rename)
+					diff_q(&outq, dst->pair);
 				pair_to_free = p;
 			}
 			else
diff --git a/diffcore.h b/diffcore.h
index b8f1fde..beee596 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -69,6 +69,7 @@ struct diff_filepair {
 	unsigned broken_pair : 1;
 	unsigned renamed_pair : 1;
 	unsigned is_unmerged : 1;
+	unsigned uninteresting_rename : 1;
 };
 #define DIFF_PAIR_UNMERGED(p) ((p)->is_unmerged)
 
-- 
1.7.2.3
Previous: Yann DirsonNext: Yann Dirson
Message 4 of 25 in “Detection of directory renames”
  1. 0/4 Detection of directory renamesYann Dirson, Oct 3, 2010
  2. 1/4 Introduce wholesame directory move detection in diffcore.Yann Dirson, Oct 3, 2010
  3. 2/4 Add testcases for the --detect-dir-renames diffcore flag.Yann Dirson, Oct 3, 2010
  4. 3/4 Allow hiding renames of individual files involved in a directory rename.Yann Dirson, Oct 3, 2010
  5. 4/4 Add testcases for the --hide-dir-rename-details diffcore flag.Yann Dirson, Oct 3, 2010
  6. Sverre RabbelierOct 3, 2010
  7. Sverre RabbelierOct 3, 2010
  8. Junio C HamanoOct 3, 2010
  9. Sverre RabbelierOct 4, 2010
  10. Yann DirsonOct 4, 2010
  11. Ævar Arnfjörð BjarmasonOct 4, 2010
  12. Yann DirsonOct 4, 2010
  13. Jonathan NiederOct 4, 2010
  14. Yann DirsonOct 4, 2010
  15. Jonathan NiederOct 4, 2010
  16. Andreas EricssonOct 5, 2010
  17. Ævar Arnfjörð BjarmasonOct 4, 2010
  18. Yann DirsonOct 4, 2010
  19. Jonathan NiederOct 4, 2010
  20. Yann DirsonOct 4, 2010
  21. Jonathan NiederOct 5, 2010
  22. Yann DirsonOct 6, 2010
  23. Jonathan NiederOct 4, 2010
  24. Jonathan NiederOct 5, 2010
  25. Yann DirsonOct 6, 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.