Skip to content

Commit ef0cedb

Browse files
committed
builtin/blame: ignore nonexistent ignore files
It's currently a problem to put blame.ignoreRevsFile in a global gitconfig, for example, to use the GitHub (and other) supported filename of .git-blame-ignore-revs by default if present in a repo, since the current implementation exits the process if it fails to open the file. If we change this to ignore nonexistent files when specified in the config option (but NOT the command line, since the command line surely means to actually assert the files exist), this remains API compatible with old usages, while behaving properly when you want to ignore missing ones. Because of this idea of putting .git-blame-ignore-revs in there, it doesn't seem to necessarily merit a warning, but maybe there should be one to be slightly less confusing if you make a typo? Signed-off-by: Jade Lovelace <[email protected]>
1 parent c152ae3 commit ef0cedb

File tree

5 files changed

+67
-6
lines changed

5 files changed

+67
-6
lines changed

Documentation/config/blame.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ blame.ignoreRevsFile::
2626
`#` are ignored. This option may be repeated multiple times. Empty
2727
file names will reset the list of ignored revisions. This option will
2828
be handled before the command line option `--ignore-revs-file`.
29+
+
30+
If a file in this list does not exist, it is disregarded and the next files in
31+
the list are processed as normal.
2932

3033
blame.markUnblamableLines::
3134
Mark lines that were changed by an ignored revision that we could not

builtin/blame.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ static int no_whole_file_rename;
6868
static int show_progress;
6969
static char repeated_meta_color[COLOR_MAXLEN];
7070
static int coloring_mode;
71+
/* Ignore-revs files specified in the config file. Processed separately to be
72+
* able to ignore failing to open them. */
73+
static struct string_list ignore_revs_config_file_list = STRING_LIST_INIT_DUP;
7174
static struct string_list ignore_revs_file_list = STRING_LIST_INIT_DUP;
7275
static int mark_unblamable_lines;
7376
static int mark_ignored_lines;
@@ -731,7 +734,7 @@ static int git_blame_config(const char *var, const char *value,
731734
ret = git_config_pathname(&str, var, value);
732735
if (ret)
733736
return ret;
734-
string_list_insert(&ignore_revs_file_list, str);
737+
string_list_insert(&ignore_revs_config_file_list, str);
735738
free(str);
736739
return 0;
737740
}
@@ -848,13 +851,33 @@ static int peel_to_commit_oid(struct object_id *oid_ret, void *cbdata)
848851
}
849852

