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

[PATCH 2/3] Introducing software archaeologist's tool "pickaxe".

From
Junio C Hamano <junkio@cox.net>
Date
May 21, 2005, 09:40 UTC
Message-ID
<7voeb4kjda.fsf_-_@assigned-by-dhcp.cox.net>
In-Reply-To
<7vzmuokjhg.fsf@assigned-by-dhcp.cox.net>

This steals the "pickaxe" feature from JIT and make it available to the bare Plumbing layer. From the command line, the user gives a string he is intersted in.

Using the diff-core infrastructure previously introduced, it filters the differences to limit the output only to the diffs between <src> and <dst> where the string appears only in one but not in the other. For example:

 $ ./git-rev-list HEAD | ./git-diff-tree -Sdiff-tree-helper --stdin -M
would show the diffs that touch the string "diff-tree-helper".

In real software-archaeologist application, you would typically look for a few to several lines of code and see where that code came from.

The "pickaxe" module runs after "rename/copy detection" module, so it even crosses the file rename boundary, as the above example demonstrates.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

Documentation/git-diff-cache.txt | 6 +++- Documentation/git-diff-files.txt | 6 +++- Documentation/git-diff-helper.txt | 6 +++- Documentation/git-diff-tree.txt | 5 ++- Makefile | 3 +- diff-cache.c | 11 +++++-- diff-files.c | 9 ++++-- diff-helper.c | 10 ++++-- diff-tree.c | 15 ++++++---- diff.c | 23 +++++++++------ diff.h | 1 diffcore-pickaxe.c | 56 ++++++++++++++++++++++++++++++++++++++ diffcore-rename.c | 29 +++++++------------ diffcore.h | 11 ++++--- 14 files changed, 140 insertions(+), 51 deletions(-) new file (100644): diffcore-pickaxe.c

diff --git a/Documentation/git-diff-cache.txt b/Documentation/git-diff-cache.txt
--- a/Documentation/git-diff-cache.txt
+++ b/Documentation/git-diff-cache.txt
@@ -9,7 +9,7 @@ git-diff-cache - Compares content and mo
 
 SYNOPSIS
 --------
-'git-diff-cache' [-p] [-r] [-z] [-m] [-M] [-R] [-C] [--cached] <tree-ish>
+'git-diff-cache' [-p] [-r] [-z] [-m] [-M] [-R] [-C] [-S<string>] [--cached] <tree-ish>
 
 DESCRIPTION
 -----------
@@ -39,6 +39,10 @@ OPTIONS
 -C::
 	Detect copies as well as renames; implies -p.
 
+-S<string>::
+	Look for differences that contains the change in <string>.
+
+
 -R::
 	Output diff in reverse.
 
diff --git a/Documentation/git-diff-files.txt b/Documentation/git-diff-files.txt
--- a/Documentation/git-diff-files.txt
+++ b/Documentation/git-diff-files.txt
@@ -9,7 +9,7 @@ git-diff-files - Compares files in the w
 
 SYNOPSIS
 --------
-'git-diff-files' [-p] [-q] [-r] [-z] [-M] [-C] [-R] [<pattern>...]
+'git-diff-files' [-p] [-q] [-r] [-z] [-M] [-C] [-R] [-S<string>] [<pattern>...]
 
 DESCRIPTION
 -----------
@@ -35,6 +35,10 @@ OPTIONS
 -C::
 	Detect copies as well as renames; implies -p.
 
+-S<string>::
+	Look for differences that contains the change in <string>.
+
+
 -r::
 	This flag does not mean anything.  It is there only to match
 	git-diff-tree.  Unlike git-diff-tree, git-diff-files always looks
diff --git a/Documentation/git-diff-helper.txt b/Documentation/git-diff-helper.txt
--- a/Documentation/git-diff-helper.txt
+++ b/Documentation/git-diff-helper.txt
@@ -9,7 +9,7 @@ git-diff-helper - Generates patch format
 
 SYNOPSIS
 --------
