提交 140011d8 编写于 作者: J Junio C Hamano

Merge branch 'jc/maint-blame-no-such-path' into maint

Even during a conflicted merge, "git blame $path" always meant to
blame uncommitted changes to the "working tree" version; make it
more useful by showing cleanly merged parts as coming from the other
branch that is being merged.

This incidentally fixes an unrelated problem on a case insensitive
filesystem, where "git blame MAKEFILE" run in a history that has
"Makefile" but not "MAKEFILE" did not say "No such file MAKEFILE in
HEAD" but pretended as if "MAKEFILE" was a newly added file.

* jc/maint-blame-no-such-path:
  blame: allow "blame file" in the middle of a conflicted merge
  blame $path: avoid getting fooled by case insensitive filesystems
...@@ -2069,6 +2069,55 @@ static int git_blame_config(const char *var, const char *value, void *cb) ...@@ -2069,6 +2069,55 @@ static int git_blame_config(const char *var, const char *value, void *cb)
return git_default_config(var, value, cb); return git_default_config(var, value, cb);
} }
static void verify_working_tree_path(struct commit *work_tree, const char *path)
{
struct commit_list *parents;
for (parents = work_tree->parents; parents; parents = parents->next) {
const unsigned char *commit_sha1 = parents->item->object.sha1;
unsigned char blob_sha1[20];
unsigned mode;
if (!get_tree_entry(commit_sha1, path, blob_sha1, &mode) &&
sha1_object_info(blob_sha1, NULL) == OBJ_BLOB)
return;
}
die("no such path '%s' in HEAD", path);
}
static struct commit_list **append_parent(struct commit_list **tail, const unsigned char *sha1)
{
struct commit *parent;
parent = lookup_commit_reference(sha1);
if (!parent)
die("no such commit %s", sha1_to_hex(sha1));
return &commit_list_insert(parent, tail)->next;
}
static void append_merge_parents(struct commit_list **tail)
{
int merge_head;
const char *merge_head_file = git_path("MERGE_HEAD");
struct strbuf line = STRBUF_INIT;
merge_head = open(merge_head_file, O_RDONLY);
if (merge_head < 0) {
if (errno == ENOENT)
return;
die("cannot open '%s' for reading", merge_head_file);
}
while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
unsigned char sha1[20];
if (line.len < 40 || get_sha1_hex(line.buf, sha1))
die("unknown line in '%s': %s", merge_head_file, line.buf);
tail = append_parent(tail, sha1);
}
close(merge_head);
strbuf_release(&line);
}
/* /*
* Prepare a dummy commit that represents the work tree (or staged) item. * Prepare a dummy commit that represents the work tree (or staged) item.
* Note that annotating work tree item never works in the reverse. * Note that annotating work tree item never works in the reverse.
...@@ -2079,6 +2128,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, ...@@ -2079,6 +2128,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
{ {
struct commit *commit; struct commit *commit;
struct origin *origin; struct origin *origin;
struct commit_list **parent_tail, *parent;
unsigned char head_sha1[20]; unsigned char head_sha1[20];
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
const char *ident; const char *ident;
...@@ -2086,20 +2136,38 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, ...@@ -2086,20 +2136,38 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
int size, len; int size, len;
struct cache_entry *ce; struct cache_entry *ce;
unsigned mode; unsigned mode;
struct strbuf msg = STRBUF_INIT;
if (get_sha1("HEAD", head_sha1))
die("No such ref: HEAD");
time(&now); time(&now);
commit = xcalloc(1, sizeof(*commit)); commit = xcalloc(1, sizeof(*commit));
commit->parents = xcalloc(1, sizeof(*commit->parents));
commit->parents->item = lookup_commit_reference(head_sha1);
commit->object.parsed = 1; commit->object.parsed = 1;
commit->date = now; commit->date = now;
commit->object.type = OBJ_COMMIT; commit->object.type = OBJ_COMMIT;
parent_tail = &commit->parents;
if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL))
die("no such ref: HEAD");
parent_tail = append_parent(parent_tail, head_sha1);
append_merge_parents(parent_tail);
verify_working_tree_path(commit, path);
origin = make_origin(commit, path); origin = make_origin(commit, path);
ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0);
strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n");
for (parent = commit->parents; parent; parent = parent->next)
strbuf_addf(&msg, "parent %s\n",
sha1_to_hex(parent->item->object.sha1));
strbuf_addf(&msg,
"author %s\n"
"committer %s\n\n"
"Version of %s from %s\n",
ident, ident, path,
(!contents_from ? path :
(!strcmp(contents_from, "-") ? "standard input" : contents_from)));
commit->buffer = strbuf_detach(&msg, NULL);
if (!contents_from || strcmp("-", contents_from)) { if (!contents_from || strcmp("-", contents_from)) {
struct stat st; struct stat st;
const char *read_from; const char *read_from;
...@@ -2136,7 +2204,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, ...@@ -2136,7 +2204,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
} }
else { else {
/* Reading from stdin */ /* Reading from stdin */
contents_from = "standard input";
mode = 0; mode = 0;
if (strbuf_read(&buf, 0, 0) < 0) if (strbuf_read(&buf, 0, 0) < 0)
die_errno("failed to read from stdin"); die_errno("failed to read from stdin");
...@@ -2181,16 +2248,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, ...@@ -2181,16 +2248,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
*/ */
cache_tree_invalidate_path(active_cache_tree, path); cache_tree_invalidate_path(active_cache_tree, path);
commit->buffer = xmalloc(400);
ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0);
snprintf(commit->buffer, 400,
"tree 0000000000000000000000000000000000000000\n"
"parent %s\n"
"author %s\n"
"committer %s\n\n"
"Version of %s from %s\n",
sha1_to_hex(head_sha1),
ident, ident, path, contents_from ? contents_from : path);
return commit; return commit;
} }
......
...@@ -66,7 +66,7 @@ test_expect_success \ ...@@ -66,7 +66,7 @@ test_expect_success \
git blame file2 git blame file2
' '
test_expect_success 'blame runs on conflicted file in stages 1,3' ' test_expect_success 'blame does not crash with conflicted file in stages 1,3' '
git blame file1 git blame file1
' '
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册