Skip to content

Commit d1a8e9c

Browse files
committed
Merge branch 'jc/blame-reverse' into next
It is a common mistake to say "git blame --reverse OLD path", expecting that the command line is dwimmed as if asking how lines in path in an old revision OLD have survived up to the current commit. Has been waiting for positive responses without seeing any. * jc/blame-reverse: blame: dwim "blame --reverse OLD" as "blame --reverse OLD.." blame: improve diagnosis for "--reverse NEW"
2 parents 8310c42 + e1d0970 commit d1a8e9c

File tree

3 files changed

+44
-5
lines changed

3 files changed

+44
-5
lines changed

Documentation/blame-options.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,13 @@ include::line-range-format.txt[]
2828
-S <revs-file>::
2929
Use revisions from revs-file instead of calling linkgit:git-rev-list[1].
3030

31-
--reverse::
31+
--reverse <rev>..<rev>::
3232
Walk history forward instead of backward. Instead of showing
3333
the revision in which a line appeared, this shows the last
3434
revision in which a line has existed. This requires a range of
3535
revision like START..END where the path to blame exists in
36-
START.
36+
START. `git blame --reverse START` is taken as `git blame
37+
--reverse START..HEAD` for convenience.
3738

3839
-p::
3940
--porcelain::

Documentation/git-blame.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ SYNOPSIS
1010
[verse]
1111
'git blame' [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-e] [-p] [-w] [--incremental]
1212
[-L <range>] [-S <revs-file>] [-M] [-C] [-C] [-C] [--since=<date>]
13-
[--progress] [--abbrev=<n>] [<rev> | --contents <file> | --reverse <rev>]
13+
[--progress] [--abbrev=<n>] [<rev> | --contents <file> | --reverse <rev>..<rev>]
1414
[--] <file>
1515

1616
DESCRIPTION

builtin/blame.c

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2456,6 +2456,41 @@ static char *prepare_final(struct scoreboard *sb)
24562456
return xstrdup_or_null(name);
24572457
}
24582458

2459+
static const char *dwim_reverse_initial(struct scoreboard *sb)
2460+
{
2461+
/*
2462+
* DWIM "git blame --reverse ONE -- PATH" as
2463+
* "git blame --reverse ONE..HEAD -- PATH" but only do so
2464+
* when it makes sense.
2465+
*/
2466+
struct object *obj;
2467+
struct commit *head_commit;
2468+
unsigned char head_sha1[20];
2469+
2470+
if (sb->revs->pending.nr != 1)
2471+
return NULL;
2472+
2473+
/* Is that sole rev a committish? */
2474+
obj = sb->revs->pending.objects[0].item;
2475+
obj = deref_tag(obj, NULL, 0);
2476+
if (obj->type != OBJ_COMMIT)
2477+
return NULL;
2478+
2479+
/* Do we have HEAD? */
2480+
if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL))
2481+
return NULL;
2482+
head_commit = lookup_commit_reference_gently(head_sha1, 1);
2483+
if (!head_commit)
2484+
return NULL;
2485+
2486+
/* Turn "ONE" into "ONE..HEAD" then */
2487+
obj->flags |= UNINTERESTING;
2488+
add_pending_object(sb->revs, &head_commit->object, "HEAD");
2489+
2490+
sb->final = (struct commit *)obj;
2491+
return sb->revs->pending.objects[0].name;
2492+
}
2493+
24592494
static char *prepare_initial(struct scoreboard *sb)
24602495
{
24612496
int i;
@@ -2474,14 +2509,17 @@ static char *prepare_initial(struct scoreboard *sb)
24742509
if (obj->type != OBJ_COMMIT)
24752510
die("Non commit %s?", revs->pending.objects[i].name);
24762511
if (sb->final)
2477-
die("More than one commit to dig down to %s and %s?",
2512+
die("More than one commit to dig up from, %s and %s?",
24782513
revs->pending.objects[i].name,
24792514
final_commit_name);
24802515
sb->final = (struct commit *) obj;
24812516
final_commit_name = revs->pending.objects[i].name;
24822517
}
2518+
2519+
if (!final_commit_name)
2520+
final_commit_name = dwim_reverse_initial(sb);
24832521
if (!final_commit_name)
2484-
die("No commit to dig down to?");
2522+
die("No commit to dig up from?");
24852523
return xstrdup(final_commit_name);
24862524
}
24872525

0 commit comments

Comments
 (0)