From: "Ravi Mistry via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Junio C Hamano <gitster@pobox.com>,
Abhijeetsingh Meena <abhijeet040403@gmail.com>,
Kristoffer Haugsbakk <code@khaugsbakk.name>,
Phillip Wood <phillip.wood@dunelm.org.uk>,
Eric Sunshine <sunshine@sunshineco.com>,
Phillip Wood <phillip.wood123@gmail.com>,
Ravi Mistry <rmistry@google.com>
Subject: [PATCH v5 0/2] blame: ignore revs in .git-blame-ignore-revs by default
Date: Tue, 13 Oct 2026 14:36:13 +0000 [thread overview]
Message-ID: <pull.2224.v5.git.1791902175.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.2224.git.1789169384240.gitgitgadget@gmail.com>
This series teaches git-blame(1) and git-annotate(1) to automatically use
.git-blame-ignore-revs at the root of the working tree (or
HEAD:.git-blame-ignore-revs in bare repositories) by default if it exists,
without requiring manual blame.ignoreRevsFile configuration in every clone.
This restarts the stalled attempt in PR
https://github.com/gitgitgadget/git/pull/1809
(https://lore.kernel.org/git/pull.1809.v2.git.1728707867.gitgitgadget@gmail.com/)
and addresses https://github.com/gitgitgadget/git/issues/1494.
Changes since v4:
* In non-bare repositories, Patch 2/2 now reads .git-blame-ignore-revs from
the root of the working tree (using open_nofollow(), S_ISREG(), and
IGNORE_REVS_MAX_FILE_SIZE) instead of HEAD:.git-blame-ignore-revs, while
continuing to use HEAD:.git-blame-ignore-revs in bare repositories
(matching the .mailmap model in read_mailmap()). This makes it ergonomic
to test uncommitted or untracked changes to .git-blame-ignore-revs
locally before committing.
* Updated the commit messages and documentation to justify the default
lookup and working-tree behavior on ergonomic grounds.
Changes since v3:
* Patch 2/2 caps the size of the default HEAD:.git-blame-ignore-revs blob
at IGNORE_REVS_MAX_FILE_SIZE (100MB, matching ATTR_MAX_FILE_SIZE from
3c50032ff5 ("attr: ignore overly large gitattributes files", 2022-12-01))
via odb_read_object_info() before calling odb_read_object(), skipping
oversized blobs with a warning without loading them into memory.
Changes since v2:
* Patch 2/2 uses sb->repo instead of the_repository in
parse_default_ignore_revs_blob().
Changes since v1:
* Split the series into two commits.
* Patch 1/2 hardens oidset_parse_file_carefully() in oidset.c and
peel_to_commit_oid() in builtin/blame.c before exposing them to
upstream-controlled content at a well-known path:
* Reject lines containing embedded NUL bytes via memchr() so trailing
bytes after a NUL cannot be silently ignored.
* Pass OBJECT_INFO_LOOKUP_REPLACE | OBJECT_INFO_SKIP_FETCH_OBJECT |
OBJECT_INFO_QUICK to odb_read_object_info_extended() and peel tags one
layer per iteration so missing OIDs or tag targets do not trigger lazy
promisor fetches or pack directory rescans in partial clones, and
verify that each peeled target matches the tag's declared type.
* Patch 2/2 reads the committed HEAD:.git-blame-ignore-revs blob (in both
bare and non-bare repositories) instead of reading a file from the
working tree, matching hosting platforms even when an untracked file is
present or a tracked one has local modifications. The tree entry is
checked with S_ISREG() so non-regular entries (such as committed
symlinks) are skipped, parsed in memory via
oidset_parse_buffer_carefully(), and bypassed without reading if cleared
via blame.ignoreRevsFile="" or --no-ignore-revs-file.
Ravi Mistry (2):
blame: harden ignore-revs parser and tag peeling
blame: ignore revs in .git-blame-ignore-revs by default
Documentation/blame-options.adoc | 9 +-
Documentation/config/blame.adoc | 10 +-
builtin/blame.c | 115 ++++++++++++-
oidset.c | 81 ++++++---
oidset.h | 9 +
t/t8013-blame-ignore-revs.sh | 271 +++++++++++++++++++++++++++++++
6 files changed, 460 insertions(+), 35 deletions(-)
base-commit: fa7f9290efe2bd22dd736689597b474b93798e11
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2224%2Frmistry%2Fblame-default-ignore-revs-v5
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2224/rmistry/blame-default-ignore-revs-v5
Pull-Request: https://github.com/gitgitgadget/git/pull/2224
Range-diff vs v4:
1: 2e12486c0d ! 1: e9b2c1dae2 blame: harden ignore-revs parser and tag peeling
@@ Commit message
Currently, blame.ignoreRevsFile and --ignore-revs-file only read paths
explicitly configured by the user, which cannot point to an
attacker-controlled file under Git's threat model. An upcoming commit
- will teach git-blame(1) and git-annotate(1) to automatically read the
- HEAD:.git-blame-ignore-revs blob by default if it exists, exposing the
+ will teach git-blame(1) and git-annotate(1) to automatically read
+ .git-blame-ignore-revs by default if it exists, exposing the
ignore-revs parser (oidset_parse_file_carefully() in oidset.c) and its
tag-peeling callback (peel_to_commit_oid() in builtin/blame.c) to
upstream-controlled content at a well-known path.
- Harden both code paths before enabling the default blob:
+ Harden both code paths before enabling the default ignore-revs file:
- In oidset_parse_file_carefully(), strbuf_getline() reads up to the
next newline and records the full line length in sb.len, including
2: 76d597dfa8 ! 2: 605eb049a1 blame: ignore revs in HEAD:.git-blame-ignore-revs
@@ Metadata
Author: Ravi Mistry <rmistry@google.com>
## Commit message ##
- blame: ignore revs in HEAD:.git-blame-ignore-revs
+ blame: ignore revs in .git-blame-ignore-revs by default
git-blame(1) can ignore a list of commits specified via
--ignore-revs-file or the blame.ignoreRevsFile configuration option.
@@ Commit message
attribution shifts took priority over a project-wide default.
Requiring explicit opt-in per clone was therefore the prudent design.
- Since then, maintaining a .git-blame-ignore-revs file in the repository
- root has become the de facto standard across the Git ecosystem, adopted
- by major hosting platforms (GitHub, GitLab, Gerrit) and prominent open
- source projects (such as Chromium and LLVM). As a consequence,
- developers frequently encounter a jarring mismatch: web interfaces
- seamlessly ignore formatting commits, but local git-blame(1) and
- git-annotate(1) runs do not, unless each user manually configures
- blame.ignoreRevsFile for every local checkout.
+ Since then, maintaining a .git-blame-ignore-revs file at the top level
+ of the repository has become the standard convention across the Git
+ ecosystem, adopted by many open source projects (such as Chromium and
+ LLVM) as well as hosting platforms (GitHub, GitLab, Gerrit). However,
+ git-blame(1) and git-annotate(1) still ignore this file unless each
+ user remembers to manually configure blame.ignoreRevsFile in every
+ local clone.
- Teach git-blame(1) and git-annotate(1) to automatically add the
- HEAD:.git-blame-ignore-revs blob, if it exists, as the initial element
- in the list of ignore-revs files in both bare and non-bare
- repositories. Reading the committed blob from HEAD rather than the
- working tree ensures that local runs match hosting platforms even when
- an untracked .git-blame-ignore-revs file is present or a tracked one
- has uncommitted local changes.
+ Teach git-blame(1) and git-annotate(1) to automatically add
+ .git-blame-ignore-revs, if it exists, as the initial element in the
+ list of ignore-revs files. Similar to how read_mailmap() handles
+ .mailmap, consult .git-blame-ignore-revs at the root of the working
+ tree when a working tree is available and fall back to the
+ HEAD:.git-blame-ignore-revs blob in bare repositories. Reading from the
+ working tree in non-bare repositories makes it ergonomic to prepare a
+ new .git-blame-ignore-revs file or add revisions to an existing one and
+ immediately test the effect with git-blame(1) before committing, while
+ falling back to HEAD:.git-blame-ignore-revs allows bare repositories to
+ respect the committed ignore list as well.
- To ensure consistent precedence and override semantics:
- - The default HEAD:.git-blame-ignore-revs entry is added before reading
+ To ensure consistent precedence, override semantics, and safety when
+ reading upstream-controlled content:
+ - The default .git-blame-ignore-revs entry is added before reading
configuration and CLI options, preserving user and repository config
overrides.
- In git_blame_config(), blame.ignoreRevsFile entries are appended via
string_list_append() rather than inserted in sorted order via
string_list_insert() so that configuration entries preserve their
order relative to the initial default entry.
- - The HEAD:.git-blame-ignore-revs tree entry is resolved quietly via
- get_oid_with_context(). Its mode is checked with S_ISREG() before
- reading the object so that non-regular tree entries (such as a
- committed symbolic link whose blob stores a target path rather than
- revision IDs, a subdirectory, or a gitlink) are skipped instead of
- being read and rejected as malformed object names. Its size is checked
- via odb_read_object_info() and capped at IGNORE_REVS_MAX_FILE_SIZE
- (100MB, matching ATTR_MAX_FILE_SIZE from 3c50032ff5 ("attr: ignore
- overly large gitattributes files", 2022-12-01)) so an oversized blob
- is skipped with a warning without being loaded into memory. The blob
- is parsed in memory via a new oidset_parse_buffer_carefully() helper
- in oidset.c that shares line parsing with
- oidset_parse_file_carefully().
+ - When a working tree is present, the working-tree
+ .git-blame-ignore-revs path is checked with lstat() and S_ISREG(),
+ opened with open_nofollow(), and verified with fstat() and S_ISREG()
+ so symbolic links and non-regular files are silently skipped. In bare
+ repositories, HEAD:.git-blame-ignore-revs is resolved quietly via
+ get_oid_with_context() and its tree entry mode is checked with
+ S_ISREG() before checking the object.
+ - In both modes, the file or blob size is capped at
+ IGNORE_REVS_MAX_FILE_SIZE (100MB, matching ATTR_MAX_FILE_SIZE from
+ 3c50032ff5 ("attr: ignore overly large gitattributes files",
+ 2022-12-01)) before reading its contents, skipping an oversized file
+ or blob with a warning without loading it into memory. The contents
+ are parsed via a new oidset_parse_buffer_carefully() helper in
+ oidset.c that shares line parsing with oidset_parse_file_carefully().
- In build_ignorelist(), ignore-revs entries are processed starting
after the last empty string entry. This ensures setting
blame.ignoreRevsFile to "" or passing --ignore-revs-file "" or
- --no-ignore-revs-file cleanly discards the default blob without
+ --no-ignore-revs-file cleanly discards the default entry without
attempting to read or parse it, allowing users to bypass a malformed
- default blob.
+ default ignore-revs file.
Update documentation in blame-options.adoc and config/blame.adoc, and
- add comprehensive test coverage in t8013 for the default blob lookup,
- subdirectory invocations, bare repositories, uncommitted and untracked
- working-tree files, CLI and config overrides, committed symlink
- entries, overly large blobs, and comments and whitespace handling.
+ add test coverage in t8013 for the default working-tree lookup,
+ uncommitted and untracked .git-blame-ignore-revs files, subdirectory
+ invocations, bare repositories, CLI and config overrides, symbolic
+ links, overly large files and blobs, and comments and whitespace
+ handling.
Based-on-patch-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
Helped-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
@@ Documentation/blame-options.adoc: take effect.
- 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.
++ processed after the default `.git-blame-ignore-revs` file at the root of
++ the working tree (or `HEAD:.git-blame-ignore-revs` in a bare repository),
++ 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 ignore-revs file.
`--color-lines`::
Color line annotations in the default format differently if they come from
@@ Documentation/config/blame.adoc: blame.showRoot::
- `#` 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
++ `#` are ignored. If `.git-blame-ignore-revs` exists at the root of the
++ working tree (or `HEAD:.git-blame-ignore-revs` in a bare repository), 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.
@@ Documentation/config/blame.adoc: blame.showRoot::
Mark lines that were changed by an ignored revision that we could not
## builtin/blame.c ##
+@@
+ #include "object-name.h"
+ #include "odb.h"
+ #include "pager.h"
++#include "path.h"
+ #include "blame.h"
+ #include "refs.h"
+ #include "setup.h"
@@ builtin/blame.c: static int git_blame_config(const char *var, const char *value,
if (ret)
return ret;
@@ builtin/blame.c: static int peel_to_commit_oid(struct object_id *oid_ret, void *
+out:
+ object_context_release(&oc);
+}
++
++static void parse_default_ignore_revs_file(struct blame_scoreboard *sb,
++ const char *name)
++{
++ char *path = repo_worktree_path(sb->repo, "%s", name);
++ struct stat st;
++ int fd = -1;
++ size_t size;
++ char *buf = NULL;
++
++ if (lstat(path, &st) || !S_ISREG(st.st_mode))
++ goto out;
++ fd = open_nofollow(path, O_RDONLY);
++ if (fd < 0 || fstat(fd, &st) || !S_ISREG(st.st_mode))
++ goto out;
++ if (st.st_size >= IGNORE_REVS_MAX_FILE_SIZE) {
++ warning(_("ignoring overly large ignore-revs file '%s'"), name);
++ goto out;
++ }
++ size = xsize_t(st.st_size);
++ buf = xmalloc(size);
++ if (read_in_full(fd, buf, size) == (ssize_t)size)
++ oidset_parse_buffer_carefully(&sb->ignore_list, buf, size,
++ sb->repo->hash_algo,
++ peel_to_commit_oid, sb);
++
++out:
++ if (fd >= 0)
++ close(fd);
++ free(buf);
++ free(path);
++}
++
++static void parse_default_ignore_revs(struct blame_scoreboard *sb)
++{
++ if (repo_get_work_tree(sb->repo))
++ parse_default_ignore_revs_file(sb, ".git-blame-ignore-revs");
++ else
++ parse_default_ignore_revs_blob(sb, "HEAD:.git-blame-ignore-revs");
++}
+
static void build_ignorelist(struct blame_scoreboard *sb,
struct string_list *ignore_revs_file_list,
@@ builtin/blame.c: static int peel_to_commit_oid(struct object_id *oid_ret, void *
+ 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);
++ parse_default_ignore_revs(sb);
else
oidset_parse_file_carefully(&sb->ignore_list, i->string,
the_repository->hash_algo,
@@ builtin/blame.c: int cmd_blame(int argc,
setup_default_color_by_age();
+ string_list_append(&ignore_revs_file_list,
-+ "HEAD:.git-blame-ignore-revs")->util = &sb;
++ ".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;
@@ t/t8013-blame-ignore-revs.sh: test_expect_success 'ignore-revs-file peels chaine
test_cmp expect actual
'
-+# Tests for default HEAD:.git-blame-ignore-revs blob
-+test_expect_success 'setup default HEAD:.git-blame-ignore-revs' '
++# Tests for default .git-blame-ignore-revs
++test_expect_success 'setup default .git-blame-ignore-revs' '
+ git checkout -b default-file-branch &&
+ test_write_lines line1 line2 >def-file &&
+ git add def-file &&
@@ t/t8013-blame-ignore-revs.sh: test_expect_success 'ignore-revs-file peels chaine
+ git tag DEF_B &&
+
+ 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_A >expect &&
++ test_cmp expect actual &&
++
+ 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' '
++test_expect_success 'default .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 &&
@@ t/t8013-blame-ignore-revs.sh: test_expect_success 'ignore-revs-file peels chaine
+ test_cmp expect actual
+'
+
-+test_expect_success 'default HEAD:.git-blame-ignore-revs respected by git annotate' '
++test_expect_success 'default .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' '
++test_expect_success 'default .git-blame-ignore-revs works from subdirectory' '
++ test_when_finished "rm -rf sub" &&
+ mkdir -p sub &&
++ echo "invalid-oid-value" >sub/.git-blame-ignore-revs &&
+ (
+ cd sub &&
+ git blame --line-porcelain ../def-file >blame_raw &&
@@ t/t8013-blame-ignore-revs.sh: test_expect_success 'ignore-revs-file peels chaine
+ 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 &&
++
++ git -C .git blame --line-porcelain HEAD -- def-file >blame_raw &&
++ sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
+ test_cmp expect actual
+'
+
-+test_expect_success 'uncommitted .git-blame-ignore-revs changes in working tree are ignored' '
++test_expect_success 'uncommitted .git-blame-ignore-revs changes in working tree are respected' '
+ test_when_finished "git checkout -- .git-blame-ignore-revs" &&
-+ echo "invalid-oid-value" >.git-blame-ignore-revs &&
++ : >.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
++ git rev-parse DEF_B >expect &&
++ test_cmp expect actual &&
++
++ rm .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 &&
++ test_cmp expect actual &&
++
++ echo "invalid-oid-value" >.git-blame-ignore-revs &&
++ test_must_fail git blame def-file
+'
+
-+test_expect_success 'disable default HEAD:.git-blame-ignore-revs with --no-ignore-revs-file' '
++test_expect_success 'disable default .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 &&
@@ t/t8013-blame-ignore-revs.sh: test_expect_success 'ignore-revs-file peels chaine
+ test_cmp expect actual
+'
+
-+test_expect_success 'disable default HEAD:.git-blame-ignore-revs with --ignore-revs-file ""' '
++test_expect_success 'disable default .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 &&
@@ t/t8013-blame-ignore-revs.sh: test_expect_success 'ignore-revs-file peels chaine
+ test_cmp expect actual
+'
+
-+test_expect_success 'disable default HEAD:.git-blame-ignore-revs with blame.ignoreRevsFile=""' '
++test_expect_success 'disable default .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 &&
@@ t/t8013-blame-ignore-revs.sh: test_expect_success 'ignore-revs-file peels chaine
+ test_cmp expect actual
+'
+
-+test_expect_success 'default HEAD:.git-blame-ignore-revs handles comments and whitespace' '
++test_expect_success 'default .git-blame-ignore-revs handles comments and whitespace' '
+ rev_def_b=$(git rev-parse DEF_B) &&
+ {
+ echo "# Leading comment" &&
@@ t/t8013-blame-ignore-revs.sh: test_expect_success 'ignore-revs-file peels chaine
+ test_cmp expect actual
+'
+
-+test_expect_success 'empty default HEAD:.git-blame-ignore-revs is harmless' '
++test_expect_success 'empty default .git-blame-ignore-revs is harmless' '
+ : >.git-blame-ignore-revs &&
+ git add .git-blame-ignore-revs &&
+ test_tick &&
@@ t/t8013-blame-ignore-revs.sh: test_expect_success 'ignore-revs-file peels chaine
+ test_cmp expect actual
+'
+
-+test_expect_success 'committed symlink .git-blame-ignore-revs in HEAD is ignored' '
-+ git rm -f .git-blame-ignore-revs &&
++test_expect_success SYMLINKS 'symlink .git-blame-ignore-revs in working tree is ignored' '
++ test_when_finished "git checkout -- .git-blame-ignore-revs && rm -f target_file" &&
+ git rev-parse DEF_B >target_file &&
-+ test_ln_s_add target_file .git-blame-ignore-revs &&
++ rm -f .git-blame-ignore-revs &&
++ ln -s target_file .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 bare repo HEAD is ignored' '
++ test_when_finished "git reset --hard HEAD~ && rm -rf bare-symlink.git" &&
++ blob=$(printf "%s" "target_file" | git hash-object -w --stdin) &&
++ git update-index --replace --cacheinfo 120000,$blob,.git-blame-ignore-revs &&
+ test_tick &&
+ git commit -m "symlink .git-blame-ignore-revs" &&
-+ git blame --line-porcelain def-file >blame_raw &&
++ git clone --bare . bare-symlink.git &&
++ git -C bare-symlink.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' '
++test_expect_success 'malformed default .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 &&
@@ t/t8013-blame-ignore-revs.sh: test_expect_success 'ignore-revs-file peels chaine
+ test_grep "invalid object name:" err
+'
+
-+test_expect_success 'default HEAD:.git-blame-ignore-revs combined with config blame.ignoreRevsFile' '
++test_expect_success 'default .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 &&
@@ t/t8013-blame-ignore-revs.sh: test_expect_success 'ignore-revs-file peels chaine
+ 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" &&
++test_expect_success 'blame works when .git-blame-ignore-revs does not exist' '
+ 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) &&
++test_expect_success EXPENSIVE 'overly large default .git-blame-ignore-revs is ignored' '
++ test_when_finished "rm -f .git-blame-ignore-revs" &&
++ dd if=/dev/zero of=.git-blame-ignore-revs bs=1048576 count=101 2>/dev/null &&
++ 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 file '\''.git-blame-ignore-revs'\''" err &&
++
++ blob=$(git hash-object -w .git-blame-ignore-revs) &&
++ rm -f .git-blame-ignore-revs &&
+ 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 &&
++ git -C .git blame --line-porcelain HEAD -- 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
+'
--
gitgitgadget
next prev parent reply other threads:[~2026-10-13 14:36 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-11 23:29 [PATCH] blame: default to ignoring revisions in .git-blame-ignore-revs Ravi Mistry via GitGitGadget
2026-09-30 14:59 ` Ravi Mistry
2026-10-05 15:37 ` Junio C Hamano
2026-10-05 21:12 ` Ravi Mistry
2026-10-07 17:43 ` Junio C Hamano
2026-10-07 18:07 ` Ravi Mistry
2026-10-08 21:07 ` [PATCH v2 0/2] blame: ignore revs in HEAD:.git-blame-ignore-revs by default Ravi Mistry via GitGitGadget
2026-10-08 21:07 ` [PATCH v2 1/2] blame: harden ignore-revs parser and tag peeling Ravi Mistry via GitGitGadget
2026-10-09 5:07 ` Junio C Hamano
2026-10-10 19:25 ` Ravi Mistry
2026-10-08 21:07 ` [PATCH v2 2/2] blame: ignore revs in HEAD:.git-blame-ignore-revs Ravi Mistry via GitGitGadget
2026-10-09 20:17 ` Junio C Hamano
2026-10-10 6:12 ` Eric Sunshine
2026-10-10 18:40 ` Ravi Mistry
2026-10-11 18:58 ` Junio C Hamano
2026-10-11 22:29 ` Ravi Mistry
2026-10-11 23:07 ` Junio C Hamano
2026-10-12 9:13 ` Phillip Wood
2026-10-12 16:38 ` Junio C Hamano
2026-10-12 19:21 ` Ravi Mistry
2026-10-12 21:13 ` Junio C Hamano
2026-10-13 14:48 ` Ravi Mistry
2026-10-11 22:21 ` [PATCH v3 0/2] blame: ignore revs in HEAD:.git-blame-ignore-revs by default Ravi Mistry via GitGitGadget
2026-10-11 22:21 ` [PATCH v3 1/2] blame: harden ignore-revs parser and tag peeling Ravi Mistry via GitGitGadget
2026-10-11 22:21 ` [PATCH v3 2/2] blame: ignore revs in HEAD:.git-blame-ignore-revs Ravi Mistry via GitGitGadget
2026-10-12 9:10 ` Phillip Wood
2026-10-12 15:48 ` Ravi Mistry
2026-10-12 19:17 ` [PATCH v4 0/2] blame: ignore revs in HEAD:.git-blame-ignore-revs by default Ravi Mistry via GitGitGadget
2026-10-12 19:17 ` [PATCH v4 1/2] blame: harden ignore-revs parser and tag peeling Ravi Mistry via GitGitGadget
2026-10-12 19:17 ` [PATCH v4 2/2] blame: ignore revs in HEAD:.git-blame-ignore-revs Ravi Mistry via GitGitGadget
2026-10-13 14:36 ` Ravi Mistry via GitGitGadget [this message]
2026-10-13 14:36 ` [PATCH v5 1/2] blame: harden ignore-revs parser and tag peeling Ravi Mistry via GitGitGadget
2026-10-13 14:36 ` [PATCH v5 2/2] blame: ignore revs in .git-blame-ignore-revs by default Ravi Mistry via GitGitGadget
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=pull.2224.v5.git.1791902175.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=abhijeet040403@gmail.com \
--cc=code@khaugsbakk.name \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=phillip.wood123@gmail.com \
--cc=phillip.wood@dunelm.org.uk \
--cc=rmistry@google.com \
--cc=sunshine@sunshineco.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.