{"thread":{"id":"3604","subject":"[PATCH 0/3] Teach git-blame about renames","startedAt":"2006-03-08T22:54:12Z","lastAt":"2006-03-09T07:30:14Z","messageCount":6,"participants":["Fredrik Kuivinen","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"17347","messageId":"20060308225412.GA461@c165.ib.student.liu.se","threadId":"3604","inReplyTo":null,"subject":"[PATCH 0/3] Teach git-blame about renames","fromName":"Fredrik Kuivinen","fromEmail":"freku045@student.liu.se","sentAt":"2006-03-08T22:54:12Z","receivedAt":"2006-03-08T22:54:12Z","isPatch":true,"sender":{"key":"frekui@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13770967?v=4"},"body":"Hi,\n\nThis patch series teaches git-blame about renames. To do this I have\nchanged the revision.h interface a bit. In particular, it is now\npossible for the user of revision.h to specify a\ntry_to_simply_commit-like function. That function can then do the\nrename tracking.\n\nI have also made a small change to sort_in_topological_order to make\nit possible to use the object.util field at the same time as a\ntopological sort is done. Previously the object.util field was\nclobbered by the topological sort. In the new interface the auxiliary\ndata that the topological sort needs to store for each commit object\nis stored with a setter function and retrieved by a getter. Pointers\nto those functions are passed to sort_in_topological_order.\n\n- Fredrik\n"},{"id":"17348","messageId":"20060308225905.GB461@c165.ib.student.liu.se","threadId":"3604","inReplyTo":"20060308225412.GA461@c165.ib.student.liu.se","subject":"[PATCH 1/3] Make it possible to not clobber object.util in sort_in_topological_order","fromName":"Fredrik Kuivinen","fromEmail":"freku045@student.liu.se","sentAt":"2006-03-08T22:59:05Z","receivedAt":"2006-03-08T22:59:05Z","isPatch":true,"sender":{"key":"frekui@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13770967?v=4"},"body":"Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>\n\n---\n\n commit.c |   27 +++++++++++++++++++++------\n commit.h |    9 +++++++++\n 2 files changed, 30 insertions(+), 6 deletions(-)\n\ndiff --git a/commit.c b/commit.c\nindex 06d5439..2552ffd 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -569,11 +569,26 @@ int count_parents(struct commit * commit\n         return count;\n }\n \n+void default_setter(struct commit* c, void* data)\n+{\n+\tc->object.util = data;\n+}\n+\n+void* default_getter(struct commit* c)\n+{\n+\treturn c->object.util;\n+}\n+\n /*\n  * Performs an in-place topological sort on the list supplied.\n  */\n void sort_in_topological_order(struct commit_list ** list, int lifo)\n {\n+\tsort_in_topological_order_fun(list, lifo, default_setter, default_getter);\n+}\n+\n+void sort_in_topological_order_fun(struct commit_list ** list, int lifo, set_fn_t setter, get_fn_t getter)\n+{\n \tstruct commit_list * next = *list;\n \tstruct commit_list * work = NULL, **insert;\n \tstruct commit_list ** pptr = list;\n@@ -596,7 +611,7 @@ void sort_in_topological_order(struct co\n \tnext=*list;\n \twhile (next) {\n \t\tnext_nodes->list_item = next;\n-\t\tnext->item->object.util = next_nodes;\n+\t\tsetter(next->item, next_nodes);\n \t\tnext_nodes++;\n \t\tnext = next->next;\n \t}\n@@ -606,7 +621,7 @@ void sort_in_topological_order(struct co\n \t\tstruct commit_list * parents = next->item->parents;\n \t\twhile (parents) {\n \t\t\tstruct commit * parent=parents->item;\n-\t\t\tstruct sort_node * pn = (struct sort_node *)parent->object.util;\n+\t\t\tstruct sort_node * pn = (struct sort_node *) getter(parent);\n \t\t\t\n \t\t\tif (pn)\n \t\t\t\tpn->indegree++;\n@@ -624,7 +639,7 @@ void sort_in_topological_order(struct co\n \tnext=*list;\n \tinsert = &work;\n \twhile (next) {\n-\t\tstruct sort_node * node = (struct sort_node *)next->item->object.util;\n+\t\tstruct sort_node * node = (struct sort_node *) getter(next->item);\n \n \t\tif (node->indegree == 0) {\n \t\t\tinsert = &commit_list_insert(next->item, insert)->next;\n@@ -637,12 +652,12 @@ void sort_in_topological_order(struct co\n \t\tsort_by_date(&work);\n \twhile (work) {\n \t\tstruct commit * work_item = pop_commit(&work);\n-\t\tstruct sort_node * work_node = (struct sort_node *)work_item->object.util;\n+\t\tstruct sort_node * work_node = (struct sort_node *) getter(work_item);\n \t\tstruct commit_list * parents = work_item->parents;\n \n \t\twhile (parents) {\n \t\t\tstruct commit * parent=parents->item;\n-\t\t\tstruct sort_node * pn = (struct sort_node *)parent->object.util;\n+\t\t\tstruct sort_node * pn = (struct sort_node *) getter(parent);\n \t\t\t\n \t\t\tif (pn) {\n \t\t\t\t/* \n@@ -667,7 +682,7 @@ void sort_in_topological_order(struct co\n \t\t*pptr = work_node->list_item;\n \t\tpptr = &(*pptr)->next;\n \t\t*pptr = NULL;\n-\t\twork_item->object.util = NULL;\n+\t\tsetter(work_item, NULL);\n \t}\n \tfree(nodes);\n }\ndiff --git a/commit.h b/commit.h\nindex 70a7c75..0be61eb 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -76,4 +76,13 @@ int count_parents(struct commit * commit\n  *   sorted in the dates order.\n  */\n void sort_in_topological_order(struct commit_list ** list, int lifo);\n+\n+typedef void (*set_fn_t)(struct commit*, void* data);\n+typedef void* (*get_fn_t)(struct commit*);\n+\n+void default_setter(struct commit* c, void* data);\n+void* default_getter(struct commit* c);\n+\n+void sort_in_topological_order(struct commit_list ** list, int lifo);\n+void sort_in_topological_order_fun(struct commit_list ** list, int lifo, set_fn_t, get_fn_t);\n #endif /* COMMIT_H */\n"},{"id":"17349","messageId":"20060308225939.GC461@c165.ib.student.liu.se","threadId":"3604","inReplyTo":"20060308225412.GA461@c165.ib.student.liu.se","subject":"[PATCH 2/3] rev-lib: Make it easy to do rename tracking","fromName":"Fredrik Kuivinen","fromEmail":"freku045@student.liu.se","sentAt":"2006-03-08T22:59:39Z","receivedAt":"2006-03-08T22:59:39Z","isPatch":true,"sender":{"key":"frekui@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13770967?v=4"},"body":"prune_fn in the rev_info structure is called in place of\ntry_to_simplify_commit. This makes it possible to do rename tracking\nwith a custom try_to_simplify_commit-like function.\n\nThis commit also introduces init_revisions which initialises the rev_info\nstructure with default values.\n\nSigned-off-by: Fredrik Kuivinen <freku045@student.liu.se>\n\n---\n\n rev-list.c |    6 +++---\n revision.c |   59 +++++++++++++++++++++++++++++++++++++----------------------\n revision.h |   20 +++++++++++++++++++-\n 3 files changed, 59 insertions(+), 26 deletions(-)\n\ndiff --git a/rev-list.c b/rev-list.c\nindex 8e4d83e..83a8ec2 100644\n--- a/rev-list.c\n+++ b/rev-list.c\n@@ -190,7 +190,7 @@ static int count_distance(struct commit_\n \n \t\tif (commit->object.flags & (UNINTERESTING | COUNTED))\n \t\t\tbreak;\n-\t\tif (!revs.paths || (commit->object.flags & TREECHANGE))\n+\t\tif (!revs.prune_data || (commit->object.flags & TREECHANGE))\n \t\t\tnr++;\n \t\tcommit->object.flags |= COUNTED;\n \t\tp = commit->parents;\n@@ -224,7 +224,7 @@ static struct commit_list *find_bisectio\n \tnr = 0;\n \tp = list;\n \twhile (p) {\n-\t\tif (!revs.paths || (p->item->object.flags & TREECHANGE))\n+\t\tif (!revs.prune_data || (p->item->object.flags & TREECHANGE))\n \t\t\tnr++;\n \t\tp = p->next;\n \t}\n@@ -234,7 +234,7 @@ static struct commit_list *find_bisectio\n \tfor (p = list; p; p = p->next) {\n \t\tint distance;\n \n-\t\tif (revs.paths && !(p->item->object.flags & TREECHANGE))\n+\t\tif (revs.prune_data && !(p->item->object.flags & TREECHANGE))\n \t\t\tcontinue;\n \n \t\tdistance = count_distance(p);\ndiff --git a/revision.c b/revision.c\nindex 2a33637..991dfe8 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -197,9 +197,6 @@ static int everybody_uninteresting(struc\n \treturn 1;\n }\n \n-#define TREE_SAME\t0\n-#define TREE_NEW\t1\n-#define TREE_DIFFERENT\t2\n static int tree_difference = TREE_SAME;\n \n static void file_add_remove(struct diff_options *options,\n@@ -241,7 +238,7 @@ static struct diff_options diff_opt = {\n \t.change = file_change,\n };\n \n-static int compare_tree(struct tree *t1, struct tree *t2)\n+int compare_tree(struct tree *t1, struct tree *t2)\n {\n \tif (!t1)\n \t\treturn TREE_NEW;\n@@ -253,7 +250,7 @@ static int compare_tree(struct tree *t1,\n \treturn tree_difference;\n }\n \n-static int same_tree_as_empty(struct tree *t1)\n+int same_tree_as_empty(struct tree *t1)\n {\n \tint retval;\n \tvoid *tree;\n@@ -321,6 +318,7 @@ static void try_to_simplify_commit(struc\n \tcommit->object.flags |= TREECHANGE;\n }\n \n+\n static void add_parents_to_list(struct rev_info *revs, struct commit *commit, struct commit_list **list)\n {\n \tstruct commit_list *parent = commit->parents;\n@@ -358,8 +356,11 @@ static void add_parents_to_list(struct r\n \t * simplify the commit history and find the parent\n \t * that has no differences in the path set if one exists.\n \t */\n-\tif (revs->paths)\n+\t/* if (revs->paths)\n \t\ttry_to_simplify_commit(revs, commit);\n+\t*/\n+\tif (revs->prune_fn)\n+\t\trevs->prune_fn(revs, commit);\n \n \tparent = commit->parents;\n \twhile (parent) {\n@@ -381,9 +382,6 @@ static void limit_list(struct rev_info *\n \tstruct commit_list *newlist = NULL;\n \tstruct commit_list **p = &newlist;\n \n-\tif (revs->paths)\n-\t\tdiff_tree_setup_paths(revs->paths);\n-\n \twhile (list) {\n \t\tstruct commit_list *entry = list;\n \t\tstruct commit *commit = list->item;\n@@ -435,6 +433,24 @@ static void handle_all(struct rev_info *\n \tfor_each_ref(handle_one_ref);\n }\n \n+\n+void init_revisions(struct rev_info *revs)\n+{\n+\tmemset(revs, 0, sizeof(*revs));\n+\trevs->lifo = 1;\n+\trevs->dense = 1;\n+\trevs->prefix = setup_git_directory();\n+\trevs->max_age = -1;\n+\trevs->min_age = -1;\n+\trevs->max_count = -1;\n+\n+\trevs->prune_fn = NULL;\n+\trevs->prune_data = NULL;\n+\n+\trevs->topo_setter = default_setter;\n+\trevs->topo_getter = default_getter;\n+}\n+\n /*\n  * Parse revision information, filling in the \"rev_info\" structure,\n  * and removing the used arguments from the argument list.\n@@ -448,14 +464,8 @@ int setup_revisions(int argc, const char\n \tconst char **unrecognized = argv + 1;\n \tint left = 1;\n \n-\tmemset(revs, 0, sizeof(*revs));\n-\trevs->lifo = 1;\n-\trevs->dense = 1;\n-\trevs->prefix = setup_git_directory();\n-\trevs->max_age = -1;\n-\trevs->min_age = -1;\n-\trevs->max_count = -1;\n-\n+\tinit_revisions(revs);\n+\t\n \t/* First, search for \"--\" */\n \tseen_dashdash = 0;\n \tfor (i = 1; i < argc; i++) {\n@@ -464,7 +474,7 @@ int setup_revisions(int argc, const char\n \t\t\tcontinue;\n \t\targv[i] = NULL;\n \t\targc = i;\n-\t\trevs->paths = get_pathspec(revs->prefix, argv + i + 1);\n+\t\trevs->prune_data = get_pathspec(revs->prefix, argv + i + 1);\n \t\tseen_dashdash = 1;\n \t\tbreak;\n \t}\n@@ -628,7 +638,7 @@ int setup_revisions(int argc, const char\n \t\t\t\tif (lstat(argv[j], &st) < 0)\n \t\t\t\t\tdie(\"'%s': %s\", arg, strerror(errno));\n \t\t\t}\n-\t\t\trevs->paths = get_pathspec(revs->prefix, argv + i);\n+\t\t\trevs->prune_data = get_pathspec(revs->prefix, argv + i);\n \t\t\tbreak;\n \t\t}\n \t\tcommit = get_commit_reference(revs, arg, sha1, flags ^ local_flags);\n@@ -642,8 +652,13 @@ int setup_revisions(int argc, const char\n \t\tcommit = get_commit_reference(revs, def, sha1, 0);\n \t\tadd_one_commit(commit, revs);\n \t}\n-\tif (revs->paths)\n+\n+\tif (revs->prune_data) {\n+\t\tdiff_tree_setup_paths(revs->prune_data);\n+\t\trevs->prune_fn = try_to_simplify_commit;\n \t\trevs->limited = 1;\n+\t}\n+\n \treturn left;\n }\n \n@@ -653,7 +668,7 @@ void prepare_revision_walk(struct rev_in\n \tif (revs->limited)\n \t\tlimit_list(revs);\n \tif (revs->topo_order)\n-\t\tsort_in_topological_order(&revs->commits, revs->lifo);\n+\t\tsort_in_topological_order_fun(&revs->commits, revs->lifo, revs->topo_setter, revs->topo_getter);\n }\n \n static int rewrite_one(struct commit **pp)\n@@ -709,7 +724,7 @@ struct commit *get_revision(struct rev_i\n \t\t\treturn NULL;\n \t\tif (revs->no_merges && commit->parents && commit->parents->next)\n \t\t\tgoto next;\n-\t\tif (revs->paths && revs->dense) {\n+\t\tif (revs->prune_fn && revs->dense) {\n \t\t\tif (!(commit->object.flags & TREECHANGE))\n \t\t\t\tgoto next;\n \t\t\trewrite_parents(commit);\ndiff --git a/revision.h b/revision.h\nindex 31e8f61..510d936 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -7,6 +7,10 @@\n #define SHOWN\t\t(1u<<3)\n #define TMP_MARK\t(1u<<4) /* for isolated cases; clean after use */\n \n+struct rev_info;\n+\n+typedef void (prune_fn_t)(struct rev_info *revs, struct commit *commit);\n+\n struct rev_info {\n \t/* Starting list */\n \tstruct commit_list *commits;\n@@ -14,7 +18,9 @@ struct rev_info {\n \n \t/* Basic information */\n \tconst char *prefix;\n-\tconst char **paths;\n+\n+\tvoid* prune_data;\n+\tprune_fn_t* prune_fn;\n \n \t/* Traversal flags */\n \tunsigned int\tdense:1,\n@@ -33,9 +39,21 @@ struct rev_info {\n \tint max_count;\n \tunsigned long max_age;\n \tunsigned long min_age;\n+\n+\tset_fn_t topo_setter;\n+\tget_fn_t topo_getter;\n };\n \n+#define TREE_SAME\t0\n+#define TREE_NEW\t1\n+#define TREE_DIFFERENT\t2\n+\n /* revision.c */\n+extern int same_tree_as_empty(struct tree *t1);\n+extern int compare_tree(struct tree *t1, struct tree *t2);\n+\n+\n+extern void init_revisions(struct rev_info *revs);\n extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def);\n extern void prepare_revision_walk(struct rev_info *revs);\n extern struct commit *get_revision(struct rev_info *revs);\n"},{"id":"17350","messageId":"20060308230001.GD461@c165.ib.student.liu.se","threadId":"3604","inReplyTo":"20060308225412.GA461@c165.ib.student.liu.se","subject":"[PATCH 3/3] blame: Rename detection","fromName":"Fredrik Kuivinen","fromEmail":"freku045@student.liu.se","sentAt":"2006-03-08T23:00:01Z","receivedAt":"2006-03-08T23:00:01Z","isPatch":true,"sender":{"key":"frekui@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13770967?v=4"},"body":"Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>\n\n---\n\nThe output format could certainly be improved. Any suggestions?\n\n blame.c |  239 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----------\n 1 files changed, 199 insertions(+), 40 deletions(-)\n\ndiff --git a/blame.c b/blame.c\nindex 90338af..2cc4c96 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -14,6 +14,7 @@\n #include \"tree.h\"\n #include \"blob.h\"\n #include \"diff.h\"\n+#include \"diffcore.h\"\n #include \"revision.h\"\n \n #define DEBUG 0\n@@ -34,7 +35,9 @@ struct util_info {\n \tchar *buf;\n \tunsigned long size;\n \tint num_lines;\n-//    const char* path;\n+\tconst char* pathname;\n+\n+\tvoid* topo_data;\n };\n \n struct chunk {\n@@ -342,25 +345,34 @@ static int map_line(struct commit *commi\n \treturn info->line_map[line];\n }\n \n-static int fill_util_info(struct commit *commit, const char *path)\n+static struct util_info* get_util(struct commit *commit)\n {\n-\tstruct util_info *util;\n-\tif (commit->object.util)\n-\t\treturn 0;\n+\tstruct util_info *util = commit->object.util;\n+\n+\tif(util)\n+\t\treturn util;\n \n \tutil = xmalloc(sizeof(struct util_info));\n+\tutil->buf = NULL;\n+\tutil->size = 0;\n+\tutil->line_map = NULL;\n+\tutil->num_lines = -1;\n+\tutil->pathname = NULL;\n+\tcommit->object.util = util;\n+\treturn util;\n+}\n+\n+static int fill_util_info(struct commit *commit)\n+{\n+\tstruct util_info *util = commit->object.util;\n \n-\tif (get_blob_sha1(commit->tree, path, util->sha1)) {\n-\t\tfree(util);\n+\tassert(util);\n+\tassert(util->pathname);\n+\t\n+\tif (get_blob_sha1(commit->tree, util->pathname, util->sha1))\n \t\treturn 1;\n-\t} else {\n-\t\tutil->buf = NULL;\n-\t\tutil->size = 0;\n-\t\tutil->line_map = NULL;\n-\t\tutil->num_lines = -1;\n-\t\tcommit->object.util = util;\n+\telse\n \t\treturn 0;\n-\t}\n }\n \n static void alloc_line_map(struct commit *commit)\n@@ -389,10 +401,11 @@ static void alloc_line_map(struct commit\n \n static void init_first_commit(struct commit* commit, const char* filename)\n {\n-\tstruct util_info* util;\n+\tstruct util_info* util = commit->object.util;\n \tint i;\n \n-\tif (fill_util_info(commit, filename))\n+\tutil->pathname = filename;\n+\tif (fill_util_info(commit))\n \t\tdie(\"fill_util_info failed\");\n \n \talloc_line_map(commit);\n@@ -453,7 +466,7 @@ static void process_commits(struct rev_i\n \t\tif(num_parents == 0)\n \t\t\t*initial = commit;\n \n-\t\tif(fill_util_info(commit, path))\n+\t\tif(fill_util_info(commit))\n \t\t\tcontinue;\n \n \t\talloc_line_map(commit);\n@@ -471,7 +484,7 @@ static void process_commits(struct rev_i\n \t\t\t\tprintf(\"parent: %s\\n\",\n \t\t\t\t       sha1_to_hex(parent->object.sha1));\n \n-\t\t\tif(fill_util_info(parent, path)) {\n+\t\t\tif(fill_util_info(parent)) {\n \t\t\t\tnum_parents--;\n \t\t\t\tcontinue;\n \t\t\t}\n@@ -511,6 +524,135 @@ static void process_commits(struct rev_i\n \t} while ((commit = get_revision(rev)) != NULL);\n }\n \n+\n+static int compare_tree_path(struct rev_info* revs,\n+\t\t\t     struct commit* c1, struct commit* c2)\n+{\n+\tconst char* paths[2];\n+\tstruct util_info* util = c2->object.util;\n+\tpaths[0] = util->pathname;\n+\tpaths[1] = NULL;\n+\n+\tdiff_tree_setup_paths(get_pathspec(revs->prefix, paths));\n+\treturn compare_tree(c1->tree, c2->tree);\n+}\n+\n+\n+static int same_tree_as_empty_path(struct rev_info *revs, struct tree* t1,\n+\t\t\t\t   const char* path)\n+{\n+\tconst char* paths[2];\n+\tpaths[0] = path;\n+\tpaths[1] = NULL;\n+\n+\tdiff_tree_setup_paths(get_pathspec(revs->prefix, paths));\n+\treturn same_tree_as_empty(t1);\n+}\n+\n+static const char* find_rename(struct commit* commit, struct commit* parent)\n+{\n+\tstruct util_info* cutil = commit->object.util;\n+\tstruct diff_options diff_opts;\n+\tconst char *paths[1];\n+\tint i;\n+\n+\tif(DEBUG) {\n+\t\tprintf(\"find_rename commit: %s \",\n+\t\t       sha1_to_hex(commit->object.sha1));\n+\t\tputs(sha1_to_hex(parent->object.sha1));\n+\t}\n+\n+\tdiff_setup(&diff_opts);\n+\tdiff_opts.recursive = 1;\n+\tdiff_opts.detect_rename = DIFF_DETECT_RENAME;\n+\tpaths[0] = NULL;\n+\tdiff_tree_setup_paths(paths);\n+\tif(diff_setup_done(&diff_opts) < 0)\n+\t\tdie(\"diff_setup_done failed\");\n+\n+\tdiff_tree_sha1(commit->tree->object.sha1, parent->tree->object.sha1,\n+\t\t       \"\", &diff_opts);\n+\tdiffcore_std(&diff_opts);\n+\n+\tfor(i = 0; i < diff_queued_diff.nr; i++) {\n+\t\tstruct diff_filepair *p = diff_queued_diff.queue[i];\n+\n+\t\tif(p->status == 'R' && !strcmp(p->one->path, cutil->pathname)) {\n+\t\t\tif(DEBUG)\n+\t\t\t\tprintf(\"rename %s -> %s\\n\", p->one->path, p->two->path);\n+\t\t\treturn p->two->path;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void simplify_commit(struct rev_info *revs, struct commit *commit)\n+{\n+\tstruct commit_list **pp, *parent;\n+\n+\tif (!commit->tree)\n+\t\treturn;\n+\n+\tif (!commit->parents) {\n+\t\tstruct util_info* util = commit->object.util;\n+\t\tif (!same_tree_as_empty_path(revs, commit->tree,\n+\t\t\t\t\t     util->pathname))\n+\t\t\tcommit->object.flags |= TREECHANGE;\n+\t\treturn;\n+\t}\n+\n+\tpp = &commit->parents;\n+\twhile ((parent = *pp) != NULL) {\n+\t\tstruct commit *p = parent->item;\n+\n+\t\tif (p->object.flags & UNINTERESTING) {\n+\t\t\tpp = &parent->next;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tparse_commit(p);\n+\t\tswitch (compare_tree_path(revs, p, commit)) {\n+\t\tcase TREE_SAME:\n+\t\t\tparent->next = NULL;\n+\t\t\tcommit->parents = parent;\n+\t\t\tget_util(p)->pathname = get_util(commit)->pathname;\n+\t\t\treturn;\n+\n+\t\tcase TREE_NEW:\n+\t\t{\n+\t\t\t\n+\t\t\tstruct util_info* util = commit->object.util;\n+\t\t\tif (revs->remove_empty_trees &&\n+\t\t\t    same_tree_as_empty_path(revs, p->tree,\n+\t\t\t\t\t\t    util->pathname)) {\n+\t\t\t\tconst char* new_name = find_rename(commit, p);\n+\t\t\t\tif(new_name) {\n+\t\t\t\t\tstruct util_info* putil = get_util(p);\n+\t\t\t\t\tif(!putil->pathname)\n+\t\t\t\t\t\tputil->pathname = strdup(new_name);\n+\t\t\t\t} else {\n+\t\t\t\t\t*pp = parent->next;\n+\t\t\t\t\tcontinue;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* fallthrough */\n+\t\tcase TREE_DIFFERENT:\n+\t\t\tpp = &parent->next;\n+\t\t\tif(!get_util(p)->pathname)\n+\t\t\t\tget_util(p)->pathname =\n+\t\t\t\t\tget_util(commit)->pathname;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tdie(\"bad tree compare for commit %s\",\n+\t\t    sha1_to_hex(commit->object.sha1));\n+\t}\n+\tcommit->object.flags |= TREECHANGE;\n+}\n+\n+\n struct commit_info\n {\n \tchar* author;\n@@ -569,6 +711,18 @@ static const char* format_time(unsigned \n \treturn time_buf;\n }\n \n+static void topo_setter(struct commit* c, void* data)\n+{\n+\tstruct util_info* util = c->object.util;\n+\tutil->topo_data = data;\n+}\n+\n+static void* topo_getter(struct commit* c)\n+{\n+\tstruct util_info* util = c->object.util;\n+\treturn util->topo_data;\n+}\n+\n int main(int argc, const char **argv)\n {\n \tint i;\n@@ -580,8 +734,8 @@ int main(int argc, const char **argv)\n \tint sha1_len = 8;\n \tint compability = 0;\n \tint options = 1;\n+\tstruct commit* start_commit;\n \n-\tint num_args;\n \tconst char* args[10];\n \tstruct rev_info rev;\n \n@@ -634,28 +788,29 @@ int main(int argc, const char **argv)\n \t\tstrcpy(filename_buf, filename);\n \tfilename = filename_buf;\n \n-\t{\n-\t\tstruct commit* c;\n-\t\tif (get_sha1(commit, sha1))\n-\t\t\tdie(\"get_sha1 failed, commit '%s' not found\", commit);\n-\t\tc = lookup_commit_reference(sha1);\n-\n-\t\tif (fill_util_info(c, filename)) {\n-\t\t\tprintf(\"%s not found in %s\\n\", filename, commit);\n-\t\t\treturn 1;\n-\t\t}\n+\tif (get_sha1(commit, sha1))\n+\t\tdie(\"get_sha1 failed, commit '%s' not found\", commit);\t\n+\tstart_commit = lookup_commit_reference(sha1);\n+\tget_util(start_commit)->pathname = filename;\n+\tif (fill_util_info(start_commit)) {\n+\t\tprintf(\"%s not found in %s\\n\", filename, commit);\n+\t\treturn 1;\n \t}\n \n-\tnum_args = 0;\n-\targs[num_args++] = NULL;\n-\targs[num_args++] = \"--topo-order\";\n-\targs[num_args++] = \"--remove-empty\";\n-\targs[num_args++] = commit;\n-\targs[num_args++] = \"--\";\n-\targs[num_args++] = filename;\n-\targs[num_args] = NULL;\n \n-\tsetup_revisions(num_args, args, &rev, \"HEAD\");\n+\tinit_revisions(&rev);\t\n+\trev.remove_empty_trees = 1;\n+\trev.topo_order = 1;\n+\trev.prune_fn = simplify_commit;\n+\trev.topo_setter = topo_setter;\n+\trev.topo_getter = topo_getter;\n+\trev.limited = 1;\n+\n+\tcommit_list_insert(start_commit, &rev.commits);\n+\t\n+\targs[0] = filename;\n+\targs[1] = NULL;\n+\tdiff_tree_setup_paths(args);\n \tprepare_revision_walk(&rev);\n \tprocess_commits(&rev, filename, &initial);\n \n@@ -665,17 +820,21 @@ int main(int argc, const char **argv)\n \n \tfor (i = 0; i < num_blame_lines; i++) {\n \t\tstruct commit *c = blame_lines[i];\n+\t\tstruct util_info* u;\n+\n \t\tif (!c)\n \t\t\tc = initial;\n \n+\t\tu = c->object.util;\n \t\tget_commit_info(c, &ci);\n \t\tfwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout);\n \t\tif(compability)\n \t\t\tprintf(\"\\t(%10s\\t%10s\\t%d)\", ci.author,\n \t\t\t       format_time(ci.author_time, ci.author_tz), i+1);\n \t\telse\n-\t\t\tprintf(\" (%-15.15s %10s %*d) \", ci.author,\n-\t\t\t       format_time(ci.author_time, ci.author_tz),\n+\t\t\tprintf(\" %s (%-15.15s %10s %*d) \", u->pathname,\n+\t\t\t       ci.author, format_time(ci.author_time,\n+\t\t\t\t\t\t      ci.author_tz),\n \t\t\t       max_digits, i+1);\n \n \t\tif(i == num_blame_lines - 1) {\n"},{"id":"17351","messageId":"7v4q28h38p.fsf@assigned-by-dhcp.cox.net","threadId":"3604","inReplyTo":"20060308225412.GA461@c165.ib.student.liu.se","subject":"Re: [PATCH 0/3] Teach git-blame about renames","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-09T00:27:02Z","receivedAt":"2006-03-09T00:27:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fredrik Kuivinen <freku045@student.liu.se> writes:\n\n(from part 1/3)\n\n> +void default_setter(struct commit* c, void* data)\n> +{\n> +\tc->object.util = data;\n> +}\n> +\n> +void* default_getter(struct commit* c)\n> +{\n> +\treturn c->object.util;\n> +}\n> +\n\nThese names are too generic to be used as a global.\n\nThe rest of the git code tends to say \"void *default_getter()\".\n\n(from part 2/3)\n\n> @@ -224,7 +224,7 @@ static struct commit_list *find_bisectio\n>  \tnr = 0;\n>  \tp = list;\n>  \twhile (p) {\n> -\t\tif (!revs.paths || (p->item->object.flags & TREECHANGE))\n> +\t\tif (!revs.prune_data || (p->item->object.flags & TREECHANGE))\n>  \t\t\tnr++;\n>  \t\tp = p->next;\n>  \t}\n\nHere you test with revs.prune_data, but the rest you test with\nrevs.prune_fn.  It is conceivable that some prune_fn could be\nwritten without using prune_data, so I'd suggest to check\nconsistently with prune_fn.\n\n> -static int compare_tree(struct tree *t1, struct tree *t2)\n> +int compare_tree(struct tree *t1, struct tree *t2)\n> ...\n> -static int same_tree_as_empty(struct tree *t1)\n> +int same_tree_as_empty(struct tree *t1)\n\nMaybe the names are a bit too generic to be used as a global?\n\n> -\tif (revs->paths)\n> +\t/* if (revs->paths)\n>  \t\ttry_to_simplify_commit(revs, commit);\n> +\t*/\n\nLeftover commenting.\n\n\n(from part 3/3)\n\n> -\tstruct util_info *util;\n> -\tif (commit->object.util)\n> -\t\treturn 0;\n> +\tstruct util_info *util = commit->object.util;\n> +\n> +\tif(util)\n> +\t\treturn util;\n\nThe rest of the git code tends to say \"if (util)\".\n"},{"id":"17359","messageId":"20060309073014.GA1500@c165.ib.student.liu.se","threadId":"3604","inReplyTo":"7v4q28h38p.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 0/3] Teach git-blame about renames","fromName":"Fredrik Kuivinen","fromEmail":"freku045@student.liu.se","sentAt":"2006-03-09T07:30:14Z","receivedAt":"2006-03-09T07:30:14Z","isPatch":true,"sender":{"key":"frekui@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13770967?v=4"},"body":"On Wed, Mar 08, 2006 at 04:27:02PM -0800, Junio C Hamano wrote:\n> > -static int compare_tree(struct tree *t1, struct tree *t2)\n> > +int compare_tree(struct tree *t1, struct tree *t2)\n> > ...\n> > -static int same_tree_as_empty(struct tree *t1)\n> > +int same_tree_as_empty(struct tree *t1)\n> \n> Maybe the names are a bit too generic to be used as a global?\n> \n\nYes.. maybe. They are quite general though. Any suggestions for better\nnames? We could prefix everything in revision.h with \"rev_\" or\nsomething like that.\n\n\nThanks for the comments. I will send an updated patch series soon.\n\n- Fredrik\n"}]}