Skip to content

Commit 700fd28

Browse files
max630gitster
authored andcommitted
blame: allow blame --reverse --first-parent when it makes sense
Allow combining --reverse and --first-parent if initial commit of specified range is at the first-parent chain starting from the final commit. Disable the prepare_revision_walk()'s builtin children collection, instead picking only the ones which are along the first parent chain. Signed-off-by: Max Kirillov <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 1b0d400 commit 700fd28

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

builtin/blame.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2502,6 +2502,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
25022502
long dashdash_pos, lno;
25032503
char *final_commit_name = NULL;
25042504
enum object_type type;
2505+
struct commit *final_commit = NULL;
25052506

25062507
static struct string_list range_list;
25072508
static int output_option = 0, opt = 0;
@@ -2689,11 +2690,11 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
26892690
}
26902691
else if (contents_from)
26912692
die("--contents and --children do not blend well.");
2692-
else if (revs.first_parent_only)
2693-
die("combining --first-parent and --reverse is not supported");
26942693
else {
26952694
final_commit_name = prepare_initial(&sb);
26962695
sb.commits.compare = compare_commits_by_reverse_commit_date;
2696+
if (revs.first_parent_only)
2697+
revs.children.name = NULL;
26972698
}
26982699

26992700
if (!sb.final) {
@@ -2710,6 +2711,14 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
27102711
else if (contents_from)
27112712
die("Cannot use --contents with final commit object name");
27122713

2714+
if (reverse && revs.first_parent_only) {
2715+
struct object_array_entry *entry = find_single_final(sb.revs);
2716+
if (!entry)
2717+
die("--reverse and --first-parent together require specified latest commit");
2718+
else
2719+
final_commit = (struct commit*) entry->item;
2720+
}
2721+
27132722
/*
27142723
* If we have bottom, this will mark the ancestors of the
27152724
* bottom commits we would reach while traversing as
@@ -2718,6 +2727,25 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
27182727
if (prepare_revision_walk(&revs))
27192728
die(_("revision walk setup failed"));
27202729

2730+
if (reverse && revs.first_parent_only) {
2731+
struct commit *c = final_commit;
2732+
2733+
sb.revs->children.name = "children";
2734+
while (c->parents &&
2735+
hashcmp(c->object.sha1, sb.final->object.sha1)) {
2736+
struct commit_list *l = xcalloc(1, sizeof(*l));
2737+
2738+
l->item = c;
2739+
if (add_decoration(&sb.revs->children,
2740+
&c->parents->item->object, l))
2741+
die("BUG: not unique item in first-parent chain");
2742+
c = c->parents->item;
2743+
}
2744+
2745+
if (hashcmp(c->object.sha1, sb.final->object.sha1))
2746+
die("--reverse --first-parent together require range along first-parent chain");
2747+
}
2748+
27212749
if (is_null_sha1(sb.final->object.sha1)) {
27222750
o = sb.final->util;
27232751
sb.final_buf = xmemdupz(o->file.ptr, o->file.size);

t/t8009-blame-vs-topicbranches.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ test_expect_success setup '
2626
test_merge A3 C1
2727
'
2828

29-
test_expect_failure 'blame --reverse --first-parent finds A1' '
29+
test_expect_success 'blame --reverse --first-parent finds A1' '
3030
git blame --porcelain --reverse --first-parent A0..A3 -- file.t >actual_full &&
3131
head -n 1 <actual_full | sed -e "s/ .*//" >actual &&
3232
git rev-parse A1 >expect &&

0 commit comments

Comments
 (0)