Signed-off-by: Jeff Smith <whydo...@gmail.com>
---
 builtin/blame.c | 264 +++++++++++++++++++++++++++++---------------------------
 scoreboard.h    |   1 +
 2 files changed, 140 insertions(+), 125 deletions(-)

diff --git a/builtin/blame.c b/builtin/blame.c
index 0af99e3..3bde5a6 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -731,14 +731,8 @@ static struct commit *find_single_final(struct rev_info 
*revs,
        return found;
 }
 
-static char *prepare_final(struct scoreboard *sb)
-{
-       const char *name;
-       sb->final = find_single_final(sb->revs, &name);
-       return xstrdup_or_null(name);
-}
-
-static const char *dwim_reverse_initial(struct scoreboard *sb)
+static struct commit *dwim_reverse_initial(struct rev_info *revs,
+                                          const char **name_p)
 {
        /*
         * DWIM "git blame --reverse ONE -- PATH" as
@@ -749,11 +743,11 @@ static const char *dwim_reverse_initial(struct scoreboard 
*sb)
        struct commit *head_commit;
        unsigned char head_sha1[20];
 
-       if (sb->revs->pending.nr != 1)
+       if (revs->pending.nr != 1)
                return NULL;
 
        /* Is that sole rev a committish? */
-       obj = sb->revs->pending.objects[0].item;
+       obj = revs->pending.objects[0].item;
        obj = deref_tag(obj, NULL, 0);
        if (obj->type != OBJ_COMMIT)
                return NULL;
@@ -767,17 +761,19 @@ static const char *dwim_reverse_initial(struct scoreboard 
*sb)
 
        /* Turn "ONE" into "ONE..HEAD" then */
        obj->flags |= UNINTERESTING;
-       add_pending_object(sb->revs, &head_commit->object, "HEAD");
+       add_pending_object(revs, &head_commit->object, "HEAD");
 
-       sb->final = (struct commit *)obj;
-       return sb->revs->pending.objects[0].name;
+       if (name_p)
+               *name_p = revs->pending.objects[0].name;
+       return (struct commit *)obj;
 }
 
