diff options
Diffstat (limited to 'blame.c')
-rw-r--r-- | blame.c | 68 |
1 files changed, 46 insertions, 22 deletions
@@ -3,9 +3,14 @@ #include "object-store.h" #include "cache-tree.h" #include "mergesort.h" +#include "convert.h" #include "diff.h" #include "diffcore.h" +#include "gettext.h" +#include "hex.h" +#include "setup.h" #include "tag.h" +#include "trace2.h" #include "blame.h" #include "alloc.h" #include "commit-slab.h" @@ -176,12 +181,12 @@ static void set_commit_buffer_from_strbuf(struct repository *r, static struct commit *fake_working_tree_commit(struct repository *r, struct diff_options *opt, const char *path, - const char *contents_from) + const char *contents_from, + struct object_id *oid) { struct commit *commit; struct blame_origin *origin; struct commit_list **parent_tail, *parent; - struct object_id head_oid; struct strbuf buf = STRBUF_INIT; const char *ident; time_t now; @@ -197,17 +202,18 @@ static struct commit *fake_working_tree_commit(struct repository *r, commit->date = now; parent_tail = &commit->parents; - if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL)) - die("no such ref: HEAD"); - - parent_tail = append_parent(r, parent_tail, &head_oid); + parent_tail = append_parent(r, parent_tail, oid); append_merge_parents(r, parent_tail); verify_working_tree_path(r, commit, path); origin = make_origin(commit, path); - ident = fmt_ident("Not Committed Yet", "not.committed.yet", - WANT_BLANK_IDENT, NULL, 0); + if (contents_from) + ident = fmt_ident("External file (--contents)", "external.file", + WANT_BLANK_IDENT, NULL, 0); + else + ident = fmt_ident("Not Committed Yet", "not.committed.yet", + WANT_BLANK_IDENT, NULL, 0); strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n"); for (parent = commit->parents; parent; parent = parent->next) strbuf_addf(&msg, "parent %s\n", @@ -1028,8 +1034,9 @@ static void fill_origin_blob(struct diff_options *opt, &o->blob_oid, 1, &file->ptr, &file_size)) ; else - file->ptr = read_object_file(&o->blob_oid, &type, - &file_size); + file->ptr = repo_read_object_file(the_repository, + &o->blob_oid, &type, + &file_size); file->size = file_size; if (!file->ptr) @@ -2429,7 +2436,7 @@ static void pass_blame(struct blame_scoreboard *sb, struct blame_origin *origin, if (sg_origin[i]) continue; - if (parse_commit(p)) + if (repo_parse_commit(the_repository, p)) continue; porigin = find(sb->repo, p, origin, sb->bloom_data); if (!porigin) @@ -2592,7 +2599,7 @@ void assign_blame(struct blame_scoreboard *sb, int opt) * so hold onto it in the meantime. */ blame_origin_incref(suspect); - parse_commit(commit); + repo_parse_commit(the_repository, commit); if (sb->reverse || (!(commit->object.flags & UNINTERESTING) && !(revs->max_age != -1 && commit->date < revs->max_age))) @@ -2771,22 +2778,37 @@ void setup_scoreboard(struct blame_scoreboard *sb, 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) { + if (sb->contents_from || !sb->final) { + struct object_id head_oid, *parent_oid; + /* - * "--not A B -- path" without anything positive; - * do not default to HEAD, but use the working tree - * or "--contents". + * Build a fake commit at the top of the history, when + * (1) "git blame [^A] --path", i.e. with no positive end + * of the history range, in which case we build such + * a fake commit on top of the HEAD to blame in-tree + * modifications. + * (2) "git blame --contents=file [A] -- path", with or + * without positive end of the history range but with + * --contents, in which case we pretend that there is + * a fake commit on top of the positive end (defaulting to + * HEAD) that has the given contents in the path. */ + if (sb->final) { + parent_oid = &sb->final->object.oid; + } else { + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL)) + die("no such ref: HEAD"); + parent_oid = &head_oid; + } + setup_work_tree(); sb->final = fake_working_tree_commit(sb->repo, &sb->revs->diffopt, - sb->path, sb->contents_from); + sb->path, sb->contents_from, + parent_oid); add_pending_object(sb->revs, &(sb->final->object), ":"); } @@ -2838,8 +2860,10 @@ void setup_scoreboard(struct blame_scoreboard *sb, &sb->final_buf_size)) ; else - sb->final_buf = read_object_file(&o->blob_oid, &type, - &sb->final_buf_size); + sb->final_buf = repo_read_object_file(the_repository, + &o->blob_oid, + &type, + &sb->final_buf_size); if (!sb->final_buf) die(_("cannot read blob %s for path %s"), |