Merge branch 'rm/blame-default-ignore-revs' into seen
'git blame' and 'git annotate' have been updated to automatically use the 'HEAD:.git-blame-ignore-revs' blob as the default ignore list if it exists, aligning local behavior with major hosting platforms. The parser and tag-peeling machinery have been hardened against missing objects and malformed files. * rm/blame-default-ignore-revs: blame: ignore revs in HEAD:.git-blame-ignore-revs blame: harden ignore-revs parser and tag peelingseen
commit
084100f874
|
|
@ -132,9 +132,11 @@ take effect.
|
|||
`--ignore-revs-file <file>`::
|
||||
Ignore revisions listed in _<file>_, which must be in the same format as an
|
||||
`fsck.skipList`. This option may be repeated, and these files will be
|
||||
processed after any files specified with the `blame.ignoreRevsFile` config
|
||||
option. An empty file name, `""`, will clear the list of revs from
|
||||
previously processed files.
|
||||
processed after the default `HEAD:.git-blame-ignore-revs` blob (if it
|
||||
exists) and any files specified with the `blame.ignoreRevsFile` config
|
||||
option. An empty file name, `""`, or `--no-ignore-revs-file` will clear
|
||||
the list of revs from previously processed files, including the default
|
||||
`HEAD:.git-blame-ignore-revs` blob.
|
||||
|
||||
`--color-lines`::
|
||||
Color line annotations in the default format differently if they come from
|
||||
|
|
|
|||
|
|
@ -23,9 +23,12 @@ blame.showRoot::
|
|||
blame.ignoreRevsFile::
|
||||
Ignore revisions listed in the file, one unabbreviated object name per
|
||||
line, in linkgit:git-blame[1]. Whitespace and comments beginning with
|
||||
`#` 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`.
|
||||
`#` are ignored. If the `HEAD:.git-blame-ignore-revs` blob exists, it
|
||||
is added as the initial element in the list of ignore-revs files.
|
||||
Other files listed in the configuration are also used, but an empty
|
||||
element makes all elements that appeared before in the list forgotten.
|
||||
This option will be handled before the command line option
|
||||
`--ignore-revs-file`.
|
||||
|
||||
blame.markUnblamableLines::
|
||||
Mark lines that were changed by an ignored revision that we could not
|
||||
|
|
|
|||
|
|
@ -770,7 +770,7 @@ static int git_blame_config(const char *var, const char *value,
|
|||
if (ret)
|
||||
return ret;
|
||||
if (str)
|
||||
string_list_insert(&ignore_revs_file_list, str);
|
||||
string_list_append(&ignore_revs_file_list, str);
|
||||
free(str);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -912,36 +912,96 @@ static int is_a_rev(const char *name)
|
|||
static int peel_to_commit_oid(struct object_id *oid_ret, void *cbdata)
|
||||
{
|
||||
struct repository *r = ((struct blame_scoreboard *)cbdata)->repo;
|
||||
enum object_type expected_type = OBJ_ANY;
|
||||
struct object_id oid;
|
||||
|
||||
oidcpy(&oid, oid_ret);
|
||||
while (1) {
|
||||
unsigned flags = OBJECT_INFO_LOOKUP_REPLACE |
|
||||
OBJECT_INFO_SKIP_FETCH_OBJECT |
|
||||
OBJECT_INFO_QUICK;
|
||||
struct object_info oi = OBJECT_INFO_INIT;
|
||||
enum object_type kind;
|
||||
struct object *obj;
|
||||
int kind = odb_read_object_info(r->objects, &oid, NULL);
|
||||
|
||||
oi.typep = &kind;
|
||||
if (odb_read_object_info_extended(r->objects, &oid, &oi,
|
||||
flags) < 0)
|
||||
return -1;
|
||||
if (expected_type != OBJ_ANY && kind != expected_type)
|
||||
return -1;
|
||||
if (kind == OBJ_COMMIT) {
|
||||
oidcpy(oid_ret, &oid);
|
||||
return 0;
|
||||
}
|
||||
if (kind != OBJ_TAG)
|
||||
return -1;
|
||||
obj = deref_tag(r, parse_object(r, &oid), NULL, 0);
|
||||
obj = parse_object(r, &oid);
|
||||
if (!obj || obj->type != OBJ_TAG)
|
||||
return -1;
|
||||
obj = ((struct tag *)obj)->tagged;
|
||||
if (!obj)
|
||||
return -1;
|
||||
expected_type = obj->type;
|
||||
oidcpy(&oid, &obj->oid);
|
||||
}
|
||||
}
|
||||
|
||||
#define IGNORE_REVS_MAX_FILE_SIZE (100 * 1024 * 1024)
|
||||
|
||||
static void parse_default_ignore_revs_blob(struct blame_scoreboard *sb,
|
||||
const char *name)
|
||||
{
|
||||
struct object_context oc;
|
||||
struct object_id oid;
|
||||
enum object_type type;
|
||||
size_t size;
|
||||
char *buf;
|
||||
|
||||
if (get_oid_with_context(sb->repo, name, GET_OID_QUIETLY,
|
||||
&oid, &oc))
|
||||
goto out;
|
||||
if (!S_ISREG(oc.mode))
|
||||
goto out;
|
||||
|
||||
if (odb_read_object_info(sb->repo->objects, &oid, &size) != OBJ_BLOB)
|
||||
goto out;
|
||||
if (size >= IGNORE_REVS_MAX_FILE_SIZE) {
|
||||
warning(_("ignoring overly large ignore-revs blob '%s'"), name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf = odb_read_object(sb->repo->objects, &oid, &type, &size);
|
||||
if (!buf)
|
||||
goto out;
|
||||
if (type == OBJ_BLOB)
|
||||
oidset_parse_buffer_carefully(&sb->ignore_list, buf, size,
|
||||
sb->repo->hash_algo,
|
||||
peel_to_commit_oid, sb);
|
||||
free(buf);
|
||||
|
||||
out:
|
||||
object_context_release(&oc);
|
||||
}
|
||||
|
||||
static void build_ignorelist(struct blame_scoreboard *sb,
|
||||
struct string_list *ignore_revs_file_list,
|
||||
struct string_list *ignore_rev_list)
|
||||
{
|
||||
struct string_list_item *i;
|
||||
struct object_id oid;
|
||||
size_t start_idx = 0, idx;
|
||||
|
||||
for (idx = 0; idx < ignore_revs_file_list->nr; idx++) {
|
||||
if (!*ignore_revs_file_list->items[idx].string)
|
||||
start_idx = idx + 1;
|
||||
}
|
||||
|
||||
oidset_init(&sb->ignore_list, 0);
|
||||
for_each_string_list_item(i, ignore_revs_file_list) {
|
||||
if (!strcmp(i->string, ""))
|
||||
oidset_clear(&sb->ignore_list);
|
||||
for (idx = start_idx; idx < ignore_revs_file_list->nr; idx++) {
|
||||
i = &ignore_revs_file_list->items[idx];
|
||||
if (i->util)
|
||||
parse_default_ignore_revs_blob(sb, i->string);
|
||||
else
|
||||
oidset_parse_file_carefully(&sb->ignore_list, i->string,
|
||||
the_repository->hash_algo,
|
||||
|
|
@ -1021,6 +1081,8 @@ int cmd_blame(int argc,
|
|||
const char *const *opt_usage = cmd_is_annotate ? annotate_opt_usage : blame_opt_usage;
|
||||
|
||||
setup_default_color_by_age();
|
||||
string_list_append(&ignore_revs_file_list,
|
||||
"HEAD:.git-blame-ignore-revs")->util = &sb;
|
||||
repo_config(the_repository, git_blame_config, &output_option);
|
||||
repo_init_revisions(the_repository, &revs, NULL);
|
||||
revs.date_mode = blame_date_mode;
|
||||
|
|
|
|||
81
oidset.c
81
oidset.c
|
|
@ -70,41 +70,76 @@ void oidset_parse_file(struct oidset *set, const char *path,
|
|||
oidset_parse_file_carefully(set, path, algop, NULL, NULL);
|
||||
}
|
||||
|
||||
static void parse_oidset_line(struct oidset *set, struct strbuf *sb,
|
||||
const struct git_hash_algo *algop,
|
||||
oidset_parse_tweak_fn fn, void *cbdata)
|
||||
{
|
||||
const char *p;
|
||||
const char *name;
|
||||
struct object_id oid;
|
||||
|
||||
if (memchr(sb->buf, '\0', sb->len))
|
||||
die("invalid object name: %s", sb->buf);
|
||||
|
||||
/*
|
||||
* Allow trailing comments, leading whitespace
|
||||
* (including before commits), and empty or whitespace
|
||||
* only lines.
|
||||
*/
|
||||
name = strchr(sb->buf, '#');
|
||||
if (name)
|
||||
strbuf_setlen(sb, name - sb->buf);
|
||||
strbuf_trim(sb);
|
||||
if (!sb->len)
|
||||
return;
|
||||
|
||||
if (parse_oid_hex_algop(sb->buf, &oid, &p, algop) || *p != '\0')
|
||||
die("invalid object name: %s", sb->buf);
|
||||
if (fn && fn(&oid, cbdata))
|
||||
return;
|
||||
oidset_insert(set, &oid);
|
||||
}
|
||||
|
||||
void oidset_parse_file_carefully(struct oidset *set, const char *path,
|
||||
const struct git_hash_algo *algop,
|
||||
oidset_parse_tweak_fn fn, void *cbdata)
|
||||
{
|
||||
FILE *fp;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
struct object_id oid;
|
||||
|
||||
fp = fopen(path, "r");
|
||||
if (!fp)
|
||||
die("could not open object name list: %s", path);
|
||||
while (!strbuf_getline(&sb, fp)) {
|
||||
const char *p;
|
||||
const char *name;
|
||||
|
||||
/*
|
||||
* Allow trailing comments, leading whitespace
|
||||
* (including before commits), and empty or whitespace
|
||||
* only lines.
|
||||
*/
|
||||
name = strchr(sb.buf, '#');
|
||||
if (name)
|
||||
strbuf_setlen(&sb, name - sb.buf);
|
||||
strbuf_trim(&sb);
|
||||
if (!sb.len)
|
||||
continue;
|
||||
|
||||
if (parse_oid_hex_algop(sb.buf, &oid, &p, algop) || *p != '\0')
|
||||
die("invalid object name: %s", sb.buf);
|
||||
if (fn && fn(&oid, cbdata))
|
||||
continue;
|
||||
oidset_insert(set, &oid);
|
||||
}
|
||||
while (!strbuf_getline(&sb, fp))
|
||||
parse_oidset_line(set, &sb, algop, fn, cbdata);
|
||||
if (ferror(fp))
|
||||
die_errno("Could not read '%s'", path);
|
||||
fclose(fp);
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
void oidset_parse_buffer_carefully(struct oidset *set, const char *buf,
|
||||
size_t size,
|
||||
const struct git_hash_algo *algop,
|
||||
oidset_parse_tweak_fn fn, void *cbdata)
|
||||
{
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
const char *p = buf, *end;
|
||||
|
||||
if (!size)
|
||||
return;
|
||||
end = buf + size;
|
||||
|
||||
while (p < end) {
|
||||
const char *nl = memchr(p, '\n', end - p);
|
||||
size_t len = (nl ? nl : end) - p;
|
||||
|
||||
strbuf_reset(&sb);
|
||||
if (len && p[len - 1] == '\r')
|
||||
len--;
|
||||
strbuf_add(&sb, p, len);
|
||||
parse_oidset_line(set, &sb, algop, fn, cbdata);
|
||||
p = nl ? nl + 1 : end;
|
||||
}
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
|
|
|||
9
oidset.h
9
oidset.h
|
|
@ -98,6 +98,15 @@ void oidset_parse_file_carefully(struct oidset *set, const char *path,
|
|||
const struct git_hash_algo *algop,
|
||||
oidset_parse_tweak_fn fn, void *cbdata);
|
||||
|
||||
/*
|
||||
* Similar to oidset_parse_file_carefully(), but parses lines from an
|
||||
* in-memory buffer of 'size' bytes.
|
||||
*/
|
||||
void oidset_parse_buffer_carefully(struct oidset *set, const char *buf,
|
||||
size_t size,
|
||||
const struct git_hash_algo *algop,
|
||||
oidset_parse_tweak_fn fn, void *cbdata);
|
||||
|
||||
struct oidset_iter {
|
||||
const kh_oid_set_t *set;
|
||||
khiter_t iter;
|
||||
|
|
|
|||
|
|
@ -327,4 +327,239 @@ test_expect_success ignore_merge '
|
|||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'ignore-revs-file rejects lines with embedded NUL bytes' '
|
||||
rev_b=$(git rev-parse B) &&
|
||||
printf "%sQgarbage\n" "$rev_b" | q_to_nul >ignore_nul &&
|
||||
test_must_fail git blame file --ignore-revs-file ignore_nul 2>err &&
|
||||
test_grep "invalid object name:" err &&
|
||||
|
||||
printf "%sQ# comment\n" "$rev_b" | q_to_nul >ignore_nul_comment &&
|
||||
test_must_fail git blame file --ignore-revs-file ignore_nul_comment 2>err &&
|
||||
test_grep "invalid object name:" err
|
||||
'
|
||||
|
||||
test_expect_success 'ignore-revs-file peels chained tags and skips missing tag targets' '
|
||||
test_write_lines BB L2-modified L3 L4 L5 L6 L7 L8 CC >file &&
|
||||
git add file &&
|
||||
test_tick &&
|
||||
git commit -m D &&
|
||||
git tag -a -m "tag 1" D_TAG1 HEAD &&
|
||||
git tag -a -m "tag 2" D_TAG2 D_TAG1 &&
|
||||
git rev-parse D_TAG2 >ignore_tag_chain &&
|
||||
git blame --line-porcelain file --ignore-revs-file ignore_tag_chain >blame_raw &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse A >expect &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
test_config extensions.partialClone origin &&
|
||||
test_config remote.origin.promisor true &&
|
||||
test_config remote.origin.url /nonexistent &&
|
||||
missing_oid=$(test_oid deadbeef) &&
|
||||
bad_tag=$(printf "object %s\ntype commit\ntag bad-tag\ntagger T <t@example.com> 0 +0000\n\nmsg\n" "$missing_oid" |
|
||||
git hash-object -t tag -w --stdin) &&
|
||||
test_write_lines "$missing_oid" "$bad_tag" >ignore_bad_tag &&
|
||||
git blame --line-porcelain file --ignore-revs-file ignore_bad_tag >blame_raw 2>err &&
|
||||
test_must_be_empty err &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse HEAD >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
# Tests for default HEAD:.git-blame-ignore-revs blob
|
||||
test_expect_success 'setup default HEAD:.git-blame-ignore-revs' '
|
||||
git checkout -b default-file-branch &&
|
||||
test_write_lines line1 line2 >def-file &&
|
||||
git add def-file &&
|
||||
test_tick &&
|
||||
git commit -m "default base" &&
|
||||
git tag DEF_A &&
|
||||
|
||||
test_write_lines line1-modified line2-modified >def-file &&
|
||||
git add def-file &&
|
||||
test_tick &&
|
||||
git commit -m "default mod" &&
|
||||
git tag DEF_B &&
|
||||
|
||||
git rev-parse DEF_B >.git-blame-ignore-revs &&
|
||||
git add .git-blame-ignore-revs &&
|
||||
test_tick &&
|
||||
git commit -m "add .git-blame-ignore-revs"
|
||||
'
|
||||
|
||||
test_expect_success 'default HEAD:.git-blame-ignore-revs is used by default' '
|
||||
git blame --line-porcelain def-file >blame_raw &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse DEF_A >expect &&
|
||||
test_cmp expect actual &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'default HEAD:.git-blame-ignore-revs respected by git annotate' '
|
||||
git rev-parse --short DEF_A >expect_sha &&
|
||||
git annotate def-file >actual &&
|
||||
test_grep "^$(cat expect_sha)" actual
|
||||
'
|
||||
|
||||
test_expect_success 'default HEAD:.git-blame-ignore-revs works from subdirectory' '
|
||||
mkdir -p sub &&
|
||||
(
|
||||
cd sub &&
|
||||
git blame --line-porcelain ../def-file >blame_raw &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse DEF_A >expect &&
|
||||
test_cmp expect actual
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'default HEAD:.git-blame-ignore-revs respected in bare repo' '
|
||||
test_when_finished "rm -rf bare.git" &&
|
||||
git clone --bare . bare.git &&
|
||||
git -C bare.git blame --line-porcelain def-file >blame_raw &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse DEF_A >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'uncommitted .git-blame-ignore-revs changes in working tree are ignored' '
|
||||
test_when_finished "git checkout -- .git-blame-ignore-revs" &&
|
||||
echo "invalid-oid-value" >.git-blame-ignore-revs &&
|
||||
git blame --line-porcelain def-file >blame_raw &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse DEF_A >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'disable default HEAD:.git-blame-ignore-revs with --no-ignore-revs-file' '
|
||||
git blame --line-porcelain --no-ignore-revs-file def-file >blame_raw &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse DEF_B >expect &&
|
||||
test_cmp expect actual &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'disable default HEAD:.git-blame-ignore-revs with --ignore-revs-file ""' '
|
||||
git blame --line-porcelain --ignore-revs-file "" def-file >blame_raw &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse DEF_B >expect &&
|
||||
test_cmp expect actual &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'disable default HEAD:.git-blame-ignore-revs with blame.ignoreRevsFile=""' '
|
||||
test_config blame.ignoreRevsFile "" &&
|
||||
git blame --line-porcelain def-file >blame_raw &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse DEF_B >expect &&
|
||||
test_cmp expect actual &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'default HEAD:.git-blame-ignore-revs handles comments and whitespace' '
|
||||
rev_def_b=$(git rev-parse DEF_B) &&
|
||||
{
|
||||
echo "# Leading comment" &&
|
||||
echo "" &&
|
||||
echo " $rev_def_b # inline comment" &&
|
||||
echo "# Trailing comment"
|
||||
} >.git-blame-ignore-revs &&
|
||||
git add .git-blame-ignore-revs &&
|
||||
test_tick &&
|
||||
git commit -m "comments and whitespace in .git-blame-ignore-revs" &&
|
||||
git blame --line-porcelain def-file >blame_raw &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse DEF_A >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'empty default HEAD:.git-blame-ignore-revs is harmless' '
|
||||
: >.git-blame-ignore-revs &&
|
||||
git add .git-blame-ignore-revs &&
|
||||
test_tick &&
|
||||
git commit -m "empty .git-blame-ignore-revs" &&
|
||||
git blame --line-porcelain def-file >blame_raw &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse DEF_B >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'committed symlink .git-blame-ignore-revs in HEAD is ignored' '
|
||||
git rm -f .git-blame-ignore-revs &&
|
||||
git rev-parse DEF_B >target_file &&
|
||||
test_ln_s_add target_file .git-blame-ignore-revs &&
|
||||
test_tick &&
|
||||
git commit -m "symlink .git-blame-ignore-revs" &&
|
||||
git blame --line-porcelain def-file >blame_raw &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse DEF_B >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'malformed default HEAD:.git-blame-ignore-revs fails but can be bypassed' '
|
||||
git rm -f .git-blame-ignore-revs &&
|
||||
echo "invalid-oid-value" >.git-blame-ignore-revs &&
|
||||
git add .git-blame-ignore-revs &&
|
||||
test_tick &&
|
||||
git commit -m "malformed .git-blame-ignore-revs" &&
|
||||
test_must_fail git blame def-file &&
|
||||
git blame --no-ignore-revs-file def-file &&
|
||||
git blame --ignore-revs-file "" def-file &&
|
||||
git -c blame.ignoreRevsFile="" blame def-file &&
|
||||
|
||||
rev_def_b=$(git rev-parse DEF_B) &&
|
||||
printf "%sQgarbage\n" "$rev_def_b" | q_to_nul >.git-blame-ignore-revs &&
|
||||
git add .git-blame-ignore-revs &&
|
||||
test_tick &&
|
||||
git commit -m "NUL in .git-blame-ignore-revs" &&
|
||||
test_must_fail git blame def-file 2>err &&
|
||||
test_grep "invalid object name:" err
|
||||
'
|
||||
|
||||
test_expect_success 'default HEAD:.git-blame-ignore-revs combined with config blame.ignoreRevsFile' '
|
||||
git rev-parse DEF_B >.git-blame-ignore-revs &&
|
||||
test_write_lines line1-modified line2-c >def-file &&
|
||||
git add .git-blame-ignore-revs def-file &&
|
||||
test_tick &&
|
||||
git commit -m C &&
|
||||
git tag DEF_C &&
|
||||
git rev-parse DEF_C >custom_ignore &&
|
||||
test_config blame.ignoreRevsFile custom_ignore &&
|
||||
git blame --line-porcelain def-file >blame_raw &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse DEF_A >expect &&
|
||||
test_cmp expect actual &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse DEF_A >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'blame works when HEAD:.git-blame-ignore-revs does not exist and ignores untracked file' '
|
||||
test_when_finished "rm -f .git-blame-ignore-revs" &&
|
||||
git rm -f .git-blame-ignore-revs &&
|
||||
test_tick &&
|
||||
git commit -m "remove .git-blame-ignore-revs" &&
|
||||
git rev-parse DEF_B >.git-blame-ignore-revs &&
|
||||
git blame --line-porcelain def-file >blame_raw &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse DEF_B >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success EXPENSIVE 'overly large default HEAD:.git-blame-ignore-revs blob is ignored' '
|
||||
blob=$(dd if=/dev/zero bs=1048576 count=101 2>/dev/null |
|
||||
git hash-object -w --stdin) &&
|
||||
git update-index --add --cacheinfo 100644,$blob,.git-blame-ignore-revs &&
|
||||
test_tick &&
|
||||
git commit -m "overly large .git-blame-ignore-revs" &&
|
||||
test_when_finished "git reset --hard HEAD~" &&
|
||||
git blame --line-porcelain def-file >blame_raw 2>err &&
|
||||
sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
|
||||
git rev-parse DEF_B >expect &&
|
||||
test_cmp expect actual &&
|
||||
test_grep "warning: ignoring overly large ignore-revs blob '\''HEAD:.git-blame-ignore-revs'\''" err
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
|||
Loading…
Reference in New Issue