-'git-diff-helper' [-z] [-R] [-M] [-C]
+'git-diff-helper' [-z] [-R] [-M] [-C] [-S<string>]
 
 DESCRIPTION
 -----------
@@ -37,6 +37,10 @@ OPTIONS
 -C::
 	Detect copies as well as renames.
 
+-S<string>::
+	Look for differences that contains the change in <string>.
+
+
 See Also
 --------
 The section on generating patches in link:git-diff-cache.html[git-diff-cache]
diff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.txt
--- a/Documentation/git-diff-tree.txt
+++ b/Documentation/git-diff-tree.txt
@@ -9,7 +9,7 @@ git-diff-tree - Compares the content and
 
 SYNOPSIS
 --------
-'git-diff-tree' [-p] [-r] [-z] [--stdin] [-M] [-R] [-C] [-m] [-s] [-v] <tree-ish> <tree-ish> [<pattern>]\*
+'git-diff-tree' [-p] [-r] [-z] [--stdin] [-M] [-R] [-C] [-S<string>] [-m] [-s] [-v] <tree-ish> <tree-ish> [<pattern>]\*
 
 DESCRIPTION
 -----------
@@ -43,6 +43,9 @@ OPTIONS
 -R::
 	Output diff in reverse.
 
+-S<string>::
+	Look for differences that contains the change in <string>.
+
 -r::
 	recurse
 
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -45,7 +45,7 @@ LIB_H += strbuf.h
 LIB_OBJS += strbuf.o
 
 LIB_H += diff.h
-LIB_OBJS += diff.o diffcore-rename.o
+LIB_OBJS += diff.o diffcore-rename.o diffcore-pickaxe.o
 
 LIB_OBJS += gitenv.o
 
@@ -125,6 +125,7 @@ strbuf.o: $(LIB_H)
 gitenv.o: $(LIB_H)
 diff.o: $(LIB_H)
 diffcore-rename.o : $(LIB_H)
+diffcore-pickaxe.o : $(LIB_H)
 
 test: all
 	make -C t/ all
diff --git a/diff-cache.c b/diff-cache.c
--- a/diff-cache.c
+++ b/diff-cache.c
@@ -8,6 +8,7 @@ static int line_termination = '\n';
 static int detect_rename = 0;
 static int reverse_diff = 0;
 static int diff_score_opt = 0;
+static char *pickaxe = 0;
 
 /* A file entry went away or appeared */
 static void show_file(const char *prefix, struct cache_entry *ce, unsigned char *sha1, unsigned int mode)
@@ -153,7 +154,7 @@ static void mark_merge_entries(void)
 }
 
 static char *diff_cache_usage =
-"git-diff-cache [-p] [-r] [-z] [-m] [-M] [-C] [-R] [--cached] <tree-ish>";
+"git-diff-cache [-p] [-r] [-z] [-m] [-M] [-C] [-R] [-S<string>] [--cached] <tree-ish>";
 
 int main(int argc, char **argv)
 {
@@ -194,6 +195,10 @@ int main(int argc, char **argv)
 			reverse_diff = 1;
 			continue;
 		}
+		if (!strcmp(arg, "-S")) {
+			pickaxe = arg + 2;
+			continue;
+		}
 		if (!strcmp(arg, "-m")) {
 			match_nonexisting = 1;
 			continue;
@@ -208,8 +213,8 @@ int main(int argc, char **argv)
 	if (argc != 2 || get_sha1(argv[1], tree_sha1))
 		usage(diff_cache_usage);
 
-	diff_setup(detect_rename, diff_score_opt, reverse_diff,
-		   (generate_patch ? -1 : line_termination),
+	diff_setup(detect_rename, diff_score_opt, pickaxe,
+		   reverse_diff, (generate_patch ? -1 : line_termination),
 		   NULL, 0);
 
 	mark_merge_entries();
diff --git a/diff-files.c b/diff-files.c
--- a/diff-files.c
+++ b/diff-files.c
@@ -7,13 +7,14 @@
 #include "diff.h"
 
 static const char *diff_files_usage =
-"git-diff-files [-p] [-q] [-r] [-z] [-M] [-C] [-R] [paths...]";
+"git-diff-files [-p] [-q] [-r] [-z] [-M] [-C] [-R] [-S<string>] [paths...]";
 
 static int generate_patch = 0;
 static int line_termination = '\n';
 static int detect_rename = 0;
 static int reverse_diff = 0;
 static int diff_score_opt = 0;
+static char *pickaxe = 0;
 static int silent = 0;
 
 static int matches_pathspec(struct cache_entry *ce, char **spec, int cnt)
@@ -67,6 +68,8 @@ int main(int argc, char **argv)
 			line_termination = 0;
 		else if (!strcmp(argv[1], "-R"))
 			reverse_diff = 1;
+		else if (!strcmp(argv[1], "-S"))
+			pickaxe = argv[1] + 2;
 		else if (!strncmp(argv[1], "-M", 2)) {
 			diff_score_opt = diff_scoreopt_parse(argv[1]);
 			detect_rename = generate_patch = 1;
@@ -89,8 +92,8 @@ int main(int argc, char **argv)
 		exit(1);
 	}
 
-	diff_setup(detect_rename, diff_score_opt, reverse_diff,
-		   (generate_patch ? -1 : line_termination),
+	diff_setup(detect_rename, diff_score_opt, pickaxe,
+		   reverse_diff, (generate_patch ? -1 : line_termination),
 		   NULL, 0);
 
 	for (i = 0; i < entries; i++) {
diff --git a/diff-helper.c b/diff-helper.c
--- a/diff-helper.c
+++ b/diff-helper.c
@@ -9,6 +9,7 @@
 static int detect_rename = 0;
 static int diff_score_opt = 0;
 static int generate_patch = 1;
+static char *pickaxe = 0;
 
 static int parse_oneside_change(const char *cp, int *mode,
 				unsigned char *sha1, char *path)
@@ -93,7 +94,7 @@ static int parse_diff_raw_output(const c
 }
 
 static const char *diff_helper_usage =
-	"git-diff-helper [-z] [-R] [-M] [-C] paths...";
+	"git-diff-helper [-z] [-R] [-M] [-C] [-S<string>] paths...";
 
 int main(int ac, const char **av) {
 	struct strbuf sb;
@@ -117,14 +118,17 @@ int main(int ac, const char **av) {
 			detect_rename = 2;
 			diff_score_opt = diff_scoreopt_parse(av[1]);
 		}
+		else if (av[1][1] == 'S') {
+			pickaxe = av[1] + 2;
+		}
 		else
 			usage(diff_helper_usage);
 		ac--; av++;
 	}
 	/* the remaining parameters are paths patterns */
 
-	diff_setup(detect_rename, diff_score_opt, reverse,
-		   (generate_patch ? -1 : line_termination),
+	diff_setup(detect_rename, diff_score_opt, pickaxe,
+		   reverse, (generate_patch ? -1 : line_termination),
 		   av+1, ac-1);
 
 	while (1) {
diff --git a/diff-tree.c b/diff-tree.c
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -13,6 +13,7 @@ static int generate_patch = 0;
 static int detect_rename = 0;
 static int reverse_diff = 0;
 static int diff_score_opt = 0;
+static char *pickaxe = 0;
 static const char *header = NULL;
 static const char *header_prefix = "";
 
@@ -271,8 +272,8 @@ static int diff_tree_sha1_top(const unsi
 {
 	int ret;
 
-	diff_setup(detect_rename, diff_score_opt, reverse_diff,
-		   (generate_patch ? -1 : line_termination),
+	diff_setup(detect_rename, diff_score_opt, pickaxe,
+		   reverse_diff, (generate_patch ? -1 : line_termination),
 		   NULL, 0);
 	ret = diff_tree_sha1(old, new, base);
 	diff_flush();
@@ -285,8 +286,8 @@ static int diff_root_tree(const unsigned
 	void *tree;
 	unsigned long size;
 
-	diff_setup(detect_rename, diff_score_opt, reverse_diff,
-		   (generate_patch ? -1 : line_termination),
+	diff_setup(detect_rename, diff_score_opt, pickaxe,
+		   reverse_diff, (generate_patch ? -1 : line_termination),
 		   NULL, 0);
 	tree = read_object_with_reference(new, "tree", &size, NULL);
 	if (!tree)
@@ -430,7 +431,7 @@ static int diff_tree_stdin(char *line)
 }
 
 static char *diff_tree_usage =
-"git-diff-tree [-p] [-r] [-z] [--stdin] [-M] [-C] [-R] [-m] [-s] [-v] <tree-ish> <tree-ish>";
+"git-diff-tree [-p] [-r] [-z] [--stdin] [-M] [-C] [-R] [-S<string>] [-m] [-s] [-v] <tree-ish> <tree-ish>";
 
 int main(int argc, char **argv)
 {
@@ -473,6 +474,10 @@ int main(int argc, char **argv)
 			recursive = generate_patch = 1;
 			continue;
 		}
+		if (!strncmp(arg, "-S", 2)) {
+			pickaxe = arg + 2;
+			continue;
+		}
 		if (!strncmp(arg, "-M", 2)) {
 			detect_rename = recursive = generate_patch = 1;
 			diff_score_opt = diff_scoreopt_parse(arg);
diff --git a/diff.c b/diff.c
--- a/diff.c
+++ b/diff.c
@@ -17,6 +17,7 @@ static int reverse_diff;
 static int diff_raw_output = -1;
 static const char **pathspec;
 static int speccnt;
+static const char *pickaxe;
 static int minimum_score;
 
 static const char *external_diff(void)
@@ -511,8 +512,9 @@ int diff_scoreopt_parse(const char *opt)
 	return MAX_SCORE * num / scale;
 }
 
-void diff_setup(int detect_rename_, int minimum_score_, int reverse_diff_,
-		int diff_raw_output_,
+void diff_setup(int detect_rename_, int minimum_score_,
+		char *pickaxe_,
+		int reverse_diff_, int diff_raw_output_,
 		const char **pathspec_, int speccnt_)
 {
 	detect_rename = detect_rename_;
@@ -521,15 +523,16 @@ void diff_setup(int detect_rename_, int 
 	diff_raw_output = diff_raw_output_;
 	speccnt = speccnt_;
 	minimum_score = minimum_score_ ? : DEFAULT_MINIMUM_SCORE;
+	pickaxe = pickaxe_;
 }
 
 static struct diff_queue_struct queued_diff;
 
-struct diff_file_pair *diff_queue(struct diff_queue_struct *queue,
+struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
 				  struct diff_filespec *one,
 				  struct diff_filespec *two)
 {
-	struct diff_file_pair *dp = xmalloc(sizeof(*dp));
+	struct diff_filepair *dp = xmalloc(sizeof(*dp));
 	dp->one = one;
 	dp->two = two;
 	dp->xfrm_msg = 0;
@@ -549,7 +552,7 @@ static const char *git_object_type(unsig
 	return S_ISDIR(mode) ? "tree" : "blob";
 }
 
-static void diff_flush_raw(struct diff_file_pair *p)
+static void diff_flush_raw(struct diff_filepair *p)
 {
 	struct diff_filespec *it;
 	int addremove;
@@ -583,7 +586,7 @@ static void diff_flush_raw(struct diff_f
 	       sha1_to_hex(it->sha1), it->path, diff_raw_output);
 }
 
-static void diff_flush_patch(struct diff_file_pair *p)
+static void diff_flush_patch(struct diff_filepair *p)
 {
 	const char *name, *other;
 
@@ -600,7 +603,7 @@ static int identical(struct diff_filespe
 {
 	/* This function is written stricter than necessary to support
 	 * the currently implemented transformers, but the idea is to
-	 * let transformers to produce diff_file_pairs any way they want,
+	 * let transformers to produce diff_filepairs any way they want,
 	 * and filter and clean them up here before producing the output.
 	 */
 
@@ -623,7 +626,7 @@ static int identical(struct diff_filespe
 	return 0;
 }
 
-static void diff_flush_one(struct diff_file_pair *p)
+static void diff_flush_one(struct diff_filepair *p)
 {
 	if (identical(p->one, p->two))
 		return;
@@ -640,11 +643,13 @@ void diff_flush(void)
 
 	if (detect_rename)
 		diff_detect_rename(q, detect_rename, minimum_score);
+	if (pickaxe)
+		diff_pickaxe(q, pickaxe);
 	for (i = 0; i < q->nr; i++)
 		diff_flush_one(q->queue[i]);
 
 	for (i = 0; i < q->nr; i++) {
-		struct diff_file_pair *p = q->queue[i];
+		struct diff_filepair *p = q->queue[i];
 		diff_free_filespec_data(p->one);
 		diff_free_filespec_data(p->two);
 		free(p->xfrm_msg);
diff --git a/diff.h b/diff.h
--- a/diff.h
+++ b/diff.h
@@ -20,6 +20,7 @@ extern void diff_unmerge(const char *pat
 extern int diff_scoreopt_parse(const char *opt);
 
 extern void diff_setup(int detect_rename, int minimum_score,
+		       char *pickaxe,
 		       int reverse, int raw_output,
 		       const char **spec, int cnt);
 
diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c
new file mode 100644
--- /dev/null
+++ b/diffcore-pickaxe.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2005 Junio C Hamano
+ */
+#include "cache.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "delta.h"
+
+static int contains(struct diff_filespec *one,
+		    const char *needle, unsigned long len)
+{
+	unsigned long offset, sz;
+	const char *data;
+	if (diff_populate_filespec(one))
+		return 0;
+	sz = one->size;
+	data = one->data;
+	for (offset = 0; offset + len <= sz; offset++)
+		     if (!strncmp(needle, data + offset, len))
+			     return 1;
+	return 0;
+}
+
+void diff_pickaxe(struct diff_queue_struct *q, const char *needle)
+{
+	unsigned long len = strlen(needle);
+	int i;
+	struct diff_queue_struct outq;
+	outq.queue = NULL;
+	outq.nr = outq.alloc = 0;
+
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filepair *p = q->queue[i];
+		if (!p->one->file_valid) {
+			if (!p->two->file_valid)
+				continue; /* ignore nonsense */
+			/* created */
+			if (contains(p->two, needle, len))
+				diff_queue(&outq, p->one, p->two);
+		}
+		else if (!p->two->file_valid) {
+			if (contains(p->one, needle, len))
+				diff_queue(&outq, p->one, p->two);
+		}
+		else if (contains(p->one, needle, len) !=
+			 contains(p->two, needle, len))
+			diff_queue(&outq, p->one, p->two);
+	}
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filepair *p = q->queue[i];
+		free(p);
+	}
+	free(q->queue);
+	*q = outq;
+	return;
+}
diff --git a/diffcore-rename.c b/diffcore-rename.c
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -129,7 +129,7 @@ static void record_rename_pair(struct di
 	 * To achieve this sort order, we give xform_work the number
 	 * above.
 	 */
-	struct diff_file_pair *dp = diff_queue(outq, src, dst);
+	struct diff_filepair *dp = diff_queue(outq, src, dst);
 	dp->xfrm_work = (rank * 2 + 1) | (score<<RENAME_SCORE_SHIFT);
 	dst->xfrm_flags |= RENAME_DST_MATCHED;
 }
@@ -148,7 +148,7 @@ static void debug_filespec(struct diff_f
 		s->size, s->xfrm_flags);
 }
 
-static void debug_filepair(const struct diff_file_pair *p, int i)
+static void debug_filepair(const struct diff_filepair *p, int i)
 {
 	debug_filespec(p->one, i, "one");
 	debug_filespec(p->two, i, "two");
@@ -165,7 +165,7 @@ static void debug_queue(const char *msg,
 		fprintf(stderr, "%s\n", msg);
 	fprintf(stderr, "q->nr = %d\n", q->nr);
 	for (i = 0; i < q->nr; i++) {
-		struct diff_file_pair *p = q->queue[i];
+		struct diff_filepair *p = q->queue[i];
 		debug_filepair(p, i);
 	}
 }
@@ -180,8 +180,8 @@ static void debug_queue(const char *msg,
  */
 static int rank_compare(const void *a_, const void *b_)
 {
-	const struct diff_file_pair *a = *(const struct diff_file_pair **)a_;
-	const struct diff_file_pair *b = *(const struct diff_file_pair **)b_;
+	const struct diff_filepair *a = *(const struct diff_filepair **)a_;
+	const struct diff_filepair *b = *(const struct diff_filepair **)b_;
 	int a_rank = a->xfrm_work & ((1<<RENAME_SCORE_SHIFT) - 1);
 	int b_rank = b->xfrm_work & ((1<<RENAME_SCORE_SHIFT) - 1);
 
@@ -207,7 +207,7 @@ static int needs_to_stay(struct diff_que
 	 * as the source of rename/copy), we need to copy, not rename.
 	 */
 	while (i < q->nr) {
-		struct diff_file_pair *p = q->queue[i++];
+		struct diff_filepair *p = q->queue[i++];
 		if (!p->two->file_valid)
 			continue; /* removed is fine */
 		if (strcmp(p->one->path, it->path))
@@ -243,15 +243,8 @@ void diff_detect_rename(struct diff_queu
 	srcs[0] = &deleted;
 	srcs[1] = &stay;
 
-	/* NEEDSWORK:
-	 * (1) make sure we properly ignore but pass trees.
-	 *
-	 * (2) make sure we do right thing on the same path deleted
-	 *     and created in the same patch.
-	 */
-
 	for (i = 0; i < q->nr; i++) {
-		struct diff_file_pair *p = q->queue[i];
+		struct diff_filepair *p = q->queue[i];
 		if (!p->one->file_valid)
 			if (!p->two->file_valid)
 				continue; /* ignore nonsense */
@@ -340,11 +333,11 @@ void diff_detect_rename(struct diff_queu
 	 * See comments at the top of record_rename_pair for numbers used
 	 * to assign xfrm_work.
 	 *
-	 * Note that we have not annotated the diff_file_pair with any comment
+	 * Note that we have not annotated the diff_filepair with any comment
 	 * so there is nothing other than p to free.
 	 */
 	for (i = 0; i < q->nr; i++) {
-		struct diff_file_pair *dp, *p = q->queue[i];
+		struct diff_filepair *dp, *p = q->queue[i];
 		if (!p->one->file_valid) {
 			if (p->two->file_valid) {
 				/* creation */
@@ -378,7 +371,7 @@ void diff_detect_rename(struct diff_queu
 
 	/* Copy it out to q, removing duplicates. */
 	for (i = 0; i < outq.nr; i++) {
-		struct diff_file_pair *p = outq.queue[i];
+		struct diff_filepair *p = outq.queue[i];
 		if (!p->one->file_valid) {
 			/* created */
 			if (p->two->xfrm_flags & RENAME_DST_MATCHED)
@@ -395,7 +388,7 @@ void diff_detect_rename(struct diff_queu
 		}
 		else if (strcmp(p->one->path, p->two->path)) {
 			/* rename or copy */
-			struct diff_file_pair *dp =
+			struct diff_filepair *dp =
 				diff_queue(q, p->one, p->two);
 			int msglen = (strlen(p->one->path) +
 				      strlen(p->two->path) + 100);
diff --git a/diffcore.h b/diffcore.h
--- a/diffcore.h
+++ b/diffcore.h
@@ -38,7 +38,7 @@ extern void fill_filespec(struct diff_fi
 extern int diff_populate_filespec(struct diff_filespec *);
 extern void diff_free_filespec_data(struct diff_filespec *);
 
-struct diff_file_pair {
+struct diff_filepair {
 	struct diff_filespec *one;
 	struct diff_filespec *two;
 	char *xfrm_msg;
@@ -47,14 +47,15 @@ struct diff_file_pair {
 };
 
 struct diff_queue_struct {
-	struct diff_file_pair **queue;
+	struct diff_filepair **queue;
 	int alloc;
 	int nr;
 };
 
-extern struct diff_file_pair *diff_queue(struct diff_queue_struct *,
-					 struct diff_filespec *,
-					 struct diff_filespec *);
+extern struct diff_filepair *diff_queue(struct diff_queue_struct *,
+					struct diff_filespec *,
+					struct diff_filespec *);
 extern void diff_detect_rename(struct diff_queue_struct *, int, int);
+extern void diff_pickaxe(struct diff_queue_struct *, const char *);
 
 #endif
------------------------------------------------
Previous: Junio C HamanoNext: Junio C Hamano
Message 23 of 43 in “Detect renames in diff family.”
  1. Detect renames in diff family.Junio C Hamano, May 19, 2005
  2. Linus TorvaldsMay 19, 2005
  3. Junio C HamanoMay 19, 2005
  4. Linus TorvaldsMay 19, 2005
  5. Nicolas PitreMay 19, 2005
  6. Junio C HamanoMay 19, 2005
  7. Nicolas PitreMay 19, 2005
  8. Junio C HamanoMay 19, 2005
  9. Nicolas PitreMay 19, 2005
  10. Junio C HamanoMay 19, 2005
  11. Linus TorvaldsMay 19, 2005
  12. Junio C HamanoMay 19, 2005
  13. Linus TorvaldsMay 20, 2005
  14. Junio C HamanoMay 20, 2005
  15. Junio C HamanoMay 19, 2005
  16. Junio C HamanoMay 19, 2005
  17. Linus TorvaldsMay 19, 2005
  18. Junio C HamanoMay 19, 2005
  19. H. Peter AnvinMay 19, 2005
  20. Joel BeckerMay 19, 2005
  21. Junio C HamanoMay 21, 2005
  22. 1/3 Diff overhaul, adding half of copy detection.Junio C Hamano, May 21, 2005
  23. 2/3 Introducing software archaeologist's tool "pickaxe".Junio C Hamano, May 21, 2005
  24. Constness fix for pickaxe option.Junio C Hamano, May 21, 2005
  25. Linus TorvaldsMay 21, 2005
  26. 3/3 Diff overhaul, adding the other half of copy detection.Junio C Hamano, May 21, 2005
  27. Teach diff-tree to report unmodified paths for -C option.Junio C Hamano, May 21, 2005
  28. Junio C HamanoMay 21, 2005
  29. Linus TorvaldsMay 21, 2005
  30. Junio C HamanoMay 21, 2005
  31. Linus TorvaldsMay 21, 2005
  32. Linus TorvaldsMay 21, 2005
  33. Linus TorvaldsMay 21, 2005
  34. Junio C HamanoMay 21, 2005
  35. Junio C HamanoMay 24, 2005
  36. Linus TorvaldsMay 24, 2005
  37. Junio C HamanoMay 24, 2005
  38. Linus TorvaldsMay 24, 2005
  39. Junio C HamanoMay 24, 2005
  40. Detect copies harder in diff-tree.Junio C Hamano, May 26, 2005
  41. Junio C HamanoMay 21, 2005
  42. Tweak diffcore-rename heuristics.Junio C Hamano, May 21, 2005
  43. Now I think I am done with diff...Junio C Hamano, May 23, 2005

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.