850853
static void build_ignorelist(struct blame_scoreboard *sb,
854+
/* Ignore-revs files specified via the config,
855+
* which are allowed to fail to open. */
856+
struct string_list *ignore_revs_config_file_list,
851857
struct string_list *ignore_revs_file_list,
852858
struct string_list *ignore_rev_list)
853859
{
854860
struct string_list_item *i;
855861
struct object_id oid;
856862

857863
oidset_init(&sb->ignore_list, 0);
864+
for_each_string_list_item(i, ignore_revs_config_file_list) {
865+
if (!strcmp(i->string, ""))
866+
oidset_clear(&sb->ignore_list);
867+
else {
868+
FILE *fp = fopen(i->string, "r");
869+
if (!fp) {
870+
if (errno == ENOENT) continue;
871+
die("could not open blame.ignoreRevsFile file at %s", i->string);
872+
}
873+
874+
oidset_parse_filep_carefully(&sb->ignore_list, fp, i->string,
875+
the_repository->hash_algo,
876+
peel_to_commit_oid, sb);
877+
878+
fclose(fp);
879+
}
880+
}
858881
for_each_string_list_item(i, ignore_revs_file_list) {
859882
if (!strcmp(i->string, ""))
860883
oidset_clear(&sb->ignore_list);
@@ -1119,7 +1142,7 @@ int cmd_blame(int argc,
11191142
sb.reverse = reverse;
11201143
sb.repo = the_repository;
11211144
sb.path = path;
1122-
build_ignorelist(&sb, &ignore_revs_file_list, &ignore_rev_list);
1145+
build_ignorelist(&sb, &ignore_revs_config_file_list, &ignore_revs_file_list, &ignore_rev_list);
11231146
string_list_clear(&ignore_revs_file_list, 0);
11241147
string_list_clear(&ignore_rev_list, 0);
11251148
setup_scoreboard(&sb, &o);

oidset.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,24 @@ void oidset_parse_file_carefully(struct oidset *set, const char *path,
5959
oidset_parse_tweak_fn fn, void *cbdata)
6060
{
6161
FILE *fp;
62-
struct strbuf sb = STRBUF_INIT;
63-
struct object_id oid;
6462

6563
fp = fopen(path, "r");
6664
if (!fp)
6765
die("could not open object name list: %s", path);
66+
67+
oidset_parse_filep_carefully(set, fp, path, algop, fn, cbdata);
68+
69+
fclose(fp);
70+
}
71+
72+
void oidset_parse_filep_carefully(struct oidset *set, FILE *fp,
73+
const char *path,
74+
const struct git_hash_algo *algop,
75+
oidset_parse_tweak_fn fn, void *cbdata)
76+
{
77+
struct strbuf sb = STRBUF_INIT;
78+
struct object_id oid;
79+
6880
while (!strbuf_getline(&sb, fp)) {
6981
const char *p;
7082
const char *name;
@@ -89,6 +101,5 @@ void oidset_parse_file_carefully(struct oidset *set, const char *path,
89101
}
90102
if (ferror(fp))
91103
die_errno("Could not read '%s'", path);
92-
fclose(fp);
93104
strbuf_release(&sb);
94105
}

oidset.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define OIDSET_H
33

44
#include "khash.h"
5+
#include <stdio.h>
56

67
/**
78
* This API is similar to oid-array, in that it maintains a set of object ids
@@ -93,6 +94,15 @@ void oidset_parse_file_carefully(struct oidset *set, const char *path,
9394
const struct git_hash_algo *algop,
9495
oidset_parse_tweak_fn fn, void *cbdata);
9596

97+
/*
98+
* Same as oidset_parse_file_carefully, but is given a pre-opened file handle.
99+
* The given path is only used for diagnostics.
100+
*/
101+
void oidset_parse_filep_carefully(struct oidset *set, FILE *fp,
102+
const char *path,
103+
const struct git_hash_algo *algop,
104+
oidset_parse_tweak_fn fn, void *cbdata);
105+
96106
struct oidset_iter {
97107
kh_oid_set_t *set;
98108
khiter_t iter;

t/t8013-blame-ignore-revs.sh

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/bin/sh
1+
#!/nix/store/cvlbhhrvzfkjl2hrrzhq3vr5gzan1r60-bash-interactive-5.2p37/bin/sh
22

33
test_description='ignore revisions when blaming'
44

@@ -116,6 +116,20 @@ test_expect_success ignore_revs_from_configs_and_files '
116116
test_cmp expect actual
117117
'
118118

119+
# Ignore-revs from the config tolerates the file not existing
120+
test_expect_success ignore_revs_config_file_nonexistent '
121+
git config --add blame.ignoreRevsFile nonexistent_ignore_file &&
122+
git blame --line-porcelain file --ignore-revs-file ignore_y >blame_raw &&
123+
124+
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
125+
git rev-parse A >expect &&
126+
test_cmp expect actual &&
127+
128+
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
129+
git rev-parse B >expect &&
130+
test_cmp expect actual
131+
'
132+
119133
# Override blame.ignoreRevsFile (ignore_x) with an empty string. X should be
120134
# blamed now for lines 1 and 2, since we are no longer ignoring X.
121135
test_expect_success override_ignore_revs_file '

0 commit comments

Comments
 (0)