Git development
 help / color / mirror / Atom feed
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 v6 0/2] blame: ignore revs in .git-blame-ignore-revs by default
Date: Tue, 13 Oct 2026 20:22:06 +0000	[thread overview]
Message-ID: <pull.2224.v6.git.1791922928.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 v5:

 * Passed i->string from build_ignorelist() into parse_default_ignore_revs()
   so the item string is used for both the working-tree path and "HEAD:" in
   bare repositories, and changed cmd_blame() to set ->util = (void *)1 with
   an explanatory comment instead of passing the scoreboard.
 * Doc update: Changed "config option" / "configuration option" to
   "configuration variable" in Documentation/blame-options.adoc and the
   commit message.

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                  | 122 +++++++++++++-
 oidset.c                         |  81 ++++++---
 oidset.h                         |   9 +
 t/t8013-blame-ignore-revs.sh     | 271 +++++++++++++++++++++++++++++++
 6 files changed, 467 insertions(+), 35 deletions(-)


base-commit: fa7f9290efe2bd22dd736689597b474b93798e11
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2224%2Frmistry%2Fblame-default-ignore-revs-v6
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2224/rmistry/blame-default-ignore-revs-v6
Pull-Request: https://github.com/gitgitgadget/git/pull/2224

Range-diff vs v5:

 1:  e9b2c1dae2 = 1:  e9b2c1dae2 blame: harden ignore-revs parser and tag peeling
 2:  605eb049a1 ! 2:  6039d4bc2d blame: ignore revs in .git-blame-ignore-revs by default
     @@ Commit message
          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.
     +    --ignore-revs-file or the blame.ignoreRevsFile configuration variable.
          This is useful for skipping uninteresting revisions such as tree-wide
          formatting changes, large-scale refactors, and code modernizations that
          would otherwise obscure genuine historical authorship.
     @@ Commit message
          .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
     +    tree when a working tree is available, and otherwise consult the
     +    HEAD:.git-blame-ignore-revs blob in bare repositories. Reading only
     +    from the working tree in non-bare repositories makes it ergonomic to
     +    prepare a new .git-blame-ignore-revs file, edit an existing one, or
     +    remove a committed one and immediately test the effect with
     +    git-blame(1) before committing, while consulting
     +    HEAD:.git-blame-ignore-revs in bare repositories allows them to
          respect the committed ignore list as well.
      
          To ensure consistent precedence, override semantics, and safety when
     @@ Documentation/blame-options.adoc: take effect.
      +	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.
     ++	configuration variable.  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
     @@ builtin/blame.c: static int peel_to_commit_oid(struct object_id *oid_ret, void *
      +#define IGNORE_REVS_MAX_FILE_SIZE (100 * 1024 * 1024)
      +
      +static void parse_default_ignore_revs_blob(struct blame_scoreboard *sb,
     -+					   const char *name)
     ++					   const char *path)
      +{
     ++	char *name = xstrfmt("HEAD:%s", path);
      +	struct object_context oc;
      +	struct object_id oid;
      +	enum object_type type;
     @@ builtin/blame.c: static int peel_to_commit_oid(struct object_id *oid_ret, void *
      +
      +out:
      +	object_context_release(&oc);
     ++	free(name);
      +}
      +
      +static void parse_default_ignore_revs_file(struct blame_scoreboard *sb,
     @@ builtin/blame.c: static int peel_to_commit_oid(struct object_id *oid_ret, void *
      +	free(path);
      +}
      +
     -+static void parse_default_ignore_revs(struct blame_scoreboard *sb)
     ++static void parse_default_ignore_revs(struct blame_scoreboard *sb,
     ++				      const char *name)
      +{
      +	if (repo_get_work_tree(sb->repo))
     -+		parse_default_ignore_revs_file(sb, ".git-blame-ignore-revs");
     ++		parse_default_ignore_revs_file(sb, name);
      +	else
     -+		parse_default_ignore_revs_blob(sb, "HEAD:.git-blame-ignore-revs");
     ++		parse_default_ignore_revs_blob(sb, name);
      +}
      +
       static void build_ignorelist(struct blame_scoreboard *sb,
     @@ 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(sb);
     ++			parse_default_ignore_revs(sb, i->string);
       		else
       			oidset_parse_file_carefully(&sb->ignore_list, i->string,
       						    the_repository->hash_algo,
     @@ builtin/blame.c: int cmd_blame(int argc,
       	const char *const *opt_usage = cmd_is_annotate ? annotate_opt_usage : blame_opt_usage;
       
       	setup_default_color_by_age();
     ++	/*
     ++	 * An entry with a non-NULL .util member names the default
     ++	 * ignore-revs file at the project root; see build_ignorelist().
     ++	 */
      +	string_list_append(&ignore_revs_file_list,
     -+			   ".git-blame-ignore-revs")->util = &sb;
     ++			   ".git-blame-ignore-revs")->util = (void *)1;
       	repo_config(the_repository, git_blame_config, &output_option);
       	repo_init_revisions(the_repository, &revs, NULL);
       	revs.date_mode = blame_date_mode;

-- 
gitgitgadget

  parent reply	other threads:[~2026-10-13 20:22 UTC|newest]

Thread overview: 38+ 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 ` [PATCH v5 0/2] blame: ignore revs in .git-blame-ignore-revs by default Ravi Mistry via GitGitGadget
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
2026-10-13 17:30   ` [PATCH v5 0/2] " Junio C Hamano
2026-10-13 20:24     ` Ravi Mistry
2026-10-13 20:22 ` Ravi Mistry via GitGitGadget [this message]
2026-10-13 20:22   ` [PATCH v6 1/2] blame: harden ignore-revs parser and tag peeling Ravi Mistry via GitGitGadget
2026-10-13 20:22   ` [PATCH v6 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.v6.git.1791922928.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox