git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] Teach git-blame about renames (take 2)
@ 2006-03-10  9:21 Fredrik Kuivinen
  2006-03-10  9:21 ` [PATCH 1/3] Make it possible to not clobber object.util in sort_in_topological_order " Fredrik Kuivinen
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Fredrik Kuivinen @ 2006-03-10  9:21 UTC (permalink / raw)
  To: git; +Cc: junkio


Changes since the previous version:

* Fix the things pointed out by Junio.
* Some other minor clean-ups

---

This patch series teaches git-blame about renames. To do this I have
changed the revision.h interface a bit. In particular, it is now
possible for the user of revision.h to specify a
try_to_simply_commit-like function. That function can then do the
rename tracking.

I have also made a small change to sort_in_topological_order to make
it possible to use the object.util field at the same time as a
topological sort is done. Previously the object.util field was
clobbered by the topological sort. In the new interface the auxiliary
data that the topological sort needs to store for each commit object
is stored with a setter function and retrieved by a getter. Pointers
to those functions are passed to sort_in_topological_order_fn.

- Fredrik

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/3] Make it possible to not clobber object.util in sort_in_topological_order (take 2)
  2006-03-10  9:21 [PATCH 0/3] Teach git-blame about renames (take 2) Fredrik Kuivinen
@ 2006-03-10  9:21 ` Fredrik Kuivinen
  2006-03-10  9:21 ` [PATCH 2/3] rev-lib: Make it easy to do rename tracking " Fredrik Kuivinen
  2006-03-10  9:21 ` [PATCH 3/3] blame: Rename detection " Fredrik Kuivinen
  2 siblings, 0 replies; 5+ messages in thread
From: Fredrik Kuivinen @ 2006-03-10  9:21 UTC (permalink / raw)
  To: git; +Cc: junkio




Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>

---

 commit.c |   30 ++++++++++++++++++++++++------
 commit.h |   16 +++++++++++++++-
 2 files changed, 39 insertions(+), 7 deletions(-)

diff --git a/commit.c b/commit.c
index 06d5439..013683a 100644
--- a/commit.c
+++ b/commit.c
@@ -569,11 +569,29 @@ int count_parents(struct commit * commit
         return count;
 }
 
