summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2016-06-14 11:41:11 -0700
committerJunio C Hamano <gitster@pobox.com>2016-06-14 12:13:07 -0700
commite1d09701a4fa3a4d15dd005e2b698934e4ae9ae0 (patch)
tree09b892aeb03a45bd0f23cba26bd52afc5da924d2
parentd993ce1ed2f025708b0f78bed241466e35f1e8a0 (diff)
downloadgit-jc/blame-reverse.tar.gz
blame: dwim "blame --reverse OLD" as "blame --reverse OLD.."jc/blame-reverse
Instead of always requiring both ends of a range, we could DWIM "OLD", which could be a misspelt "OLD..", to be a range that ends at the current commit. Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--Documentation/blame-options.txt5
-rw-r--r--builtin/blame.c38
2 files changed, 41 insertions, 2 deletions
diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt
index 02cb6845cd..2669b87c9d 100644
--- a/Documentation/blame-options.txt
+++ b/Documentation/blame-options.txt
@@ -28,12 +28,13 @@ include::line-range-format.txt[]
-S <revs-file>::
Use revisions from revs-file instead of calling linkgit:git-rev-list[1].
---reverse::
+--reverse <rev>..<rev>::
Walk history forward instead of backward. Instead of showing
the revision in which a line appeared, this shows the last
revision in which a line has existed. This requires a range of
revision like START..END where the path to blame exists in
- START.
+ START. `git blame --reverse START` is taken as `git blame
+ --reverse START..HEAD` for convenience.
-p::
--porcelain::
diff --git a/builtin/blame.c b/builtin/blame.c
index a027b8a607..574b47dd55 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -2447,6 +2447,41 @@ static char *prepare_final(struct scoreboard *sb)
return xstrdup_or_null(name);
}
+static const char *dwim_reverse_initial(struct scoreboard *sb)
+{
+ /*
+ * DWIM "git blame --reverse ONE -- PATH" as
+ * "git blame --reverse ONE..HEAD -- PATH" but only do so
+ * when it makes sense.
+ */
+ struct object *obj;
+ struct commit *head_commit;
+ unsigned char head_sha1[20];
+
+ if (sb->revs->pending.nr != 1)
+ return NULL;
+
+ /* Is that sole rev a committish? */
+ obj = sb->revs->pending.objects[0].item;
+ obj = deref_tag(obj, NULL, 0);
+ if (obj->type != OBJ_COMMIT)
+ return NULL;
+
+ /* Do we have HEAD? */
+ if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL))
+ return NULL;
+ head_commit = lookup_commit_reference_gently(head_sha1, 1);
+ if (!head_commit)
+ return NULL;
+
+ /* Turn "ONE" into "ONE..HEAD" then */
+ obj->flags |= UNINTERESTING;
+ add_pending_object(sb->revs, &head_commit->object, "HEAD");
+
+ sb->final = (struct commit *)obj;
+ return sb->revs->pending.objects[0].name;
+}
+
static char *prepare_initial(struct scoreboard *sb)
{
int i;
@@ -2472,6 +2507,9 @@ static char *prepare_initial(struct scoreboard *sb)
sb->final = (struct commit *) obj;
final_commit_name = revs->pending.objects[i].name;
}
+
+ if (!final_commit_name)
+ final_commit_name = dwim_reverse_initial(sb);
if (!final_commit_name)
die("No commit to dig up from?");
return xstrdup(final_commit_name);