Skip to content

Commit 140011d

Browse files
committed
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
2 parents 8144049 + 9aeaab6 commit 140011d

File tree

2 files changed

+74
-17
lines changed

2 files changed

+74
-17
lines changed

builtin/blame.c

Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2069,6 +2069,55 @@ static int git_blame_config(const char *var, const char *value, void *cb)
20692069
return git_default_config(var, value, cb);
20702070
}
20712071

2072+
static void verify_working_tree_path(struct commit *work_tree, const char *path)
2073+
{
2074+
struct commit_list *parents;
2075+
2076+
for (parents = work_tree->parents; parents; parents = parents->next) {
2077+
const unsigned char *commit_sha1 = parents->item->object.sha1;
2078+
unsigned char blob_sha1[20];
2079+
unsigned mode;
2080+
2081+
if (!get_tree_entry(commit_sha1, path, blob_sha1, &mode) &&
2082+
sha1_object_info(blob_sha1, NULL) == OBJ_BLOB)
2083+
return;
2084+
}
2085+
die("no such path '%s' in HEAD", path);
2086+
}
2087+
2088+
static struct commit_list **append_parent(struct commit_list **tail, const unsigned char *sha1)
2089+
{
2090+
struct commit *parent;
2091+
2092+
parent = lookup_commit_reference(sha1);
2093+
if (!parent)
2094+
die("no such commit %s", sha1_to_hex(sha1));
2095+
return &commit_list_insert(parent, tail)->next;
2096+
}
2097+
2098+
static void append_merge_parents(struct commit_list **tail)
2099+
{
2100+
int merge_head;
2101+
const char *merge_head_file = git_path("MERGE_HEAD");
2102+
struct strbuf line = STRBUF_INIT;
2103+
2104+
merge_head = open(merge_head_file, O_RDONLY);
2105+
if (merge_head < 0) {
2106+
if (errno == ENOENT)
2107+
return;
2108+
die("cannot open '%s' for reading", merge_head_file);
2109+
}
2110+
2111+
while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
2112+
unsigned char sha1[20];
2113+
if (line.len < 40 || get_sha1_hex(line.buf, sha1))
2114+
die("unknown line in '%s': %s", merge_head_file, line.buf);
2115+
tail = append_parent(tail, sha1);
2116+
}
2117+
close(merge_head);
2118+
strbuf_release(&line);
2119+
}
2120+
20722121
/*
20732122
* Prepare a dummy commit that represents the work tree (or staged) item.
20742123
* Note that annotating work tree item never works in the reverse.
@@ -2079,27 +2128,46 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
20792128
{
20802129
struct commit *commit;
20812130
struct origin *origin;
2131+
struct commit_list **parent_tail, *parent;
20822132
unsigned char head_sha1[20];
20832133
struct strbuf buf = STRBUF_INIT;
20842134
const char *ident;
20852135
time_t now;
20862136
int size, len;
20872137
struct cache_entry *ce;
20882138
unsigned mode;
2089-
2090-
if (get_sha1("HEAD", head_sha1))
2091-
die("No such ref: HEAD");
2139+
struct strbuf msg = STRBUF_INIT;
20922140

20932141
time(&now);
20942142
commit = xcalloc(1, sizeof(*commit));
2095-
commit->parents = xcalloc(1, sizeof(*commit->parents));
2096-
commit->parents->item = lookup_commit_reference(head_sha1);
20972143
commit->object.parsed = 1;
20982144
commit->date = now;
20992145
commit->object.type = OBJ_COMMIT;
2146+
parent_tail = &commit->parents;
2147+
2148+
if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL))
2149+
die("no such ref: HEAD");
2150+
2151+
parent_tail = append_parent(parent_tail, head_sha1);
2152+
append_merge_parents(parent_tail);
2153+
verify_working_tree_path(commit, path);
21002154

21012155
origin = make_origin(commit, path);
21022156

2157+
ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0);
2158+
strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n");
2159+
for (parent = commit->parents; parent; parent = parent->next)
2160+
strbuf_addf(&msg, "parent %s\n",
2161+
sha1_to_hex(parent->item->object.sha1));
2162+
strbuf_addf(&msg,
2163+
"author %s\n"
2164+
"committer %s\n\n"
2165+
"Version of %s from %s\n",
2166+
ident, ident, path,
2167+
(!contents_from ? path :
2168+
(!strcmp(contents_from, "-") ? "standard input" : contents_from)));
2169+
commit->buffer = strbuf_detach(&msg, NULL);
2170+
21032171
if (!contents_from || strcmp("-", contents_from)) {
21042172
struct stat st;
21052173
const char *read_from;
@@ -2136,7 +2204,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
21362204
}
21372205
else {
21382206
/* Reading from stdin */
2139-
contents_from = "standard input";
21402207
mode = 0;
21412208
if (strbuf_read(&buf, 0, 0) < 0)
21422209
die_errno("failed to read from stdin");
@@ -2181,16 +2248,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
21812248
*/
21822249
cache_tree_invalidate_path(active_cache_tree, path);
21832250

2184-
commit->buffer = xmalloc(400);
2185-
ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0);
2186-
snprintf(commit->buffer, 400,
2187-
"tree 0000000000000000000000000000000000000000\n"
2188-
"parent %s\n"
2189-
"author %s\n"
2190-
"committer %s\n\n"
2191-
"Version of %s from %s\n",
2192-
sha1_to_hex(head_sha1),
2193-
ident, ident, path, contents_from ? contents_from : path);
21942251
return commit;
21952252
}
21962253

t/t8004-blame-with-conflicts.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ test_expect_success \
6666
git blame file2
6767
'
6868

69-
test_expect_success 'blame runs on conflicted file in stages 1,3' '
69+
test_expect_success 'blame does not crash with conflicted file in stages 1,3' '
7070
git blame file1
7171
'
7272

0 commit comments

Comments
 (0)