+void topo_sort_default_setter(struct commit *c, void *data)
+{
+	c->object.util = data;
+}
+
+void *topo_sort_default_getter(struct commit *c)
+{
+	return c->object.util;
+}
+
 /*
  * Performs an in-place topological sort on the list supplied.
  */
 void sort_in_topological_order(struct commit_list ** list, int lifo)
 {
+	sort_in_topological_order_fn(list, lifo, topo_sort_default_setter,
+				     topo_sort_default_getter);
+}
+
+void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
+				  topo_sort_set_fn_t setter,
+				  topo_sort_get_fn_t getter)
+{
 	struct commit_list * next = *list;
 	struct commit_list * work = NULL, **insert;
 	struct commit_list ** pptr = list;
@@ -596,7 +614,7 @@ void sort_in_topological_order(struct co
 	next=*list;
 	while (next) {
 		next_nodes->list_item = next;
-		next->item->object.util = next_nodes;
+		setter(next->item, next_nodes);
 		next_nodes++;
 		next = next->next;
 	}
@@ -606,7 +624,7 @@ void sort_in_topological_order(struct co
 		struct commit_list * parents = next->item->parents;
 		while (parents) {
 			struct commit * parent=parents->item;
-			struct sort_node * pn = (struct sort_node *)parent->object.util;
+			struct sort_node * pn = (struct sort_node *) getter(parent);
 			
 			if (pn)
 				pn->indegree++;
@@ -624,7 +642,7 @@ void sort_in_topological_order(struct co
 	next=*list;
 	insert = &work;
 	while (next) {
-		struct sort_node * node = (struct sort_node *)next->item->object.util;
+		struct sort_node * node = (struct sort_node *) getter(next->item);
 
 		if (node->indegree == 0) {
 			insert = &commit_list_insert(next->item, insert)->next;
@@ -637,12 +655,12 @@ void sort_in_topological_order(struct co
 		sort_by_date(&work);
 	while (work) {
 		struct commit * work_item = pop_commit(&work);
-		struct sort_node * work_node = (struct sort_node *)work_item->object.util;
+		struct sort_node * work_node = (struct sort_node *) getter(work_item);
 		struct commit_list * parents = work_item->parents;
 
 		while (parents) {
 			struct commit * parent=parents->item;
-			struct sort_node * pn = (struct sort_node *)parent->object.util;
+			struct sort_node * pn = (struct sort_node *) getter(parent);
 			
 			if (pn) {
 				/* 
@@ -667,7 +685,7 @@ void sort_in_topological_order(struct co
 		*pptr = work_node->list_item;
 		pptr = &(*pptr)->next;
 		*pptr = NULL;
-		work_item->object.util = NULL;
+		setter(work_item, NULL);
 	}
 	free(nodes);
 }
diff --git a/commit.h b/commit.h
index 70a7c75..15c798a 100644
--- a/commit.h
+++ b/commit.h
@@ -65,15 +65,29 @@ int count_parents(struct commit * commit
 /*
  * Performs an in-place topological sort of list supplied.
  *
- * Pre-conditions:
+ * Pre-conditions for sort_in_topological_order:
  *   all commits in input list and all parents of those
  *   commits must have object.util == NULL
  *        
+ * Pre-conditions for sort_in_topological_order_fn:
+ *   all commits in input list and all parents of those
+ *   commits must have getter(commit) == NULL
+ *
  * Post-conditions: 
  *   invariant of resulting list is:
  *      a reachable from b => ord(b) < ord(a)
  *   in addition, when lifo == 0, commits on parallel tracks are
  *   sorted in the dates order.
  */
+
+typedef void (*topo_sort_set_fn_t)(struct commit*, void *data);
+typedef void* (*topo_sort_get_fn_t)(struct commit*);
+
+void topo_sort_default_setter(struct commit *c, void *data);
+void *topo_sort_default_getter(struct commit *c);
+
 void sort_in_topological_order(struct commit_list ** list, int lifo);
+void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
+				  topo_sort_set_fn_t setter,
+				  topo_sort_get_fn_t getter);
 #endif /* COMMIT_H */

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/3] rev-lib: Make it easy to do rename tracking (take 2)
  2006-03-10  9:21 [PATCH 0/3] Teach git-blame about renames (take 2) Fredrik Kuivinen
  2006-03-10  9:21 ` [PATCH 1/3] Make it possible to not clobber object.util in sort_in_topological_order " Fredrik Kuivinen
@ 2006-03-10  9:21 ` Fredrik Kuivinen
  2006-03-10  9:21 ` [PATCH 3/3] blame: Rename detection " Fredrik Kuivinen
  2 siblings, 0 replies; 5+ messages in thread
From: Fredrik Kuivinen @ 2006-03-10  9:21 UTC (permalink / raw)
  To: git; +Cc: junkio


prune_fn in the rev_info structure is called in place of
try_to_simplify_commit. This makes it possible to do rename tracking
with a custom try_to_simplify_commit-like function.

This commit also introduces init_revisions which initialises the rev_info
structure with default values.

Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>

---

 rev-list.c |    6 ++--
 revision.c |  100 ++++++++++++++++++++++++++++++++++--------------------------
 revision.h |   18 ++++++++++-
 3 files changed, 76 insertions(+), 48 deletions(-)

diff --git a/rev-list.c b/rev-list.c
index 8e4d83e..812d237 100644
--- a/rev-list.c
+++ b/rev-list.c
@@ -190,7 +190,7 @@ static int count_distance(struct commit_
 
 		if (commit->object.flags & (UNINTERESTING | COUNTED))
 			break;
-		if (!revs.paths || (commit->object.flags & TREECHANGE))
+		if (!revs.prune_fn || (commit->object.flags & TREECHANGE))
 			nr++;
 		commit->object.flags |= COUNTED;
 		p = commit->parents;
@@ -224,7 +224,7 @@ static struct commit_list *find_bisectio
 	nr = 0;
 	p = list;
 	while (p) {
-		if (!revs.paths || (p->item->object.flags & TREECHANGE))
+		if (!revs.prune_fn || (p->item->object.flags & TREECHANGE))
 			nr++;
 		p = p->next;
 	}
@@ -234,7 +234,7 @@ static struct commit_list *find_bisectio
 	for (p = list; p; p = p->next) {
 		int distance;
 
-		if (revs.paths && !(p->item->object.flags & TREECHANGE))
+		if (revs.prune_fn && !(p->item->object.flags & TREECHANGE))
 			continue;
 
 		distance = count_distance(p);
diff --git a/revision.c b/revision.c
index 2a33637..b41f961 100644
--- a/revision.c
+++ b/revision.c
@@ -197,31 +197,27 @@ static int everybody_uninteresting(struc
 	return 1;
 }
 
-#define TREE_SAME	0
-#define TREE_NEW	1
-#define TREE_DIFFERENT	2
-static int tree_difference = TREE_SAME;
+static int tree_difference = REV_TREE_SAME;
 
 static void file_add_remove(struct diff_options *options,
 		    int addremove, unsigned mode,
 		    const unsigned char *sha1,
 		    const char *base, const char *path)
 {
-	int diff = TREE_DIFFERENT;
+	int diff = REV_TREE_DIFFERENT;
 
 	/*
-	 * Is it an add of a new file? It means that
-	 * the old tree didn't have it at all, so we
-	 * will turn "TREE_SAME" -> "TREE_NEW", but
-	 * leave any "TREE_DIFFERENT" alone (and if
-	 * it already was "TREE_NEW", we'll keep it
-	 * "TREE_NEW" of course).
+	 * Is it an add of a new file? It means that the old tree
+	 * didn't have it at all, so we will turn "REV_TREE_SAME" ->
+	 * "REV_TREE_NEW", but leave any "REV_TREE_DIFFERENT" alone
+	 * (and if it already was "REV_TREE_NEW", we'll keep it
+	 * "REV_TREE_NEW" of course).
 	 */
 	if (addremove == '+') {
 		diff = tree_difference;
-		if (diff != TREE_SAME)
+		if (diff != REV_TREE_SAME)
 			return;
-		diff = TREE_NEW;
+		diff = REV_TREE_NEW;
 	}
 	tree_difference = diff;
 }
@@ -232,7 +228,7 @@ static void file_change(struct diff_opti
 		 const unsigned char *new_sha1,
 		 const char *base, const char *path)
 {
-	tree_difference = TREE_DIFFERENT;
+	tree_difference = REV_TREE_DIFFERENT;
 }
 
 static struct diff_options diff_opt = {
@@ -241,19 +237,19 @@ static struct diff_options diff_opt = {
 	.change = file_change,
 };
 
-static int compare_tree(struct tree *t1, struct tree *t2)
+int rev_compare_tree(struct tree *t1, struct tree *t2)
 {
 	if (!t1)
-		return TREE_NEW;
+		return REV_TREE_NEW;
 	if (!t2)
-		return TREE_DIFFERENT;
-	tree_difference = TREE_SAME;
+		return REV_TREE_DIFFERENT;
+	tree_difference = REV_TREE_SAME;
 	if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "", &diff_opt) < 0)
-		return TREE_DIFFERENT;
+		return REV_TREE_DIFFERENT;
 	return tree_difference;
 }
 
-static int same_tree_as_empty(struct tree *t1)
+int rev_same_tree_as_empty(struct tree *t1)
 {
 	int retval;
 	void *tree;
@@ -285,7 +281,7 @@ static void try_to_simplify_commit(struc
 		return;
 
 	if (!commit->parents) {
-		if (!same_tree_as_empty(commit->tree))
+		if (!rev_same_tree_as_empty(commit->tree))
 			commit->object.flags |= TREECHANGE;
 		return;
 	}
@@ -300,19 +296,20 @@ static void try_to_simplify_commit(struc
 		}
 
 		parse_commit(p);
-		switch (compare_tree(p->tree, commit->tree)) {
-		case TREE_SAME:
+		switch (rev_compare_tree(p->tree, commit->tree)) {
+		case REV_TREE_SAME:
 			parent->next = NULL;
 			commit->parents = parent;
 			return;
 
-		case TREE_NEW:
-			if (revs->remove_empty_trees && same_tree_as_empty(p->tree)) {
+		case REV_TREE_NEW:
+			if (revs->remove_empty_trees &&
+			    rev_same_tree_as_empty(p->tree)) {
 				*pp = parent->next;
 				continue;
 			}
 		/* fallthrough */
-		case TREE_DIFFERENT:
+		case REV_TREE_DIFFERENT:
 			pp = &parent->next;
 			continue;
 		}
@@ -358,8 +355,8 @@ static void add_parents_to_list(struct r
 	 * simplify the commit history and find the parent
 	 * that has no differences in the path set if one exists.
 	 */
-	if (revs->paths)
-		try_to_simplify_commit(revs, commit);
+	if (revs->prune_fn)
+		revs->prune_fn(revs, commit);
 
 	parent = commit->parents;
 	while (parent) {
@@ -381,9 +378,6 @@ static void limit_list(struct rev_info *
 	struct commit_list *newlist = NULL;
 	struct commit_list **p = &newlist;
 
-	if (revs->paths)
-		diff_tree_setup_paths(revs->paths);
-
 	while (list) {
 		struct commit_list *entry = list;
 		struct commit *commit = list->item;
@@ -435,6 +429,23 @@ static void handle_all(struct rev_info *
 	for_each_ref(handle_one_ref);
 }
 
+void init_revisions(struct rev_info *revs)
+{
+	memset(revs, 0, sizeof(*revs));
+	revs->lifo = 1;
+	revs->dense = 1;
+	revs->prefix = setup_git_directory();
+	revs->max_age = -1;
+	revs->min_age = -1;
+	revs->max_count = -1;
+
+	revs->prune_fn = NULL;
+	revs->prune_data = NULL;
+
+	revs->topo_setter = topo_sort_default_setter;
+	revs->topo_getter = topo_sort_default_getter;
+}
+
 /*
  * Parse revision information, filling in the "rev_info" structure,
  * and removing the used arguments from the argument list.
@@ -448,14 +459,8 @@ int setup_revisions(int argc, const char
 	const char **unrecognized = argv + 1;
 	int left = 1;
 
-	memset(revs, 0, sizeof(*revs));
-	revs->lifo = 1;
-	revs->dense = 1;
-	revs->prefix = setup_git_directory();
-	revs->max_age = -1;
-	revs->min_age = -1;
-	revs->max_count = -1;
-
+	init_revisions(revs);
+	
 	/* First, search for "--" */
 	seen_dashdash = 0;
 	for (i = 1; i < argc; i++) {
@@ -464,7 +469,7 @@ int setup_revisions(int argc, const char
 			continue;
 		argv[i] = NULL;
 		argc = i;
-		revs->paths = get_pathspec(revs->prefix, argv + i + 1);
+		revs->prune_data = get_pathspec(revs->prefix, argv + i + 1);
 		seen_dashdash = 1;
 		break;
 	}
@@ -628,7 +633,7 @@ int setup_revisions(int argc, const char
 				if (lstat(argv[j], &st) < 0)
 					die("'%s': %s", arg, strerror(errno));
 			}
-			revs->paths = get_pathspec(revs->prefix, argv + i);
+			revs->prune_data = get_pathspec(revs->prefix, argv + i);
 			break;
 		}
 		commit = get_commit_reference(revs, arg, sha1, flags ^ local_flags);
@@ -642,8 +647,13 @@ int setup_revisions(int argc, const char
 		commit = get_commit_reference(revs, def, sha1, 0);
 		add_one_commit(commit, revs);
 	}
-	if (revs->paths)
+
+	if (revs->prune_data) {
+		diff_tree_setup_paths(revs->prune_data);
+		revs->prune_fn = try_to_simplify_commit;
 		revs->limited = 1;
+	}
+
 	return left;
 }
 
@@ -653,7 +663,9 @@ void prepare_revision_walk(struct rev_in
 	if (revs->limited)
 		limit_list(revs);
 	if (revs->topo_order)
-		sort_in_topological_order(&revs->commits, revs->lifo);
+		sort_in_topological_order_fn(&revs->commits, revs->lifo,
+					     revs->topo_setter,
+					     revs->topo_getter);
 }
 
 static int rewrite_one(struct commit **pp)
@@ -709,7 +721,7 @@ struct commit *get_revision(struct rev_i
 			return NULL;
 		if (revs->no_merges && commit->parents && commit->parents->next)
 			goto next;
-		if (revs->paths && revs->dense) {
+		if (revs->prune_fn && revs->dense) {
 			if (!(commit->object.flags & TREECHANGE))
 				goto next;
 			rewrite_parents(commit);
diff --git a/revision.h b/revision.h
index 31e8f61..6c2beca 100644
--- a/revision.h
+++ b/revision.h
@@ -7,6 +7,10 @@
 #define SHOWN		(1u<<3)
 #define TMP_MARK	(1u<<4) /* for isolated cases; clean after use */
 
+struct rev_info;
+
+typedef void (prune_fn_t)(struct rev_info *revs, struct commit *commit);
+
 struct rev_info {
 	/* Starting list */
 	struct commit_list *commits;
@@ -14,7 +18,8 @@ struct rev_info {
 
 	/* Basic information */
 	const char *prefix;
-	const char **paths;
+	void *prune_data;
+	prune_fn_t *prune_fn;
 
 	/* Traversal flags */
 	unsigned int	dense:1,
@@ -33,9 +38,20 @@ struct rev_info {
 	int max_count;
 	unsigned long max_age;
 	unsigned long min_age;
+
+	topo_sort_set_fn_t topo_setter;
+	topo_sort_get_fn_t topo_getter;
 };
 
+#define REV_TREE_SAME		0
+#define REV_TREE_NEW		1
+#define REV_TREE_DIFFERENT	2
+
 /* revision.c */
+extern int rev_same_tree_as_empty(struct tree *t1);
+extern int rev_compare_tree(struct tree *t1, struct tree *t2);
+
+extern void init_revisions(struct rev_info *revs);
 extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def);
 extern void prepare_revision_walk(struct rev_info *revs);
 extern struct commit *get_revision(struct rev_info *revs);

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/3] blame: Rename detection (take 2)
  2006-03-10  9:21 [PATCH 0/3] Teach git-blame about renames (take 2) Fredrik Kuivinen
  2006-03-10  9:21 ` [PATCH 1/3] Make it possible to not clobber object.util in sort_in_topological_order " Fredrik Kuivinen
  2006-03-10  9:21 ` [PATCH 2/3] rev-lib: Make it easy to do rename tracking " Fredrik Kuivinen
@ 2006-03-10  9:21 ` Fredrik Kuivinen
  2006-03-16  0:31   ` Junio C Hamano
  2 siblings, 1 reply; 5+ messages in thread
From: Fredrik Kuivinen @ 2006-03-10  9:21 UTC (permalink / raw)
  To: git; +Cc: junkio




Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>

---

 blame.c |  239 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 199 insertions(+), 40 deletions(-)

diff --git a/blame.c b/blame.c
index 90338af..ac57e10 100644
--- a/blame.c
+++ b/blame.c
@@ -14,6 +14,7 @@
 #include "tree.h"
 #include "blob.h"
 #include "diff.h"
+#include "diffcore.h"
 #include "revision.h"
 
 #define DEBUG 0
@@ -34,7 +35,9 @@ struct util_info {
 	char *buf;
 	unsigned long size;
 	int num_lines;
-//    const char* path;
+	const char* pathname;
+
+	void* topo_data;
 };
 
 struct chunk {
@@ -342,25 +345,34 @@ static int map_line(struct commit *commi
 	return info->line_map[line];
 }
 
-static int fill_util_info(struct commit *commit, const char *path)
+static struct util_info* get_util(struct commit *commit)
 {
-	struct util_info *util;
-	if (commit->object.util)
-		return 0;
+	struct util_info *util = commit->object.util;
+
+	if (util)
+		return util;
 
 	util = xmalloc(sizeof(struct util_info));
+	util->buf = NULL;
+	util->size = 0;
+	util->line_map = NULL;
+	util->num_lines = -1;
+	util->pathname = NULL;
+	commit->object.util = util;
+	return util;
+}
 
-	if (get_blob_sha1(commit->tree, path, util->sha1)) {
-		free(util);
+static int fill_util_info(struct commit *commit)
+{
+	struct util_info *util = commit->object.util;
+
+	assert(util);
+	assert(util->pathname);
+	
+	if (get_blob_sha1(commit->tree, util->pathname, util->sha1))
 		return 1;
-	} else {
-		util->buf = NULL;
-		util->size = 0;
-		util->line_map = NULL;
-		util->num_lines = -1;
-		commit->object.util = util;
+	else
 		return 0;
-	}
 }
 
 static void alloc_line_map(struct commit *commit)
@@ -389,10 +401,11 @@ static void alloc_line_map(struct commit
 
 static void init_first_commit(struct commit* commit, const char* filename)
 {
-	struct util_info* util;
+	struct util_info* util = commit->object.util;
 	int i;
 
-	if (fill_util_info(commit, filename))
+	util->pathname = filename;
+	if (fill_util_info(commit))
 		die("fill_util_info failed");
 
 	alloc_line_map(commit);
@@ -453,7 +466,7 @@ static void process_commits(struct rev_i
 		if(num_parents == 0)
 			*initial = commit;
 
-		if(fill_util_info(commit, path))
+		if (fill_util_info(commit))
 			continue;
 
 		alloc_line_map(commit);
@@ -471,7 +484,7 @@ static void process_commits(struct rev_i
 				printf("parent: %s\n",
 				       sha1_to_hex(parent->object.sha1));
 
-			if(fill_util_info(parent, path)) {
+			if (fill_util_info(parent)) {
 				num_parents--;
 				continue;
 			}
@@ -511,6 +524,135 @@ static void process_commits(struct rev_i
 	} while ((commit = get_revision(rev)) != NULL);
 }
 
+
+static int compare_tree_path(struct rev_info* revs,
+			     struct commit* c1, struct commit* c2)
+{
+	const char* paths[2];
+	struct util_info* util = c2->object.util;
+	paths[0] = util->pathname;
+	paths[1] = NULL;
+
+	diff_tree_setup_paths(get_pathspec(revs->prefix, paths));
+	return rev_compare_tree(c1->tree, c2->tree);
+}
+
+
+static int same_tree_as_empty_path(struct rev_info *revs, struct tree* t1,
+				   const char* path)
+{
+	const char* paths[2];
+	paths[0] = path;
+	paths[1] = NULL;
+
+	diff_tree_setup_paths(get_pathspec(revs->prefix, paths));
+	return rev_same_tree_as_empty(t1);
+}
+
+static const char* find_rename(struct commit* commit, struct commit* parent)
+{
+	struct util_info* cutil = commit->object.util;
+	struct diff_options diff_opts;
+	const char *paths[1];
+	int i;
+
+	if (DEBUG) {
+		printf("find_rename commit: %s ",
+		       sha1_to_hex(commit->object.sha1));
+		puts(sha1_to_hex(parent->object.sha1));
+	}
+
+	diff_setup(&diff_opts);
+	diff_opts.recursive = 1;
+	diff_opts.detect_rename = DIFF_DETECT_RENAME;
+	paths[0] = NULL;
+	diff_tree_setup_paths(paths);
+	if (diff_setup_done(&diff_opts) < 0)
+		die("diff_setup_done failed");
+
+	diff_tree_sha1(commit->tree->object.sha1, parent->tree->object.sha1,
+		       "", &diff_opts);
+	diffcore_std(&diff_opts);
+
+	for (i = 0; i < diff_queued_diff.nr; i++) {
+		struct diff_filepair *p = diff_queued_diff.queue[i];
+
+		if (p->status == 'R' && !strcmp(p->one->path, cutil->pathname)) {
+			if (DEBUG)
+				printf("rename %s -> %s\n", p->one->path, p->two->path);
+			return p->two->path;
+		}
+	}
+
+	return 0;
+}
+
+static void simplify_commit(struct rev_info *revs, struct commit *commit)
+{
+	struct commit_list **pp, *parent;
+
+	if (!commit->tree)
+		return;
+
+	if (!commit->parents) {
+		struct util_info* util = commit->object.util;
+		if (!same_tree_as_empty_path(revs, commit->tree,
+					     util->pathname))
+			commit->object.flags |= TREECHANGE;
+		return;
+	}
+
+	pp = &commit->parents;
+	while ((parent = *pp) != NULL) {
+		struct commit *p = parent->item;
+
+		if (p->object.flags & UNINTERESTING) {
+			pp = &parent->next;
+			continue;
+		}
+
+		parse_commit(p);
+		switch (compare_tree_path(revs, p, commit)) {
+		case REV_TREE_SAME:
+			parent->next = NULL;
+			commit->parents = parent;
+			get_util(p)->pathname = get_util(commit)->pathname;
+			return;
+
+		case REV_TREE_NEW:
+		{
+			
+			struct util_info* util = commit->object.util;
+			if (revs->remove_empty_trees &&
+			    same_tree_as_empty_path(revs, p->tree,
+						    util->pathname)) {
+				const char* new_name = find_rename(commit, p);
+				if (new_name) {
+					struct util_info* putil = get_util(p);
+					if (!putil->pathname)
+						putil->pathname = strdup(new_name);
+				} else {
+					*pp = parent->next;
+					continue;
+				}
+			}
+		}
+
+		/* fallthrough */
+		case REV_TREE_DIFFERENT:
+			pp = &parent->next;
+			if (!get_util(p)->pathname)
+				get_util(p)->pathname =
+					get_util(commit)->pathname;
+			continue;
+		}
+		die("bad tree compare for commit %s",
+		    sha1_to_hex(commit->object.sha1));
+	}
+	commit->object.flags |= TREECHANGE;
+}
+
+
 struct commit_info
 {
 	char* author;
@@ -569,6 +711,18 @@ static const char* format_time(unsigned 
 	return time_buf;
 }
 
+static void topo_setter(struct commit* c, void* data)
+{
+	struct util_info* util = c->object.util;
+	util->topo_data = data;
+}
+
+static void* topo_getter(struct commit* c)
+{
+	struct util_info* util = c->object.util;
+	return util->topo_data;
+}
+
 int main(int argc, const char **argv)
 {
 	int i;
@@ -580,8 +734,8 @@ int main(int argc, const char **argv)
 	int sha1_len = 8;
 	int compability = 0;
 	int options = 1;
+	struct commit* start_commit;
 
-	int num_args;
 	const char* args[10];
 	struct rev_info rev;
 
@@ -634,28 +788,29 @@ int main(int argc, const char **argv)
 		strcpy(filename_buf, filename);
 	filename = filename_buf;
 
-	{
-		struct commit* c;
-		if (get_sha1(commit, sha1))
-			die("get_sha1 failed, commit '%s' not found", commit);
-		c = lookup_commit_reference(sha1);
-
-		if (fill_util_info(c, filename)) {
-			printf("%s not found in %s\n", filename, commit);
-			return 1;
-		}
+	if (get_sha1(commit, sha1))
+		die("get_sha1 failed, commit '%s' not found", commit);	
+	start_commit = lookup_commit_reference(sha1);
+	get_util(start_commit)->pathname = filename;
+	if (fill_util_info(start_commit)) {
+		printf("%s not found in %s\n", filename, commit);
+		return 1;
 	}
 
-	num_args = 0;
-	args[num_args++] = NULL;
-	args[num_args++] = "--topo-order";
-	args[num_args++] = "--remove-empty";
-	args[num_args++] = commit;
-	args[num_args++] = "--";
-	args[num_args++] = filename;
-	args[num_args] = NULL;
 
-	setup_revisions(num_args, args, &rev, "HEAD");
+	init_revisions(&rev);	
+	rev.remove_empty_trees = 1;
+	rev.topo_order = 1;
+	rev.prune_fn = simplify_commit;
+	rev.topo_setter = topo_setter;
+	rev.topo_getter = topo_getter;
+	rev.limited = 1;
+
+	commit_list_insert(start_commit, &rev.commits);
+	
+	args[0] = filename;
+	args[1] = NULL;
+	diff_tree_setup_paths(args);
 	prepare_revision_walk(&rev);
 	process_commits(&rev, filename, &initial);
 
@@ -665,17 +820,21 @@ int main(int argc, const char **argv)
 
 	for (i = 0; i < num_blame_lines; i++) {
 		struct commit *c = blame_lines[i];
+		struct util_info* u;
+
 		if (!c)
 			c = initial;
 
+		u = c->object.util;
 		get_commit_info(c, &ci);
 		fwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout);
 		if(compability)
 			printf("\t(%10s\t%10s\t%d)", ci.author,
 			       format_time(ci.author_time, ci.author_tz), i+1);
 		else
-			printf(" (%-15.15s %10s %*d) ", ci.author,
-			       format_time(ci.author_time, ci.author_tz),
+			printf(" %s (%-15.15s %10s %*d) ", u->pathname,
+			       ci.author, format_time(ci.author_time,
+						      ci.author_tz),
 			       max_digits, i+1);
 
 		if(i == num_blame_lines - 1) {

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 3/3] blame: Rename detection (take 2)
  2006-03-10  9:21 ` [PATCH 3/3] blame: Rename detection " Fredrik Kuivinen
@ 2006-03-16  0:31   ` Junio C Hamano
  0 siblings, 0 replies; 5+ messages in thread
From: Junio C Hamano @ 2006-03-16  0:31 UTC (permalink / raw)
  To: Fredrik Kuivinen; +Cc: git

Very nice.  It even works with that "insanely fast rename
detector" by Linus ;-)

An example, from an early part of "git blame git-format-patch.sh":

0acfc972 git-format-patch-script (Junio C Hamano  2005-07-05 13:19:05 -0700 
0acfc972 git-format-patch-script (Junio C Hamano  2005-07-05 13:19:05 -0700 
0acfc972 git-format-patch-script (Junio C Hamano  2005-07-05 13:19:05 -0700 
19bb7327 git-format-patch.sh (Mike McCormack  2006-03-06 22:12:12 +0900   6)
66f04f38 git-format-patch.sh (Andreas Ericsso 2006-02-07 09:37:54 +0000   7)
66f04f38 git-format-patch.sh (Andreas Ericsso 2006-02-07 09:37:54 +0000   8)
66f04f38 git-format-patch.sh (Andreas Ericsso 2006-02-07 09:37:54 +0000   9)
66f04f38 git-format-patch.sh (Andreas Ericsso 2006-02-07 09:37:54 +0000  10)

However, I think this underlines that chopping people's names to
the first 15 bytes (or any length for that matter) does not buy
you much.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2006-03-16  0:32 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-03-10  9:21 [PATCH 0/3] Teach git-blame about renames (take 2) Fredrik Kuivinen
2006-03-10  9:21 ` [PATCH 1/3] Make it possible to not clobber object.util in sort_in_topological_order " Fredrik Kuivinen
2006-03-10  9:21 ` [PATCH 2/3] rev-lib: Make it easy to do rename tracking " Fredrik Kuivinen
2006-03-10  9:21 ` [PATCH 3/3] blame: Rename detection " Fredrik Kuivinen
2006-03-16  0:31   ` Junio C Hamano

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).