@@ -26,3 +26,7 @@ blame.ignoreRevsFile::
`#` are ignored. This option may be repeated multiple times. Empty
file names will reset the list of ignored revisions. This option will
be handled before the command line option `--ignore-revs-file`.
+
+blame.markIgnoredLines::
+ Mark lines that were changed by an ignored revision with a '*' in the
+ output of linkgit:git-blame[1].
@@ -480,6 +480,7 @@ void blame_coalesce(struct blame_scoreboard *sb)
for (ent = sb->ent; ent && (next = ent->next); ent = next) {
if (ent->suspect == next->suspect &&
ent->s_lno + ent->num_lines == next->s_lno &&
+ ent->ignored == next->ignored &&
ent->unblamable == next->unblamable) {
ent->num_lines += next->num_lines;
ent->next = next->next;
@@ -732,6 +733,7 @@ static void split_overlap(struct blame_entry *split,
int chunk_end_lno;
memset(split, 0, sizeof(struct blame_entry [3]));
+ split[0].ignored = split[1].ignored = split[2].ignored = e->ignored;
split[0].unblamable = e->unblamable;
split[1].unblamable = e->unblamable;
split[2].unblamable = e->unblamable;
@@ -854,6 +856,7 @@ static struct blame_entry *split_blame_at(struct blame_entry *e, int len,
struct blame_entry *n = xcalloc(1, sizeof(struct blame_entry));
n->suspect = new_suspect;
+ n->ignored = e->ignored;
n->unblamable = e->unblamable;
n->lno = e->lno + len;
n->s_lno = e->s_lno + len;
@@ -951,6 +954,7 @@ static void blame_chunk(struct blame_entry ***dstq, struct blame_entry ***srcq,
blame_origin_decref(e->suspect);
e->suspect = blame_origin_incref(parent);
e->s_lno += offset;
+ e->ignored = 1;
/* The top part of any ignored diff will not exist in
* the parent, and we will never be able to accurately
* blame it. We'll keep it on the blame list for the
@@ -92,6 +92,7 @@ struct blame_entry {
* scanning the lines over and over.
*/
unsigned score;
+ int ignored;
int unblamable;
};
@@ -53,6 +53,7 @@ static int show_progress;
static char repeated_meta_color[COLOR_MAXLEN];
static int coloring_mode;
static struct string_list ignore_revs_file_list = STRING_LIST_INIT_NODUP;
+static int mark_ignored_lines;
static struct date_mode blame_date_mode = { DATE_ISO8601 };
static size_t blame_date_width;
@@ -482,6 +483,10 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
}
}
+ if (mark_ignored_lines && ent->ignored) {
+ length--;
+ putchar('*');
+ }
if (ent->unblamable)
memset(hex, '0', length);
printf("%.*s", length, hex);
@@ -710,6 +715,10 @@ static int git_blame_config(const char *var, const char *value, void *cb)
string_list_insert(&ignore_revs_file_list, str);
return 0;
}
+ if (!strcmp(var, "blame.markignoredlines")) {
+ mark_ignored_lines = git_config_bool(var, value);
+ return 0;
+ }
if (!strcmp(var, "color.blame.repeatedlines")) {
if (color_parse_mem(value, strlen(value), repeated_meta_color))
warning(_("invalid color '%s' in color.blame.repeatedLines"),
@@ -121,6 +121,39 @@ test_expect_success bad_files_and_revs '
test_i18ngrep "Invalid object name: NOREV" err
'
+# Commit Z will touch the first two lines. Y touched all four.
+# A--B--X--Y--Z
+# The blame output when ignoring Z should be:
+# ^Y ... 1)
+# ^Y ... 2)
+# Y ... 3)
+# Y ... 4)
+# We're checking only the first character
+test_expect_success mark_ignored_lines '
+ git config --add blame.markIgnoredLines true &&
+
+ test_write_lines line-one-Z line-two-Z new_line3 new_line4 >file &&
+ git add file &&
+ test_tick &&
+ git commit -m Z &&
+ git tag Z &&
+
+ git blame --ignore-rev Z file >blame_raw &&
+ echo "*" >expect &&
+
+ sed -n "1p" blame_raw | cut -c1 >actual &&
+ test_cmp expect actual &&
+
+ sed -n "2p" blame_raw | cut -c1 >actual &&
+ test_cmp expect actual &&
+
+ sed -n "3p" blame_raw | cut -c1 >actual &&
+ ! test_cmp expect actual &&
+
+ sed -n "4p" blame_raw | cut -c1 >actual &&
+ ! test_cmp expect actual
+ '
+
# Resetting the repo and creating:
#
# A--B--M
When ignoring commits, the commit that is blamed might not be responsible for the change. Users might want to know when a particular line has a potentially inaccurate blame. This patch adds a config option to identify these lines by specifying blame.markIgnoredFiles. When this option is set, each blame line is marked with an '*'. For example: 278b6158d6fdb (Barret Rhoden 2016-04-11 13:57:54 -0400 26) appears as: *278b6158d6fd (Barret Rhoden 2016-04-11 13:57:54 -0400 26) where the '*' is placed before the commit, and the hash has one fewer characters. Signed-off-by: Barret Rhoden <brho@google.com> --- Documentation/config/blame.txt | 4 ++++ blame.c | 4 ++++ blame.h | 1 + builtin/blame.c | 9 +++++++++ t/t8013-blame-ignore-revs.sh | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 51 insertions(+)