diff options
Diffstat (limited to 'blame.c')
-rw-r--r-- | blame.c | 211 |
1 files changed, 122 insertions, 89 deletions
@@ -1,11 +1,31 @@ #include "cache.h" #include "refs.h" +#include "object-store.h" #include "cache-tree.h" #include "mergesort.h" #include "diff.h" #include "diffcore.h" #include "tag.h" #include "blame.h" +#include "alloc.h" +#include "commit-slab.h" + +define_commit_slab(blame_suspects, struct blame_origin *); +static struct blame_suspects blame_suspects; + +struct blame_origin *get_blame_suspects(struct commit *commit) +{ + struct blame_origin **result; + + result = blame_suspects_peek(&blame_suspects, commit); + + return result ? *result : NULL; +} + +static void set_blame_suspects(struct commit *commit, struct blame_origin *origin) +{ + *blame_suspects_at(&blame_suspects, commit) = origin; +} void blame_origin_decref(struct blame_origin *o) { @@ -15,12 +35,12 @@ void blame_origin_decref(struct blame_origin *o) blame_origin_decref(o->previous); free(o->file.ptr); /* Should be present exactly once in commit chain */ - for (p = o->commit->util; p; l = p, p = p->next) { + for (p = get_blame_suspects(o->commit); p; l = p, p = p->next) { if (p == o) { if (l) l->next = p->next; else - o->commit->util = p->next; + set_blame_suspects(o->commit, p->next); free(o); return; } @@ -41,8 +61,8 @@ static struct blame_origin *make_origin(struct commit *commit, const char *path) FLEX_ALLOC_STR(o, path, path); o->commit = commit; o->refcnt = 1; - o->next = commit->util; - commit->util = o; + o->next = get_blame_suspects(commit); + set_blame_suspects(commit, o); return o; } @@ -54,13 +74,13 @@ static struct blame_origin *get_origin(struct commit *commit, const char *path) { struct blame_origin *o, *l; - for (o = commit->util, l = NULL; o; l = o, o = o->next) { + for (o = get_blame_suspects(commit), l = NULL; o; l = o, o = o->next) { if (!strcmp(o->path, path)) { /* bump to front */ if (l) { l->next = o->next; - o->next = commit->util; - commit->util = o; + o->next = get_blame_suspects(commit); + set_blame_suspects(commit, o); } return blame_origin_incref(o); } @@ -70,7 +90,8 @@ static struct blame_origin *get_origin(struct commit *commit, const char *path) -static void verify_working_tree_path(struct commit *work_tree, const char *path) +static void verify_working_tree_path(struct repository *repo, + struct commit *work_tree, const char *path) { struct commit_list *parents; int pos; @@ -80,16 +101,16 @@ static void verify_working_tree_path(struct commit *work_tree, const char *path) struct object_id blob_oid; unsigned mode; - if (!get_tree_entry(commit_oid->hash, path, blob_oid.hash, &mode) && - sha1_object_info(blob_oid.hash, NULL) == OBJ_BLOB) + if (!get_tree_entry(commit_oid, path, &blob_oid, &mode) && + oid_object_info(repo, &blob_oid, NULL) == OBJ_BLOB) return; } - pos = cache_name_pos(path, strlen(path)); + pos = index_name_pos(repo->index, path, strlen(path)); if (pos >= 0) ; /* path is in the index */ - else if (-1 - pos < active_nr && - !strcmp(active_cache[-1 - pos]->name, path)) + else if (-1 - pos < repo->index->cache_nr && + !strcmp(repo->index->cache[-1 - pos]->name, path)) ; /* path is in the index, unmerged */ else die("no such path '%s' in HEAD", path); @@ -99,7 +120,7 @@ static struct commit_list **append_parent(struct commit_list **tail, const struc { struct commit *parent; - parent = lookup_commit_reference(oid); + parent = lookup_commit_reference(the_repository, oid); if (!parent) die("no such commit %s", oid_to_hex(oid)); return &commit_list_insert(parent, tail)->next; @@ -110,17 +131,19 @@ static void append_merge_parents(struct commit_list **tail) int merge_head; struct strbuf line = STRBUF_INIT; - merge_head = open(git_path_merge_head(), O_RDONLY); + merge_head = open(git_path_merge_head(the_repository), O_RDONLY); if (merge_head < 0) { if (errno == ENOENT) return; - die("cannot open '%s' for reading", git_path_merge_head()); + die("cannot open '%s' for reading", + git_path_merge_head(the_repository)); } while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) { struct object_id oid; if (line.len < GIT_SHA1_HEXSZ || get_oid_hex(line.buf, &oid)) - die("unknown line in '%s': %s", git_path_merge_head(), line.buf); + die("unknown line in '%s': %s", + git_path_merge_head(the_repository), line.buf); tail = append_parent(tail, &oid); } close(merge_head); @@ -136,14 +159,15 @@ static void set_commit_buffer_from_strbuf(struct commit *c, struct strbuf *sb) { size_t len; void *buf = strbuf_detach(sb, &len); - set_commit_buffer(c, buf, len); + set_commit_buffer(the_repository, c, buf, len); } /* * Prepare a dummy commit that represents the work tree (or staged) item. * Note that annotating work tree item never works in the reverse. */ -static struct commit *fake_working_tree_commit(struct diff_options *opt, +static struct commit *fake_working_tree_commit(struct repository *repo, + struct diff_options *opt, const char *path, const char *contents_from) { @@ -154,24 +178,24 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, struct strbuf buf = STRBUF_INIT; const char *ident; time_t now; - int size, len; + int len; struct cache_entry *ce; unsigned mode; struct strbuf msg = STRBUF_INIT; - read_cache(); + read_index(repo->index); time(&now); - commit = alloc_commit_node(); + commit = alloc_commit_node(the_repository); commit->object.parsed = 1; commit->date = now; parent_tail = &commit->parents; - if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL)) + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL)) die("no such ref: HEAD"); parent_tail = append_parent(parent_tail, &head_oid); append_merge_parents(parent_tail); - verify_working_tree_path(commit, path); + verify_working_tree_path(repo, commit, path); origin = make_origin(commit, path); @@ -209,7 +233,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, switch (st.st_mode & S_IFMT) { case S_IFREG: - if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) && + if (opt->flags.allow_textconv && textconv_object(read_from, mode, &null_oid, 0, &buf_ptr, &buf_len)) strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1); else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size) @@ -229,10 +253,10 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, if (strbuf_read(&buf, 0, 0) < 0) die_errno("failed to read from stdin"); } - convert_to_git(&the_index, path, buf.buf, buf.len, &buf, 0); + convert_to_git(repo->index, path, buf.buf, buf.len, &buf, 0); origin->file.ptr = buf.buf; origin->file.size = buf.len; - pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_oid.hash); + pretend_object_file(buf.buf, buf.len, OBJ_BLOB, &origin->blob_oid); /* * Read the current index, replace the path entry with @@ -240,28 +264,28 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, * bits; we are not going to write this index out -- we just * want to run "diff-index --cached". */ - discard_cache(); - read_cache(); + discard_index(repo->index); + read_index(repo->index); len = strlen(path); if (!mode) { - int pos = cache_name_pos(path, len); + int pos = index_name_pos(repo->index, path, len); if (0 <= pos) - mode = active_cache[pos]->ce_mode; + mode = repo->index->cache[pos]->ce_mode; else /* Let's not bother reading from HEAD tree */ mode = S_IFREG | 0644; } - size = cache_entry_size(len); - ce = xcalloc(1, size); + ce = make_empty_cache_entry(repo->index, len); oidcpy(&ce->oid, &origin->blob_oid); memcpy(ce->name, path, len); ce->ce_flags = create_ce_flags(0); ce->ce_namelen = len; ce->ce_mode = create_ce_mode(mode); - add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); + add_index_entry(repo->index, ce, + ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE); - cache_tree_invalidate_path(&the_index, path); + cache_tree_invalidate_path(repo->index, path); return commit; } @@ -293,12 +317,12 @@ static void fill_origin_blob(struct diff_options *opt, unsigned long file_size; (*num_read_blob)++; - if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) && + if (opt->flags.allow_textconv && textconv_object(o->path, o->mode, &o->blob_oid, 1, &file->ptr, &file_size)) ; else - file->ptr = read_sha1_file(o->blob_oid.hash, &type, - &file_size); + file->ptr = read_object_file(&o->blob_oid, &type, + &file_size); file->size = file_size; if (!file->ptr) @@ -478,7 +502,7 @@ static void queue_blames(struct blame_scoreboard *sb, struct blame_origin *porig porigin->suspects = blame_merge(porigin->suspects, sorted); else { struct blame_origin *o; - for (o = porigin->commit->util; o; o = o->next) { + for (o = get_blame_suspects(porigin->commit); o; o = o->next) { if (o->suspects) { porigin->suspects = sorted; return; @@ -498,15 +522,14 @@ static void queue_blames(struct blame_scoreboard *sb, struct blame_origin *porig * * This also fills origin->mode for corresponding tree path. */ -static int fill_blob_sha1_and_mode(struct blame_origin *origin) +static int fill_blob_sha1_and_mode(struct repository *repo, + struct blame_origin *origin) { if (!is_null_oid(&origin->blob_oid)) return 0; - if (get_tree_entry(origin->commit->object.oid.hash, - origin->path, - origin->blob_oid.hash, &origin->mode)) + if (get_tree_entry(&origin->commit->object.oid, origin->path, &origin->blob_oid, &origin->mode)) goto error_out; - if (sha1_object_info(origin->blob_oid.hash, NULL) != OBJ_BLOB) + if (oid_object_info(repo, &origin->blob_oid, NULL) != OBJ_BLOB) goto error_out; return 0; error_out: @@ -527,7 +550,7 @@ static struct blame_origin *find_origin(struct commit *parent, const char *paths[2]; /* First check any existing origins */ - for (porigin = parent->util; porigin; porigin = porigin->next) + for (porigin = get_blame_suspects(parent); porigin; porigin = porigin->next) if (!strcmp(porigin->path, origin->path)) { /* * The same path between origin and its parent @@ -541,7 +564,7 @@ static struct blame_origin *find_origin(struct commit *parent, * same and diff-tree is fairly efficient about this. */ diff_setup(&diff_opts); - DIFF_OPT_SET(&diff_opts, RECURSIVE); + diff_opts.flags.recursive = 1; diff_opts.detect_rename = 0; diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; paths[0] = origin->path; @@ -553,10 +576,10 @@ static struct blame_origin *find_origin(struct commit *parent, diff_setup_done(&diff_opts); if (is_null_oid(&origin->commit->object.oid)) - do_diff_cache(&parent->tree->object.oid, &diff_opts); + do_diff_cache(get_commit_tree_oid(parent), &diff_opts); else - diff_tree_oid(&parent->tree->object.oid, - &origin->commit->tree->object.oid, + diff_tree_oid(get_commit_tree_oid(parent), + get_commit_tree_oid(origin->commit), "", &diff_opts); diffcore_std(&diff_opts); @@ -615,17 +638,17 @@ static struct blame_origin *find_rename(struct commit *parent, int i; diff_setup(&diff_opts); - DIFF_OPT_SET(&diff_opts, RECURSIVE); + diff_opts.flags.recursive = 1; diff_opts.detect_rename = DIFF_DETECT_RENAME; diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; diff_opts.single_follow = origin->path; diff_setup_done(&diff_opts); if (is_null_oid(&origin->commit->object.oid)) - do_diff_cache(&parent->tree->object.oid, &diff_opts); + do_diff_cache(get_commit_tree_oid(parent), &diff_opts); else - diff_tree_oid(&parent->tree->object.oid, - &origin->commit->tree->object.oid, + diff_tree_oid(get_commit_tree_oid(parent), + get_commit_tree_oid(origin->commit), "", &diff_opts); diffcore_std(&diff_opts); @@ -998,28 +1021,29 @@ unsigned blame_entry_score(struct blame_scoreboard *sb, struct blame_entry *e) } /* - * best_so_far[] and this[] are both a split of an existing blame_entry - * that passes blame to the parent. Maintain best_so_far the best split - * so far, by comparing this and best_so_far and copying this into + * best_so_far[] and potential[] are both a split of an existing blame_entry + * that passes blame to the parent. Maintain best_so_far the best split so + * far, by comparing potential and best_so_far and copying potential into * bst_so_far as needed. */ static void copy_split_if_better(struct blame_scoreboard *sb, struct blame_entry *best_so_far, - struct blame_entry *this) + struct blame_entry *potential) { int i; - if (!this[1].suspect) + if (!potential[1].suspect) return; if (best_so_far[1].suspect) { - if (blame_entry_score(sb, &this[1]) < blame_entry_score(sb, &best_so_far[1])) + if (blame_entry_score(sb, &potential[1]) < + blame_entry_score(sb, &best_so_far[1])) return; } for (i = 0; i < 3; i++) - blame_origin_incref(this[i].suspect); + blame_origin_incref(potential[i].suspect); decref_split(best_so_far); - memcpy(best_so_far, this, sizeof(struct blame_entry [3])); + memcpy(best_so_far, potential, sizeof(struct blame_entry[3])); } /* @@ -1046,12 +1070,12 @@ static void handle_split(struct blame_scoreboard *sb, if (ent->num_lines <= tlno) return; if (tlno < same) { - struct blame_entry this[3]; + struct blame_entry potential[3]; tlno += ent->s_lno; same += ent->s_lno; - split_overlap(this, ent, tlno, plno, same, parent); - copy_split_if_better(sb, split, this); - decref_split(this); + split_overlap(potential, ent, tlno, plno, same, parent); + copy_split_if_better(sb, split, potential); + decref_split(potential); } } @@ -1238,7 +1262,7 @@ static void find_copy_in_parent(struct blame_scoreboard *sb, return; /* nothing remains for this target */ diff_setup(&diff_opts); - DIFF_OPT_SET(&diff_opts, RECURSIVE); + diff_opts.flags.recursive = 1; diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; diff_setup_done(&diff_opts); @@ -1253,16 +1277,16 @@ static void find_copy_in_parent(struct blame_scoreboard *sb, if ((opt & PICKAXE_BLAME_COPY_HARDEST) || ((opt & PICKAXE_BLAME_COPY_HARDER) && (!porigin || strcmp(target->path, porigin->path)))) - DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER); + diff_opts.flags.find_copies_harder = 1; if (is_null_oid(&target->commit->object.oid)) - do_diff_cache(&parent->tree->object.oid, &diff_opts); + do_diff_cache(get_commit_tree_oid(parent), &diff_opts); else - diff_tree_oid(&parent->tree->object.oid, - &target->commit->tree->object.oid, + diff_tree_oid(get_commit_tree_oid(parent), + get_commit_tree_oid(target->commit), "", &diff_opts); - if (!DIFF_OPT_TST(&diff_opts, FIND_COPIES_HARDER)) + if (!diff_opts.flags.find_copies_harder) diffcore_std(&diff_opts); do { @@ -1273,7 +1297,7 @@ static void find_copy_in_parent(struct blame_scoreboard *sb, struct diff_filepair *p = diff_queued_diff.queue[i]; struct blame_origin *norigin; mmfile_t file_p; - struct blame_entry this[3]; + struct blame_entry potential[3]; if (!DIFF_FILE_VALID(p->one)) continue; /* does not exist in parent */ @@ -1292,10 +1316,10 @@ static void find_copy_in_parent(struct blame_scoreboard *sb, for (j = 0; j < num_ents; j++) { find_copy_in_blob(sb, blame_list[j].ent, - norigin, this, &file_p); + norigin, potential, &file_p); copy_split_if_better(sb, blame_list[j].split, - this); - decref_split(this); + potential); + decref_split(potential); } blame_origin_decref(norigin); } @@ -1551,7 +1575,7 @@ void assign_blame(struct blame_scoreboard *sb, int opt) while (commit) { struct blame_entry *ent; - struct blame_origin *suspect = commit->util; + struct blame_origin *suspect = get_blame_suspects(commit); /* find one suspect to break down */ while (suspect && !suspect->suspects) @@ -1653,7 +1677,7 @@ static struct commit *find_single_final(struct rev_info *revs, struct object *obj = revs->pending.objects[i].item; if (obj->flags & UNINTERESTING) continue; - obj = deref_tag(obj, NULL, 0); + obj = deref_tag(the_repository, obj, NULL, 0); if (obj->type != OBJ_COMMIT) die("Non commit %s?", revs->pending.objects[i].name); if (found) @@ -1684,14 +1708,15 @@ static struct commit *dwim_reverse_initial(struct rev_info *revs, /* Is that sole rev a committish? */ obj = revs->pending.objects[0].item; - obj = deref_tag(obj, NULL, 0); + obj = deref_tag(the_repository, obj, NULL, 0); if (obj->type != OBJ_COMMIT) return NULL; /* Do we have HEAD? */ - if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL)) + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL)) return NULL; - head_commit = lookup_commit_reference_gently(&head_oid, 1); + head_commit = lookup_commit_reference_gently(the_repository, + &head_oid, 1); if (!head_commit) return NULL; @@ -1719,7 +1744,7 @@ static struct commit *find_single_initial(struct rev_info *revs, struct object *obj = revs->pending.objects[i].item; if (!(obj->flags & UNINTERESTING)) continue; - obj = deref_tag(obj, NULL, 0); + obj = deref_tag(the_repository, obj, NULL, 0); if (obj->type != OBJ_COMMIT) die("Non commit %s?", revs->pending.objects[i].name); if (found) @@ -1746,16 +1771,23 @@ void init_scoreboard(struct blame_scoreboard *sb) sb->copy_score = BLAME_DEFAULT_COPY_SCORE; } -void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blame_origin **orig) +void setup_scoreboard(struct blame_scoreboard *sb, + const char *path, + struct blame_origin **orig) { const char *final_commit_name = NULL; struct blame_origin *o; struct commit *final_commit = NULL; enum object_type type; + init_blame_suspects(&blame_suspects); + if (sb->reverse && sb->contents_from) die(_("--contents and --reverse do not blend well.")); + if (!sb->repo) + BUG("repo is NULL"); + if (!sb->reverse) { sb->final = find_single_final(sb->revs, &final_commit_name); sb->commits.compare = compare_commits_by_commit_date; @@ -1777,7 +1809,8 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam * or "--contents". */ setup_work_tree(); - sb->final = fake_working_tree_commit(&sb->revs->diffopt, + sb->final = fake_working_tree_commit(sb->repo, + &sb->revs->diffopt, path, sb->contents_from); add_pending_object(sb->revs, &(sb->final->object), ":"); } @@ -1807,7 +1840,7 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam l->item = c; if (add_decoration(&sb->revs->children, &c->parents->item->object, l)) - die("BUG: not unique item in first-parent chain"); + BUG("not unique item in first-parent chain"); c = c->parents->item; } @@ -1816,22 +1849,22 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam } if (is_null_oid(&sb->final->object.oid)) { - o = sb->final->util; + o = get_blame_suspects(sb->final); 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)) + if (fill_blob_sha1_and_mode(sb->repo, o)) die(_("no such path %s in %s"), path, final_commit_name); - if (DIFF_OPT_TST(&sb->revs->diffopt, ALLOW_TEXTCONV) && + if (sb->revs->diffopt.flags.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); + sb->final_buf = read_object_file(&o->blob_oid, &type, + &sb->final_buf_size); if (!sb->final_buf) die(_("cannot read blob %s for path %s"), |