-static char *prepare_initial(struct scoreboard *sb)
+static struct commit *find_single_initial(struct rev_info *revs,
+                                         const char **name_p)
 {
        int i;
-       const char *final_commit_name = NULL;
-       struct rev_info *revs = sb->revs;
+       struct commit *found = NULL;
+       const char *name = NULL;
 
        /*
         * There must be one and only one negative commit, and it must be
@@ -790,19 +786,127 @@ static char *prepare_initial(struct scoreboard *sb)
                obj = deref_tag(obj, NULL, 0);
                if (obj->type != OBJ_COMMIT)
                        die("Non commit %s?", revs->pending.objects[i].name);
-               if (sb->final)
+               if (found)
                        die("More than one commit to dig up from, %s and %s?",
-                           revs->pending.objects[i].name,
-                           final_commit_name);
-               sb->final = (struct commit *) obj;
-               final_commit_name = revs->pending.objects[i].name;
+                           revs->pending.objects[i].name, name);
+               found = (struct commit *) obj;
+               name = revs->pending.objects[i].name;
        }
 
-       if (!final_commit_name)
-               final_commit_name = dwim_reverse_initial(sb);
-       if (!final_commit_name)
+       if (!name)
+               found = dwim_reverse_initial(revs, &name);
+       if (!name)
                die("No commit to dig up from?");
-       return xstrdup(final_commit_name);
+
+       if (name_p)
+               *name_p = name;
+       return found;
+}
+
+void init_scoreboard(struct scoreboard *sb)
+{
+       memset(sb, 0, sizeof(struct scoreboard));
+       sb->blame_move_score = BLAME_DEFAULT_MOVE_SCORE;
+       sb->blame_copy_score = BLAME_DEFAULT_COPY_SCORE;
+}
+
+void setup_scoreboard(struct scoreboard *sb, const char *path, struct origin 
**orig)
+{
+       const char *final_commit_name = NULL;
+       struct origin *o;
+       struct commit *final_commit = NULL;
+       enum object_type type;
+
+       if (sb->reverse && sb->contents_from)
+               die(_("--contents and --reverse do not blend well."));
+
+       if (!sb->reverse) {
+               sb->final = find_single_final(sb->revs, &final_commit_name);
+               sb->commits.compare = compare_commits_by_commit_date;
+       } else {
+               sb->final = find_single_initial(sb->revs, &final_commit_name);
+               sb->commits.compare = compare_commits_by_reverse_commit_date;
+       }
+
+       if (sb->final && sb->contents_from)
+               die(_("cannot use --contents with final commit object name"));
+
+       if (sb->reverse && sb->revs->first_parent_only)
+               sb->revs->children.name = NULL;
+
+       if (!sb->final) {
+               /*
+                * "--not A B -- path" without anything positive;
+                * do not default to HEAD, but use the working tree
+                * or "--contents".
+                */
+               setup_work_tree();
+               sb->final = fake_working_tree_commit(&sb->revs->diffopt,
+                                                    path, sb->contents_from);
+               add_pending_object(sb->revs, &(sb->final->object), ":");
+       }
+
+       if (sb->reverse && sb->revs->first_parent_only) {
+               final_commit = find_single_final(sb->revs, NULL);
+               if (!final_commit)
+                       die(_("--reverse and --first-parent together require 
specified latest commit"));
+       }
+
+       /*
+        * If we have bottom, this will mark the ancestors of the
+        * bottom commits we would reach while traversing as
+        * uninteresting.
+        */
+       if (prepare_revision_walk(sb->revs))
+               die(_("revision walk setup failed"));
+
+       if (sb->reverse && sb->revs->first_parent_only) {
+               struct commit *c = final_commit;
+
+               sb->revs->children.name = "children";
+               while (c->parents &&
+                      oidcmp(&c->object.oid, &sb->final->object.oid)) {
+                       struct commit_list *l = xcalloc(1, sizeof(*l));
+
+                       l->item = c;
+                       if (add_decoration(&sb->revs->children,
+                                          &c->parents->item->object, l))
+                               die("BUG: not unique item in first-parent 
chain");
+                       c = c->parents->item;
+               }
+
+               if (oidcmp(&c->object.oid, &sb->final->object.oid))
+                       die(_("--reverse --first-parent together require range 
along first-parent chain"));
+       }
+
+       if (is_null_oid(&sb->final->object.oid)) {
+               o = sb->final->util;
+               sb->final_buf = xmemdupz(o->file.ptr, o->file.size);
+               sb->final_buf_size = o->file.size;
+       }
+       else {
+               o = get_origin(sb->final, path);
+               if (fill_blob_sha1_and_mode(o))
+                       die(_("no such path %s in %s"), path, 
final_commit_name);
+
+               if (DIFF_OPT_TST(&sb->revs->diffopt, ALLOW_TEXTCONV) &&
+                   textconv_object(path, o->mode, &o->blob_oid, 1, (char **) 
&sb->final_buf,
+                                   &sb->final_buf_size))
+                       ;
+               else
+                       sb->final_buf = read_sha1_file(o->blob_oid.hash, &type,
+                                                      &sb->final_buf_size);
+
+               if (!sb->final_buf)
+                       die(_("cannot read blob %s for path %s"),
+                           oid_to_hex(&o->blob_oid),
+                           path);
+       }
+       sb->num_read_blob++;
+       prepare_lines(sb);
+
+       if (orig)
+               *orig = o;
 }
 
 static int blame_copy_callback(const struct option *option, const char *arg, 
int unset)
@@ -846,9 +950,6 @@ int cmd_blame(int argc, const char **argv, const char 
*prefix)
        struct origin *o;
        struct blame_entry *ent = NULL;
        long dashdash_pos, lno;
-       char *final_commit_name = NULL;
-       enum object_type type;
-       struct commit *final_commit = NULL;
        struct progress_info pi = { NULL, 0 };
 
        struct string_list range_list = STRING_LIST_INIT_NODUP;
@@ -996,11 +1097,6 @@ int cmd_blame(int argc, const char **argv, const char 
*prefix)
                opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE |
                        PICKAXE_BLAME_COPY_HARDER);
 
-       if (!blame_move_score)
-               blame_move_score = BLAME_DEFAULT_MOVE_SCORE;
-       if (!blame_copy_score)
-               blame_copy_score = BLAME_DEFAULT_COPY_SCORE;
-
        /*
         * We have collected options unknown to us in argv[1..unk]
         * which are to be passed to revision machinery if we are
@@ -1053,94 +1149,14 @@ int cmd_blame(int argc, const char **argv, const char 
*prefix)
 
        revs.disable_stdin = 1;
        setup_revisions(argc, argv, &revs, NULL);
-       memset(&sb, 0, sizeof(sb));
 
+       init_scoreboard(&sb);
        sb.revs = &revs;
-       if (!reverse) {
-               final_commit_name = prepare_final(&sb);
-               sb.commits.compare = compare_commits_by_commit_date;
-       }
-       else if (contents_from)
-               die(_("--contents and --reverse do not blend well."));
-       else {
-               final_commit_name = prepare_initial(&sb);
-               sb.commits.compare = compare_commits_by_reverse_commit_date;
-               if (revs.first_parent_only)
-                       revs.children.name = NULL;
-       }
-
-       if (!sb.final) {
-               /*
-                * "--not A B -- path" without anything positive;
-                * do not default to HEAD, but use the working tree
-                * or "--contents".
-                */
-               setup_work_tree();
-               sb.final = fake_working_tree_commit(&sb.revs->diffopt,
-                                                   path, contents_from);
-               add_pending_object(&revs, &(sb.final->object), ":");
-       }
-       else if (contents_from)
-               die(_("cannot use --contents with final commit object name"));
-
-       if (reverse && revs.first_parent_only) {
-               final_commit = find_single_final(sb.revs, NULL);
-               if (!final_commit)
-                       die(_("--reverse and --first-parent together require 
specified latest commit"));
-       }
-
-       /*
-        * If we have bottom, this will mark the ancestors of the
-        * bottom commits we would reach while traversing as
-        * uninteresting.
-        */
-       if (prepare_revision_walk(&revs))
-               die(_("revision walk setup failed"));
-
-       if (reverse && revs.first_parent_only) {
-               struct commit *c = final_commit;
-
-               sb.revs->children.name = "children";
-               while (c->parents &&
-                      oidcmp(&c->object.oid, &sb.final->object.oid)) {
-                       struct commit_list *l = xcalloc(1, sizeof(*l));
-
-                       l->item = c;
-                       if (add_decoration(&sb.revs->children,
-                                          &c->parents->item->object, l))
-                               die("BUG: not unique item in first-parent 
chain");
-                       c = c->parents->item;
-               }
-
-               if (oidcmp(&c->object.oid, &sb.final->object.oid))
-                       die(_("--reverse --first-parent together require range 
along first-parent chain"));
-       }
-
-       if (is_null_oid(&sb.final->object.oid)) {
-               o = sb.final->util;
-               sb.final_buf = xmemdupz(o->file.ptr, o->file.size);
-               sb.final_buf_size = o->file.size;
-       }
-       else {
-               o = get_origin(sb.final, path);
-               if (fill_blob_sha1_and_mode(o))
-                       die(_("no such path %s in %s"), path, 
final_commit_name);
+       sb.reverse = reverse;
+       sb.contents_from = contents_from;
+       setup_scoreboard(&sb, path, &o);
 
-               if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) &&
-                   textconv_object(path, o->mode, &o->blob_oid, 1, (char **) 
&sb.final_buf,
-                                   &sb.final_buf_size))
-                       ;
-               else
-                       sb.final_buf = read_sha1_file(o->blob_oid.hash, &type,
-                                                     &sb.final_buf_size);
-
-               if (!sb.final_buf)
-                       die(_("cannot read blob %s for path %s"),
-                           oid_to_hex(&o->blob_oid),
-                           path);
-       }
-       sb.num_read_blob++;
-       lno = prepare_lines(&sb);
+       lno = sb.num_lines;
 
        if (lno && !range_list.nr)
                string_list_append(&range_list, "1");
@@ -1192,13 +1208,14 @@ int cmd_blame(int argc, const char **argv, const char 
*prefix)
        sb.ent = NULL;
        sb.path = path;
 
-       sb.blame_move_score = blame_move_score;
-       sb.blame_copy_score = blame_copy_score;
+       if (blame_move_score)
+               sb.blame_move_score = blame_move_score;
+       if (blame_copy_score)
+               sb.blame_copy_score = blame_copy_score;
 
        sb.sanity_check = DEBUG ? &sanity_check_refcnt : NULL;
 
        sb.show_root = show_root;
-       sb.reverse = reverse;
        sb.xdl_opts = xdl_opts;
        sb.no_whole_file_rename = no_whole_file_rename;
 
@@ -1216,10 +1233,7 @@ int cmd_blame(int argc, const char **argv, const char 
*prefix)
 
        if (!incremental)
                setup_pager();
-
-       free(final_commit_name);
-
-       if (incremental)
+       else
                return 0;
 
        blame_sort_final(&sb);
diff --git a/scoreboard.h b/scoreboard.h
index 7e9e313..42d9aac 100644
--- a/scoreboard.h
+++ b/scoreboard.h
@@ -24,6 +24,7 @@ struct scoreboard {
        struct prio_queue commits;
        struct rev_info *revs;
        const char *path;
+       const char *contents_from;
 
        /*
         * The contents in the final image.
-- 
2.9.3

Reply via email to