Git development
 help / color / mirror / Atom feed
* Re: [PATCH v6] checkout: extend --track with a "fetch" mode to refresh start-point
From: Harald Nordgren @ 2026-06-18 12:38 UTC (permalink / raw)
  To: Phillip Wood; +Cc: gitgitgadget, git
In-Reply-To: <f23eb128-958f-475f-911b-eac4f6daddff@gmail.com>

Hi Phillip!

How do you feel now, is it worth it for us to move forward with this
topic or not?


Harald

On Fri, May 8, 2026 at 3:15 PM Phillip Wood <phillip.wood123@gmail.com> wrote:
>
> Hi Harald
>
> On 07/05/2026 21:12, Harald Nordgren wrote:
> > Is this ready to move to next?
>
> I'm not particularly enthusiastic one way or the other about adding
> this, but so long as we only try to fetch when the user explicitly asks
> for it I don't particularly object. However having had a quick scan of
> the implementation I have a few comments
>
> * "--track=inherit,direct" is nonsense and should be rejected
>
> * currently "--track" has "last one wins" behavior so
>    "--track=inherit --track=direct" behaves like "--track=direct". We
>    should probably keep that so that "--track=fetch --track=direct"
>    behaves like "--track=direct", not "--track=fetch,direct"
>
> * if "git fetch" fails and the remote tracking ref already exists then
>    we should print a warning and carry on rather than dying which is more
>    convenient if the user or remote server are offline.
>
> * "git checkout --track=fetch origin/branch" should respect
>    remote.origin.fetch so that we fetch the ref that we're going to
>    checkout. I wonder if we can share this logic with the code that
>    sets the upstream branch.
>
> * "git checkout --track=fetch origin" should only fetch the remote
>    ref that we're going to checkout, not all the refs from origin. i.e.
>    it should read origin/HEAD to work out what to fetch.
>
> Thanks
>
> Phillip
>

^ permalink raw reply

* Re: [PATCH] checkout: add --fetch to fetch remote before resolving start-point
From: Harald Nordgren @ 2026-06-18 12:36 UTC (permalink / raw)
  To: D. Ben Knoble; +Cc: Harald Nordgren via GitGitGadget, git
In-Reply-To: <CALnO6CCNoo8y2V5KmE0KQ6qDurZELipFowcr=ZpZ3ocVB-uLjA@mail.gmail.com>

Hi Ben!

Trying to shore up some support for this topic. How do you feel about this now?


Harald

^ permalink raw reply

* Re: [PATCH v2 1/5] SubmittingPatches: encourage trailer use for substantial help
From: Kristoffer Haugsbakk @ 2026-06-18 12:21 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Patrick Steinhardt
In-Reply-To: <xmqq4ij0vo8f.fsf@gitster.g>

On Wed, Jun 17, 2026, at 23:41, Junio C Hamano wrote:
> kristofferhaugsbakk@fastmail.com writes:
>
>> diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
>> index 176567738d4..0b12badf86d 100644
>> --- a/Documentation/SubmittingPatches
>> +++ b/Documentation/SubmittingPatches
>> @@ -443,8 +443,16 @@ identifying, and not misleading.
>>  The goal of this policy is to allow us to have sufficient information to contact
>>  you if questions arise about your contribution.
>>
>> +=== Commit trailers
>>  [[commit-trailers]]
>> -If you like, you can put extra trailers at the end:
>
> I think majority of AsciiDoc files in this project places [[anchor]]
> before the "=== title" of a section.  For example, here is how the
> patch flow section begins in SubmittingPatches:
>
>     [[patch-flow]]
>     === A typical life cycle of a patch series
>
>     To help us understand the reason behind various guidelines given later
>     in the document, first let's understand how the life cycle of a
>     typical patch series for this project goes.
>
> I do not offhand know which way is kosher, but we should be
> consistent either way.

Your suspicion is correct. Skimming this I cannot seem to find any
examples where the anchor goes after the title.

    git grep --extended-regexp -C1 '^\[\[' -- 'Documentation/*adoc'

I’ll fix it.

^ permalink raw reply

* Re: [PATCH v2 0/7] More work supporting objects larger than 4GB on Windows
From: Patrick Steinhardt @ 2026-06-18 12:13 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Kristofer Karlsson, Johannes Schindelin
In-Reply-To: <pull.2137.v2.git.1781524349.gitgitgadget@gmail.com>

On Mon, Jun 15, 2026 at 11:52:22AM +0000, Johannes Schindelin via GitGitGadget wrote:
> This patch series tries to address the problems pointed out by the expensive
> tests that now run in CI: t5608 and t7508 verify various aspects about
> objects larger than 4GB, which Git does not currently handle correctly when
> run on a platform where size_t is 64-bit and unsigned long is 32-bit.
> 
> Changes vs v1:
> 
>  * Rebased onto master, which merged ps/odb-source-loose (with which these
>    patches previously conflicted rather badly).
>  * Removed superfluous size_t s variables (thanks, Patrick!).

I skimmed those parts that I was previously commenting on and am
happy with those changes. Thanks!

Patrick

^ permalink raw reply

* Re: [PATCH] Fix typo in MaintNotes regarding versioning scheme
From: Tuomas Ahola @ 2026-06-18 11:48 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Silas Poulson, gitgitgadget, git
In-Reply-To: <xmqqfr6czmye.fsf@gitster.g>

Junio C Hamano <gitster@pobox.com> wrote:

> Silas Poulson <silas@dyalog.com> writes:
> 
> > I'm aware this is a very minor change, but it would be good to not let 
> > this fall through the cracks.
> 
> Thanks for noticing a typo.
> 
> Will update before the next issue is sent to the mailing list.  No
> point in changing it before that.

On that occasion, please consider also these fixes:
-----8<-----
Subject: [PATCH] MaintNotes: fix typos and grammar

Signed-off-by: Tuomas Ahola <taahol@utu.fi>
---
 MaintNotes | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/MaintNotes b/MaintNotes
index 12ba677c36..44b29c9e10 100644
--- a/MaintNotes
+++ b/MaintNotes
@@ -82,7 +82,7 @@ available at:
 There is a volunteer-run newsletter to serve our community ("Git Rev
 News" https://git.github.io/rev_news/).
 
-Git is a member project of software freedom conservancy, a non-profit
+Git is a member project of Software Freedom Conservancy, a non-profit
 organization (https://sfconservancy.org/).  To reach a committee of
 liaisons to the conservancy, contact them at <git@sfconservancy.org>.
 
@@ -245,7 +245,7 @@ by others may cause conflicts with their own work, and find people who
 are working on these topics to talk to before the potential conflicts
 get out of control.  It would be a good idea to fork your work from
 maint or master and to (1) test it by itself, (2) test a temporary
-merge of it to "next" and (3) test a temporary merge to it to "seen",
+merge of it to "next" and (3) test a temporary merge of it to "seen",
 before sending it to the list (or asking GitGitGadget to send it to
 the list).
 
@@ -262,10 +262,10 @@ using the topics that didn't make the cut in the feature release.
 Some topics that used to be in "next" during the previous cycle may
 get ejected from "next" when this happens.
 
-A natural consequence of how "next" and "seen" bundles topics together
-is that until a topic is merged to "next", updates to it is expected
+A natural consequence of how "next" and "seen" bundle topics together
+is that until a topic is merged to "next", updates to it are expected
 by replacing the patch(es) in the topic with an improved version, and
-once a topic is merged to "next", updates to it needs to come as
+once a topic is merged to "next", updates to it need to come as
 incremental patches, pointing out what was wrong in the previous
 patches and how the problem was corrected.  The idea is that if many
 reviewers thought it has seen enough eyeballs and is good enough for

base-commit: f9b08c9b285c9154e41b9f5fce7506018b83dfcb
-- 
2.30.2


^ permalink raw reply related

* [PATCH v2 2/2] config: use repo_ignore_case() to access core.ignorecase
From: Tian Yuchen @ 2026-06-18 11:42 UTC (permalink / raw)
  To: git
  Cc: ps, phillip.wood123, johannes.schindelin, stolee, Tian Yuchen,
	Christian Couder, Ayush Chandekar, Olamide Caleb Bello
In-Reply-To: <20260618114207.605211-1-cat@malon.dev>

Replace the accesses to the global 'ignore_case' variable with
calls to 'repo_ignore_case(the_repository)'. This step eliminates
the 'ignore_case' global state.

Note on compat/win32/path-utils.c:
To eliminate the global state, several helper functions
(e.g. 'win32_fspathncmp()') now read from
'repo_ignore_case(the_repository)'. While this introduces
dependency on 'repository.h' into the 'compat/', it avoids massive
refactoring of the signatures across the codebase.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Ayush Chandekar <ayu.chandekar@gmail.com>
Mentored-by: Olamide Caleb Bello <belkid98@gmail.com>
Signed-off-by: Tian Yuchen <cat@malon.dev>
---
 apply.c                             |  2 +-
 builtin/fetch.c                     |  2 +-
 builtin/mv.c                        |  2 +-
 compat/win32/path-utils.c           |  3 ++-
 dir.c                               | 18 +++++++++---------
 environment.c                       |  3 +--
 environment.h                       |  1 -
 fsmonitor.c                         |  2 +-
 name-hash.c                         |  6 +++---
 read-cache.c                        |  6 +++---
 refs/files-backend.c                |  4 ++--
 submodule.c                         |  2 +-
 t/helper/test-lazy-init-name-hash.c |  2 +-
 unpack-trees.c                      |  2 +-
 14 files changed, 27 insertions(+), 28 deletions(-)

diff --git a/apply.c b/apply.c
index 249248d4f2..620c88d2a0 100644
--- a/apply.c
+++ b/apply.c
@@ -4008,7 +4008,7 @@ static int path_is_beyond_symlink_1(struct apply_state *state, struct strbuf *na
 			struct cache_entry *ce;
 
 			ce = index_file_exists(state->repo->index, name->buf,
-					       name->len, ignore_case);
+					       name->len, repo_ignore_case(the_repository));
 			if (ce && S_ISLNK(ce->ce_mode))
 				return 1;
 		} else {
diff --git a/builtin/fetch.c b/builtin/fetch.c
index e4e8a72ed9..073e716bc4 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1819,7 +1819,7 @@ static void ref_transaction_rejection_handler(const char *refname,
 {
 	struct ref_rejection_data *data = cb_data;
 
-	if (err == REF_TRANSACTION_ERROR_CASE_CONFLICT && ignore_case &&
+	if (err == REF_TRANSACTION_ERROR_CASE_CONFLICT && repo_ignore_case(the_repository) &&
 	    !data->case_sensitive_msg_shown) {
 		error(_("You're on a case-insensitive filesystem, and the remote you are\n"
 			"trying to fetch from has references that only differ in casing. It\n"
diff --git a/builtin/mv.c b/builtin/mv.c
index 948b330639..d60582262c 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -419,7 +419,7 @@ int cmd_mv(int argc,
 			goto act_on_entry;
 		}
 		if (lstat(dst, &st) == 0 &&
-		    (!ignore_case || strcasecmp(src, dst))) {
+		    (!repo_ignore_case(the_repository) || strcasecmp(src, dst))) {
 			bad = _("destination exists");
 			if (force) {
 				/*
diff --git a/compat/win32/path-utils.c b/compat/win32/path-utils.c
index 966ef779b9..f779f367cf 100644
--- a/compat/win32/path-utils.c
+++ b/compat/win32/path-utils.c
@@ -2,6 +2,7 @@
 
 #include "../../git-compat-util.h"
 #include "../../environment.h"
+#include "../../repository.h"
 
 int win32_has_dos_drive_prefix(const char *path)
 {
@@ -75,7 +76,7 @@ int win32_fspathncmp(const char *a, const char *b, size_t count)
 		} else if (is_dir_sep(*b))
 			return +1;
 
-		diff = ignore_case ?
+		diff = repo_ignore_case(the_repository) ?
 			(unsigned char)tolower(*a) - (int)(unsigned char)tolower(*b) :
 			(unsigned char)*a - (int)(unsigned char)*b;
 		if (diff)
diff --git a/dir.c b/dir.c
index 33c81c256e..540dd372c1 100644
--- a/dir.c
+++ b/dir.c
@@ -126,7 +126,7 @@ int count_slashes(const char *s)
 
 int git_fspathcmp(const char *a, const char *b)
 {
-	return ignore_case ? strcasecmp(a, b) : strcmp(a, b);
+	return repo_ignore_case(the_repository) ? strcasecmp(a, b) : strcmp(a, b);
 }
 
 int fspatheq(const char *a, const char *b)
@@ -136,7 +136,7 @@ int fspatheq(const char *a, const char *b)
 
 int git_fspathncmp(const char *a, const char *b, size_t count)
 {
-	return ignore_case ? strncasecmp(a, b, count) : strncmp(a, b, count);
+	return repo_ignore_case(the_repository) ? strncasecmp(a, b, count) : strncmp(a, b, count);
 }
 
 int paths_collide(const char *a, const char *b)
@@ -153,7 +153,7 @@ int paths_collide(const char *a, const char *b)
 
 unsigned int fspathhash(const char *str)
 {
-	return ignore_case ? strihash(str) : strhash(str);
+	return repo_ignore_case(the_repository) ? strihash(str) : strhash(str);
 }
 
 int git_fnmatch(const struct pathspec_item *item,
@@ -202,7 +202,7 @@ static int fnmatch_icase_mem(const char *pattern, int patternlen,
 		use_str = str_buf.buf;
 	}
 
-	if (ignore_case)
+	if (repo_ignore_case(the_repository))
 		flags |= WM_CASEFOLD;
 	match_status = wildmatch(use_pat, use_str, flags);
 
@@ -1851,7 +1851,7 @@ static struct dir_entry *dir_add_name(struct dir_struct *dir,
 				      struct index_state *istate,
 				      const char *pathname, int len)
 {
-	if (index_file_exists(istate, pathname, len, ignore_case))
+	if (index_file_exists(istate, pathname, len, repo_ignore_case(the_repository)))
 		return NULL;
 
 	ALLOC_GROW(dir->entries, dir->nr+1, dir->internal.alloc);
@@ -1888,7 +1888,7 @@ static enum exist_status directory_exists_in_index_icase(struct index_state *ist
 	if (index_dir_exists(istate, dirname, len))
 		return index_directory;
 
-	ce = index_file_exists(istate, dirname, len, ignore_case);
+	ce = index_file_exists(istate, dirname, len, repo_ignore_case(the_repository));
 	if (ce && S_ISGITLINK(ce->ce_mode))
 		return index_gitdir;
 
@@ -1907,7 +1907,7 @@ static enum exist_status directory_exists_in_index(struct index_state *istate,
 {
 	int pos;
 
-	if (ignore_case)
+	if (repo_ignore_case(the_repository))
 		return directory_exists_in_index_icase(istate, dirname, len);
 
 	pos = index_name_pos(istate, dirname, len);
@@ -2447,7 +2447,7 @@ static enum path_treatment treat_path(struct dir_struct *dir,
 
 	/* Always exclude indexed files */
 	has_path_in_index = !!index_file_exists(istate, path->buf, path->len,
-						ignore_case);
+						repo_ignore_case(the_repository));
 	if (dtype != DT_DIR && has_path_in_index)
 		return path_none;
 
@@ -3201,7 +3201,7 @@ static int cmp_icase(char a, char b)
 {
 	if (a == b)
 		return 0;
-	if (ignore_case)
+	if (repo_ignore_case(the_repository))
 		return toupper(a) - toupper(b);
 	return a - b;
 }
diff --git a/environment.c b/environment.c
index bfa3cb3045..c288c3613d 100644
--- a/environment.c
+++ b/environment.c
@@ -46,7 +46,6 @@ int trust_ctime = 1;
 int check_stat = 1;
 int has_symlinks = 1;
 int minimum_abbrev = 4, default_abbrev = -1;
-int ignore_case;
 int assume_unchanged;
 int is_bare_repository_cfg = -1; /* unspecified */
 int warn_on_object_refname_ambiguity = 1;
@@ -342,7 +341,7 @@ int git_default_core_config(const char *var, const char *value,
 	}
 
 	if (!strcmp(var, "core.ignorecase")) {
-		ignore_case = git_config_bool(var, value);
+		cfg->ignore_case = git_config_bool(var, value);
 		return 0;
 	}
 
diff --git a/environment.h b/environment.h
index 39a8bf0b49..c15121db65 100644
--- a/environment.h
+++ b/environment.h
@@ -171,7 +171,6 @@ extern int trust_ctime;
 extern int check_stat;
 extern int has_symlinks;
 extern int minimum_abbrev, default_abbrev;
-extern int ignore_case;
 extern int assume_unchanged;
 extern int warn_on_object_refname_ambiguity;
 extern char *apply_default_whitespace;
diff --git a/fsmonitor.c b/fsmonitor.c
index d07dc18967..107767527e 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -453,7 +453,7 @@ static void fsmonitor_refresh_callback(struct index_state *istate, char *name)
 	 * case-insensitive file system, try again using the name-hash
 	 * and dir-name-hash.
 	 */
-	if (!nr_in_cone && ignore_case) {
+	if (!nr_in_cone && repo_ignore_case(the_repository)) {
 		nr_in_cone = handle_using_name_hash_icase(istate, name);
 		if (!nr_in_cone)
 			nr_in_cone = handle_using_dir_name_hash_icase(
diff --git a/name-hash.c b/name-hash.c
index b91e276267..83757db874 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -126,7 +126,7 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)
 		hashmap_add(&istate->name_hash, &ce->ent);
 	}
 
-	if (ignore_case)
+	if (repo_ignore_case(the_repository))
 		add_dir_entry(istate, ce);
 }
 
@@ -207,7 +207,7 @@ static int lookup_lazy_params(struct index_state *istate)
 	 * code to build the "istate->name_hash".  We don't
 	 * need the complexity here.
 	 */
-	if (!ignore_case)
+	if (!repo_ignore_case(the_repository))
 		return 0;
 
 	nr_cpus = online_cpus();
@@ -651,7 +651,7 @@ void remove_name_hash(struct index_state *istate, struct cache_entry *ce)
 	ce->ce_flags &= ~CE_HASHED;
 	hashmap_remove(&istate->name_hash, &ce->ent, ce);
 
-	if (ignore_case)
+	if (repo_ignore_case(the_repository))
 		remove_dir_entry(istate, ce);
 }
 
diff --git a/read-cache.c b/read-cache.c
index 21829102ae..fcdf0e5ef1 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -760,12 +760,12 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
 	 * case of the file being added to the repository matches (is folded into) the existing
 	 * entry's directory case.
 	 */
-	if (ignore_case) {
+	if (repo_ignore_case(the_repository)) {
 		adjust_dirname_case(istate, ce->name);
 	}
 	if (!(flags & ADD_CACHE_RENORMALIZE)) {
 		alias = index_file_exists(istate, ce->name,
-					  ce_namelen(ce), ignore_case);
+					  ce_namelen(ce), repo_ignore_case(the_repository));
 		if (alias &&
 		    !ce_stage(alias) &&
 		    !ie_match_stat(istate, alias, st, ce_option)) {
@@ -786,7 +786,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
 	} else
 		set_object_name_for_intent_to_add_entry(ce);
 
-	if (ignore_case && alias && different_name(ce, alias))
+	if (repo_ignore_case(the_repository) && alias && different_name(ce, alias))
 		ce = create_alias_ce(istate, ce, alias);
 	ce->ce_flags |= CE_ADDED;
 
diff --git a/refs/files-backend.c b/refs/files-backend.c
index a4c7858787..c1da06b1d5 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -806,7 +806,7 @@ static enum ref_transaction_error lock_raw_ref(struct files_ref_store *refs,
 		} else {
 			unable_to_lock_message(ref_file.buf, myerr, err);
 			if (myerr == EEXIST) {
-				if (ignore_case &&
+				if (repo_ignore_case(the_repository) &&
 				    transaction_has_case_conflicting_update(transaction, update)) {
 					/*
 					 * In case-insensitive filesystems, ensure that conflicts within a
@@ -920,7 +920,7 @@ static enum ref_transaction_error lock_raw_ref(struct files_ref_store *refs,
 		 * conflicts between 'foo' and 'Foo/bar'. So let's lowercase
 		 * the refname.
 		 */
-		if (ignore_case) {
+		if (repo_ignore_case(the_repository)) {
 			struct strbuf lower = STRBUF_INIT;
 
 			strbuf_addstr(&lower, refname);
diff --git a/submodule.c b/submodule.c
index a939ff5072..6e7f8b9f7c 100644
--- a/submodule.c
+++ b/submodule.c
@@ -2389,7 +2389,7 @@ static int validate_submodule_encoded_git_dir(char *git_dir, const char *submodu
 
 	/* Prevent conflicts on case-folding filesystems */
 	repo_config_get_bool(the_repository, "core.ignorecase", &config_ignorecase);
-	if (ignore_case || config_ignorecase) {
+	if (repo_ignore_case(the_repository) || config_ignorecase) {
 		bool suffixes_match = !strcmp(last_submodule_name, submodule_name);
 		return check_casefolding_conflict(git_dir, submodule_name,
 						  suffixes_match);
diff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c
index e542985c94..43cead6d7d 100644
--- a/t/helper/test-lazy-init-name-hash.c
+++ b/t/helper/test-lazy-init-name-hash.c
@@ -218,7 +218,7 @@ int cmd__lazy_init_name_hash(int argc, const char **argv)
 	/*
 	 * istate->dir_hash is only created when ignore_case is set.
 	 */
-	ignore_case = 1;
+	repo_config_values(the_repository)->ignore_case = 1;
 
 	if (dump) {
 		if (perf || analyze > 0)
diff --git a/unpack-trees.c b/unpack-trees.c
index 998a1e6dc7..d13b004f71 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -2428,7 +2428,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
 	 *
 	 * Ignore that lstat() if it matches.
 	 */
-	if (ignore_case && icase_exists(o, name, len, st))
+	if (repo_ignore_case(the_repository) && icase_exists(o, name, len, st))
 		return 0;
 
 	if (o->internal.dir &&
-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 1/2] environment: move ignore_case into repo_config_values
From: Tian Yuchen @ 2026-06-18 11:42 UTC (permalink / raw)
  To: git
  Cc: ps, phillip.wood123, johannes.schindelin, stolee, Tian Yuchen,
	Christian Couder, Ayush Chandekar, Olamide Caleb Bello
In-Reply-To: <20260618114207.605211-1-cat@malon.dev>

The 'core.ignorecase' configuration which is stored as the
global variable 'ignore_case' acts as a core filesystem
capability flag.

Move this global variable into 'struct repo_config_values' to tie it
to the specific repository instance it was read from. This reduces
global state and aligns with the ongoing libification effort.

To ensure code readability, the getter function
'repo_ignore_case()' is introduced.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Ayush Chandekar <ayu.chandekar@gmail.com>
Mentored-by: Olamide Caleb Bello <belkid98@gmail.com>
Signed-off-by: Tian Yuchen <cat@malon.dev>
---
 environment.c | 8 ++++++++
 environment.h | 8 ++++++++
 2 files changed, 16 insertions(+)

diff --git a/environment.c b/environment.c
index fc3ed8bb1c..bfa3cb3045 100644
--- a/environment.c
+++ b/environment.c
@@ -142,6 +142,13 @@ int is_bare_repository(void)
 	return is_bare_repository_cfg && !repo_get_work_tree(the_repository);
 }
 
+int repo_ignore_case(struct repository *repo)
+{
+	return (repo && repo->initialized) ?
+		repo_config_values(repo)->ignore_case :
+		0;
+}
+
 int have_git_dir(void)
 {
 	return startup_info->have_repository
@@ -720,5 +727,6 @@ void repo_config_values_init(struct repo_config_values *cfg)
 {
 	cfg->attributes_file = NULL;
 	cfg->apply_sparse_checkout = 0;
+	cfg->ignore_case = 0;
 	cfg->branch_track = BRANCH_TRACK_REMOTE;
 }
diff --git a/environment.h b/environment.h
index 9eb97b3869..39a8bf0b49 100644
--- a/environment.h
+++ b/environment.h
@@ -91,6 +91,7 @@ struct repo_config_values {
 	/* section "core" config values */
 	char *attributes_file;
 	int apply_sparse_checkout;
+	int ignore_case;
 
 	/* section "branch" config values */
 	enum branch_track branch_track;
@@ -123,6 +124,13 @@ int git_default_config(const char *, const char *,
 int git_default_core_config(const char *var, const char *value,
 			    const struct config_context *ctx, void *cb);
 
+/*
+ * Getter for the `ignore_case` field of `struct repo_config_values`.
+ * It checks `repo->initialized` to prevent calling repo_config_values()`
+ * before the repository setup is fully complete or in non-git environments.
+ */
+int repo_ignore_case(struct repository *repo);
+
 void repo_config_values_init(struct repo_config_values *cfg);
 
 /*
-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 0/2] environment: move ignore_case into repo_config_values
From: Tian Yuchen @ 2026-06-18 11:42 UTC (permalink / raw)
  To: git; +Cc: ps, phillip.wood123, johannes.schindelin, stolee, Tian Yuchen
In-Reply-To: <20260617154929.564498-1-cat@malon.dev>

The 'core.ignorecase' configuration, stored as the global variable
'ignore_case', acts as a core filesystem capability flag.

This series continues the ongoing libification effort by moving
this global variable into 'struct repo_config_values', tying it
to the specific repository instance it was read from. This allows
us to encapsulate the configuration without altering its
eager-parsing behavior.

The getter function 'repo_ignore_case()' is introduced so
that we can safely retrieve the configuration value whilst
maintaining the correct fallback logic.

RFC Questions:

dir.c --- Performance overhead?

compat/win32/path-utils.c --- Is it appropriate to include the
repository.h header file?

Related materials:

 [1] In this patch to migrate protect_hfs and protect_ntfs, the approach
of introducing getters has been endorsed.

 [2] Derrick Stolee's previous attempt. The reasons for the failure are
also mentioned in [1].

Changes since V1:

 - s/repo_get_ignore_case()/repo_ignore_case()

 - Use repo->initialized instead of repo->gitdir

Thanks!

Mentored-by: Christian Couder christian.couder@gmail.com
Mentored-by: Ayush Chandekar ayu.chandekar@gmail.com
Mentored-by: Olamide Caleb Bello belkid98@gmail.com
Signed-off-by: Tian Yuchen cat@malon.dev

[1] https://lore.kernel.org/git/20260606143412.15443-1-cat@malon.dev/
[2] https://lore.kernel.org/git/2b4198c09cb6c04c60608d19072d419503dfe5df.1685716421.git.gitgitgadget@gmail.com/

Tian Yuchen (2):
  environment: move ignore_case into repo_config_values
  config: use repo_ignore_case() to access core.ignorecase

 apply.c                             |  2 +-
 builtin/fetch.c                     |  2 +-
 builtin/mv.c                        |  2 +-
 compat/win32/path-utils.c           |  3 ++-
 dir.c                               | 18 +++++++++---------
 environment.c                       | 11 +++++++++--
 environment.h                       |  9 ++++++++-
 fsmonitor.c                         |  2 +-
 name-hash.c                         |  6 +++---
 read-cache.c                        |  6 +++---
 refs/files-backend.c                |  4 ++--
 submodule.c                         |  2 +-
 t/helper/test-lazy-init-name-hash.c |  2 +-
 unpack-trees.c                      |  2 +-
 14 files changed, 43 insertions(+), 28 deletions(-)

-- 
2.43.0


^ permalink raw reply

* Re: [PATCH 1/2] environment: move ignore_case into repo_config_values
From: Tian Yuchen @ 2026-06-18 10:56 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: git, ps, phillip.wood123, johannes.schindelin, stolee,
	Christian Couder, Ayush Chandekar, Olamide Caleb Bello
In-Reply-To: <xmqqh5n1w0i7.fsf@gitster.g>

On 6/18/26 01:16, Junio C Hamano wrote:
> Tian Yuchen <cat@malon.dev> writes:
> 
>> Note that the newly introduced getter, 'repo_get_ignore_case()',
>> intentionally avoids checking 'repo->gitdir'. This could safely
>> accommodates early dynamic probing of the filesystem during
>> 'git init' or clone operations, where the 'gitdir' might not be fully
>> initialized but the filesystem capability must be recorded.
> 
> Why "could"?  It either "safely accommodates" or it doesn't.
> 

Okay, will change in the next reroll.

> I do not quite understand the logic behind this part.  Why is it OK
> to punt until .gitdir is ready for trust-executable-bit, like it is
> done in f951ed98 (environment: move trust_executable_bit into
> repo_config_values, 2026-06-13)
> 
> diff --git a/environment.c b/environment.c
> index fc3ed8bb1c..75069a884d 100644
> --- a/environment.c
> +++ b/environment.c
> @@ -142,6 +141,13 @@ int is_bare_repository(void)
>   	return is_bare_repository_cfg && !repo_get_work_tree(the_repository);
>   }
>   
> +int repo_trust_executable_bit(struct repository *repo)
> +{
> +	return repo->gitdir?
> +		repo_config_values(repo)->trust_executable_bit :
> +		1;
> +}
> +
> 
> or hfs/ntfs in 71386c21 (environment: move 'protect_hfs' and
> 'protect_ntfs' into 'repo_config_values', 2026-06-10)
> 
> diff --git a/environment.c b/environment.c
> index fc3ed8bb1c..683fe1b4d3 100644
> --- a/environment.c
> +++ b/environment.c
> @@ -142,6 +140,20 @@ int is_bare_repository(void)
>   	return is_bare_repository_cfg && !repo_get_work_tree(the_repository);
>   }
>   
> +int repo_protect_ntfs(struct repository *repo)
> +{
> +	return repo->gitdir ?
> +		repo_config_values(repo)->protect_ntfs :
> +		PROTECT_NTFS_DEFAULT;
> +}
> +
> +int repo_protect_hfs(struct repository *repo)
> +{
> +	return repo->gitdir ?
> +		repo_config_values(repo)->protect_hfs :
> +		PROTECT_HFS_DEFAULT;
> +}
> +
>   int have_git_dir(void)
>   {
>   	return startup_info->have_repository
> 
> but not for this bit?

You're right, I made a mistake.

Earlier, when I was testing using 'repo->gitdir', the CI tests failed, 
and I thought it was because the test script was forcing initial values 
too early. I just realized the error was somewhere else. I'll fix it.

> 
>> +int repo_get_ignore_case(struct repository *repo)
>> +{
>> +	if (repo)
>> +		return repo_config_values(repo)->ignore_case;
>> +	return 0;
>> +}
> 
> What makes ignore-case so special?  Doesn't the same logic apply to
> the other three bits?
> 
> Or use a more direct
> 
> 	if (repo && repo->initialized)
> 		...;
> 
> for all three, as repo_config_values(repo) barfs when repo is not
> initialized?
> 
> I dunno.

That makes some sense. The reasoning behind using 'repo->gitdir' is that 
"as long as I know where .git is, I assume the repository has been 
initialized," which may indeed be less precise than 'repo->initialized'.

Btw, I think it's better to change the getter's name from 
'repo_get_ignore_case()' to 'repo_ignore_case()'. This way, it will be 
consistent with the previous flags.

Thanks, yuchen

^ permalink raw reply

* Re: [PATCH] SubmittingPatches: address design critiques
From: Kristoffer Haugsbakk @ 2026-06-18  8:55 UTC (permalink / raw)
  To: Michael Montalbo, Junio C Hamano; +Cc: git
In-Reply-To: <CAC2QwmJdF+YzAQE3WDEaUrurLVkYcAA0Cgs1YAqyxYcQ0jKfqA@mail.gmail.com>

On Thu, Jun 18, 2026, at 05:53, Michael Montalbo wrote:
> Junio C Hamano wrote:
>>[snip]
>
> Two small suggestions: open with a direct imperative and replace
> "effort in the implementation" with "effort on the implementation".
>[snip]

The threading doesn’t work here. This is in reply to:

https://lore.kernel.org/git/xmqqv7bhxiby.fsf@gitster.g/

But your email has no `In-Reply-To` header.

^ permalink raw reply

* [PATCH v2] SubmittingPatches: address design critiques
From: Junio C Hamano @ 2026-06-18  8:50 UTC (permalink / raw)
  To: git
In-Reply-To: <xmqqv7bhxiby.fsf@gitster.g>

Contributors sometimes fail to answer fundamental design or
viability comments from reviewers and submit subsequent rounds
without addressing them.  When design decisions are resolved on the
mailing list, the final justification should be recorded in the
commit messages.

Instruct authors to be particularly mindful of critiques regarding
high-level design or viability, to defend their choices on the list,
and to accompany new iterations with clearer explanations in the cover
letter, responses, and revised commit messages. Also instruct them to
explicitly document the resolution of these concerns in the commit
message body to keep the historical record complete.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---

 * Rephrased the instruction in the first hunk somewhat to be a bit
   more explicit, and added a missing verb to the second hunk.

 Documentation/SubmittingPatches | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index f042bb5aaf..bbe759f3d9 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -51,6 +51,21 @@ area.
   respond to them with "Reply-All" on the mailing list, while taking
   them into account while preparing an updated set of patches.
 +
+You should be particularly mindful of critiques regarding the
+high-level design or viability of your proposal (e.g., questioning
+whether the feature is worth implementing, or if the chosen approach
+is appropriate).  Defend your design decisions on the list first, to
+avoid wasting effort on an implementation whose design is not yet
+solid.
++
+Make sure that any new version is accompanied by a much clearer
+explanation and justification (in the cover letter, your responses,
+and in the revised commit messages).  Aim to make the reviewers say
+"it is now clear why we may want to do this with the updated version".
++
+Topics that fail to address fundamental design critiques without
+resolution will not be considered ready for merging.
++
 It is often beneficial to allow some time for reviewers to provide
 feedback before sending a new version, rather than sending an updated
 series immediately after receiving a review. This helps collect broader
@@ -323,6 +338,10 @@ The body should provide a meaningful commit message, which:
 
 . alternate solutions considered but discarded, if any.
 
+. records the resolution of design or viability concerns raised by the
+  community during the review, if any, ensuring the historical record
+  explains why the chosen approach was accepted over alternatives.
+
 [[present-tense]]
 The problem statement that describes the status quo is written in the
 present tense.  Write "The code does X when it is given input Y",

Range-diff against v1:
1:  eb5f96ab04 ! 1:  aecdcf0bda SubmittingPatches: address design critiques
    @@ Documentation/SubmittingPatches: area.
        respond to them with "Reply-All" on the mailing list, while taking
        them into account while preparing an updated set of patches.
      +
    -+You would want to be particularly mindful of critiques regarding the
    ++You should be particularly mindful of critiques regarding the
     +high-level design or viability of your proposal (e.g., questioning
     +whether the feature is worth implementing, or if the chosen approach
    -+is appropriate).  You want to defend your design decisions on the list
    -+first, because you do not want to spend too much effort in the
    -+implementation if the design is not yet solid.
    ++is appropriate).  Defend your design decisions on the list first, to
    ++avoid wasting effort on an implementation whose design is not yet
    ++solid.
     ++
    -+Also, make sure that any new version is accompanied by a much clearer
    ++Make sure that any new version is accompanied by a much clearer
     +explanation and justification (in the cover letter, your responses,
     +and in the revised commit messages).  Aim to make the reviewers say
     +"it is now clear why we may want to do this with the updated version".
    @@ Documentation/SubmittingPatches: The body should provide a meaningful commit mes
      
      . alternate solutions considered but discarded, if any.
      
    -+. the resolution of design or viability concerns raised by the
    ++. records the resolution of design or viability concerns raised by the
     +  community during the review, if any, ensuring the historical record
     +  explains why the chosen approach was accepted over alternatives.
     +
-- 
2.55.0-rc1-93-ge727df1850


^ permalink raw reply related

* [ANNOUNCE] Git for Windows 2.55.0-rc1
From: Johannes Schindelin @ 2026-06-18  7:07 UTC (permalink / raw)
  To: git, git-packagers

Dear Git users,

I hereby announce that Git for Windows 2.55.0-rc1 is available from:

    https://github.com/git-for-windows/git/releases/tag/v2.55.0-rc1.windows.1

Changes since Git for Windows v2.54.0 (April 20th 2026)

Following the MSYS2 project, on which Git for Windows is based, Windows
8.1 support will be dropped after Git for Windows v2.55.

New Features

  * Comes with Git v2.55.0-rc1.
  * Comes with the MSYS2 runtime (Git for Windows flavor) based on
    Cygwin v3.6.9.
  * Comes with Git Credential Manager v2.8.0.
  * Comes with cURL v8.20.0.
  * Comes with less 702.
  * The FSCache now accelerates more git add scenarios.
  * Comes with OpenSSL v3.5.7.
  * The diff helper handling Word documents was ported from Perl to
    Rust.
  * Comes with Bash v5.3.15.

Bug Fixes

  * A regression in v2.54.0 that could cause endless "Unlink of file
    '.git/objects/pack/pack-.idx' failed. Should I try again?" loops on
    older Windows 10 versions during git fetch operations was fixed.
  * A bug that prevented proper shutdown of processes launched via Git
    Bash under certain circumstances was fixed.
  * A bug was fixed which could cause parallel checkouts to fail under
    certain circumstances when the FSCache is enabled.
  * Git Bash (MinTTY) now respects screen scaling settings under more
    circumstances.

Git-2.55.0-rc1-64-bit.exe | 40ccf96f6cb90e1c1e987108d339bf59cf883f4f62fe1d811bf7f453f216a3c2
Git-2.55.0-rc1-arm64.exe | 32ea9f89ebdcb4b5386bb8d91ac09bddca05f97aab2bb97f3a30e4a2ee13dfd7
PortableGit-2.55.0-rc1-64-bit.7z.exe | cea2707ee1a25ef33d9db4235c1b4ae33d22c2fe618dd3d4ec8574b34ec6f3d9
PortableGit-2.55.0-rc1-arm64.7z.exe | 70da0c29b0c60d7417d698c0d1850a2c409ab89cf9d5431ab75ff203356f5132
MinGit-2.55.0-rc1-64-bit.zip | bb7d17aa2e1cf1b015b7fe2f0312465fa0e035699b0970a5898c07595a61985f
MinGit-2.55.0-rc1-arm64.zip | 49df32406f57d2886c93acf8ce2fcb9640a1b73c1829fdbb36ea069c41d216c7
MinGit-2.55.0-rc1-32-bit.zip | 7d8c7828ee2490d406a4a9132a6a2e61f955c26c0a9cdebaf05ccde9bf156ebb
MinGit-2.55.0-rc1-busybox-64-bit.zip | 22abdf14fceaa1172a3416df33fb535a790faab7584a8ba903f3f88d4d0c45af
MinGit-2.55.0-rc1-busybox-32-bit.zip | 0139489b7baae8c9738cd3ea8dcbaf946c4f758716e9d64a6b2491db0c0cc229
Git-2.55.0-rc1-64-bit.tar.bz2 | 87be9bf3d21a53b6e415e0650b4c4632e4226ae9c148a6d5b090e3521d5cfa6e
Git-2.55.0-rc1-arm64.tar.bz2 | 9d7786f3dfb29d1715ff2a73a0f08abcd298fe610c70d1117dcffdb0d15e43ce

Ciao,
Johannes

^ permalink raw reply

* [PATCH v3 8/8] refs: drop local buffer in `refs_compute_filesystem_location()`
From: Patrick Steinhardt @ 2026-06-18  6:54 UTC (permalink / raw)
  To: git; +Cc: Karthik Nayak, Jeff King, Justin Tobler
In-Reply-To: <20260618-b4-pks-refs-avoid-chdir-notify-reparent-v3-0-2a5669e8f486@pks.im>

We're using a local buffer in `refs_compute_filesystem_location()` that
is only used so that we can fill it and then call `strbuf_realpath()` on
its result. This roundtrip isn't necessary though: `strbuf_realpath()`
already knows to use a single buffer as both input and output at the
same time. So all this does is to add a bit of confusion and an extra
memory allocation.

Drop the local buffer.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 refs.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/refs.c b/refs.c
index e69b9b8ac8..4912510590 100644
--- a/refs.c
+++ b/refs.c
@@ -3571,8 +3571,6 @@ void refs_compute_filesystem_location(const char *gitdir, const char *payload,
 				      bool *is_worktree, struct strbuf *refdir,
 				      struct strbuf *ref_common_dir)
 {
-	struct strbuf sb = STRBUF_INIT;
-
 	*is_worktree = get_common_dir_noenv(ref_common_dir, gitdir);
 
 	if (!payload) {
@@ -3586,8 +3584,8 @@ void refs_compute_filesystem_location(const char *gitdir, const char *payload,
 	}
 
 	if (!is_absolute_path(payload)) {
-		strbuf_addf(&sb, "%s/%s", ref_common_dir->buf, payload);
-		strbuf_realpath(ref_common_dir, sb.buf, 1);
+		strbuf_addf(ref_common_dir, "/%s", payload);
+		strbuf_realpath(ref_common_dir, ref_common_dir->buf, 1);
 	} else {
 		strbuf_realpath(ref_common_dir, payload, 1);
 	}
@@ -3600,6 +3598,4 @@ void refs_compute_filesystem_location(const char *gitdir, const char *payload,
 			BUG("worktree path does not contain slash");
 		strbuf_addf(refdir, "/worktrees/%s", wt_id + 1);
 	}
-
-	strbuf_release(&sb);
 }

-- 
2.55.0.rc0.786.g65d90a0328.dirty


^ permalink raw reply related

* [PATCH v3 7/8] refs: fix recursing `get_main_ref_store()` with "onbranch" config
From: Patrick Steinhardt @ 2026-06-18  6:54 UTC (permalink / raw)
  To: git; +Cc: Karthik Nayak, Jeff King, Justin Tobler
In-Reply-To: <20260618-b4-pks-refs-avoid-chdir-notify-reparent-v3-0-2a5669e8f486@pks.im>

When we have an "onbranch" condition we need to ask the reference
database whether HEAD currently points at the configured branch. This
unfortunately creates a chicken-and-egg problem:

  - The reference database needs to read the configuration so that it
    can configure itself.

  - The configuration needs to construct a reference database to fully
    parse all of its conditionals.

The way we handle this is by simply excluding "onbranch" conditionals
when we haven't yet configured the reference database.

The mechanism for this is broken though: to verify whether or not we
have configured the reference database we check whether its format is
set to `REF_STORAGE_UNKNOWN` in `include_by_branch()`. But typically,
the format _is_ already known at that time because we set it up during
repository discovery in "setup.c".

The consequence is that we have recursion:

  1. We call `get_main_ref_store()`.

  2. We don't yet have a reference store, so we call `ref_store_init()`.

  3. We parse the configuration required for the reference store.

  4. We eventually end up in `include_by_branch()`.

  5. We have already configured the reference storage format, so we end
     up calling `get_main_ref_store()` again.

We still haven't finished (1) though, so `get_main_ref_store()` will now
call `ref_store_init()` a second time. The end result is that we have
constructed the same reference store twice.

Of course, as both reference stores would be assigned to `refs_private`,
we leak one of those two instances. This never surfaced as an actual
leak though because the pointer is kept alive by the "chdir_notify"
subsystem.

For now, we can fix the issue by explicitly unsetting the reference
storage format before constructing it. This makes the mentioned check
trigger as expected, and consequently we won't end up constructing a
second reference database at all. Ultimately, this means that we
consistently stop evaluating "onbranch" conditions when constructing the
main reference database.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 refs.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/refs.c b/refs.c
index d3caa9a633..e69b9b8ac8 100644
--- a/refs.c
+++ b/refs.c
@@ -2351,15 +2351,31 @@ void ref_store_release(struct ref_store *ref_store)
 
 struct ref_store *get_main_ref_store(struct repository *r)
 {
+	enum ref_storage_format format;
+
 	if (r->refs_private)
 		return r->refs_private;
 
 	if (!r->gitdir)
 		BUG("attempting to get main_ref_store outside of repository");
 
-	r->refs_private = ref_store_init(r, r->ref_storage_format,
-					 r->gitdir, REF_STORE_ALL_CAPS);
+	/*
+	 * When constructing the reference backend we'll end up reading the Git
+	 * configuration. This means we'll also try to evaluate "onbranch"
+	 * conditions.
+	 *
+	 * We cannot read branches when constructing the refdb, so it is not
+	 * possible to evaluate those conditions in the first place. To gate
+	 * their evaluation we check whether or not the reference storage
+	 * format has been configured -- we thus have to temporarily set it to
+	 * UNKNOWN here so that we don't end up recursing.
+	 */
+	format = r->ref_storage_format;
+	r->ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
+	r->refs_private = ref_store_init(r, format, r->gitdir, REF_STORE_ALL_CAPS);
 	r->refs_private = maybe_debug_wrap_ref_store(r->gitdir, r->refs_private);
+	r->ref_storage_format = format;
+
 	return r->refs_private;
 }
 

-- 
2.55.0.rc0.786.g65d90a0328.dirty


^ permalink raw reply related

* [PATCH v3 6/8] repository: free main reference database
From: Patrick Steinhardt @ 2026-06-18  6:54 UTC (permalink / raw)
  To: git; +Cc: Karthik Nayak, Jeff King, Justin Tobler
In-Reply-To: <20260618-b4-pks-refs-avoid-chdir-notify-reparent-v3-0-2a5669e8f486@pks.im>

While we release worktree and submodule reference databases when
clearing a repository, we don't ever release the main reference
database. This memory leak went unnoticed because its pointer is
kept alive by the "chdir_notify" subsystem.

Fix the memory leak.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 repository.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/repository.c b/repository.c
index 187dd471c4..e2b5c6712b 100644
--- a/repository.c
+++ b/repository.c
@@ -421,6 +421,11 @@ void repo_clear(struct repository *repo)
 		FREE_AND_NULL(repo->remote_state);
 	}
 
+	if (repo->refs_private) {
+		ref_store_release(repo->refs_private);
+		FREE_AND_NULL(repo->refs_private);
+	}
+
 	strmap_for_each_entry(&repo->submodule_ref_stores, &iter, e)
 		ref_store_release(e->value);
 	strmap_clear(&repo->submodule_ref_stores, 1);

-- 
2.55.0.rc0.786.g65d90a0328.dirty


^ permalink raw reply related

* [PATCH v3 5/8] chdir-notify: drop unused `chdir_notify_reparent()`
From: Patrick Steinhardt @ 2026-06-18  6:54 UTC (permalink / raw)
  To: git; +Cc: Karthik Nayak, Jeff King, Justin Tobler
In-Reply-To: <20260618-b4-pks-refs-avoid-chdir-notify-reparent-v3-0-2a5669e8f486@pks.im>

With the preceding commit we've removed all callers of
`chdir_notify_reparent()`, so the function is unused now. Drop it.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 chdir-notify.c | 26 --------------------------
 chdir-notify.h |  6 +-----
 2 files changed, 1 insertion(+), 31 deletions(-)

diff --git a/chdir-notify.c b/chdir-notify.c
index f8bfe3cbef..1237a45e2e 100644
--- a/chdir-notify.c
+++ b/chdir-notify.c
@@ -43,32 +43,6 @@ void chdir_notify_unregister(const char *name, chdir_notify_callback cb,
 	}
 }
 
-static void reparent_cb(const char *name,
-			const char *old_cwd,
-			const char *new_cwd,
-			void *data)
-{
-	char **path = data;
-	char *tmp = *path;
-
-	if (!tmp)
-		return;
-
-	*path = reparent_relative_path(old_cwd, new_cwd, tmp);
-	free(tmp);
-
-	if (name) {
-		trace_printf_key(&trace_setup_key,
-				 "setup: reparent %s to '%s'",
-				 name, *path);
-	}
-}
-
-void chdir_notify_reparent(const char *name, char **path)
-{
-	chdir_notify_register(name, reparent_cb, path);
-}
-
 int chdir_notify(const char *new_cwd)
 {
 	struct strbuf old_cwd = STRBUF_INIT;
diff --git a/chdir-notify.h b/chdir-notify.h
index 81eb69d846..36b4114472 100644
--- a/chdir-notify.h
+++ b/chdir-notify.h
@@ -19,10 +19,7 @@
  *   chdir_notify_register("description", foo, data);
  *
  * In practice most callers will want to move a relative path to the new root;
- * they can use the reparent_relative_path() helper for that. If that's all
- * you're doing, you can also use the convenience function:
- *
- *   chdir_notify_reparent("description", &my_path);
+ * they can use the reparent_relative_path() helper for that.
  *
  * Whenever a chdir event occurs, that will update my_path (if it's relative)
  * to adjust for the new cwd by freeing any existing string and allocating a
@@ -43,7 +40,6 @@ typedef void (*chdir_notify_callback)(const char *name,
 void chdir_notify_register(const char *name, chdir_notify_callback cb, void *data);
 void chdir_notify_unregister(const char *name, chdir_notify_callback cb,
 			     void *data);
-void chdir_notify_reparent(const char *name, char **path);
 
 /*
  *

-- 
2.55.0.rc0.786.g65d90a0328.dirty


^ permalink raw reply related

* [PATCH v3 4/8] refs: unregister reference stores from "chdir_notify"
From: Patrick Steinhardt @ 2026-06-18  6:54 UTC (permalink / raw)
  To: git; +Cc: Karthik Nayak, Jeff King, Justin Tobler
In-Reply-To: <20260618-b4-pks-refs-avoid-chdir-notify-reparent-v3-0-2a5669e8f486@pks.im>

When creating reference stores we register them with the "chdir_notify"
subsystem. This is required because some of the paths we track may be
relative paths, so we have to reparent them in case the current working
directory changes.

But while we register the reference stores, we never unregister them.
This can have multiple outcomes:

  - For a repository's main reference database we essentially keep the
    pointer alive. We never free that database, either, and our leak
    checker doesn't notice because it's still registered.

  - For submodule and worktree reference databases we do eventually free
    them in `repo_clear()`, so we may keep pointers to free'd memory
    registered. We never notice though as we don't tend to chdir around
    in the middle of the process.

We never noticed either of these symptoms, but they are obviously bad.

Partially fix those issues by unregistering the reference stores when
releasing them. The leak of the main reference database will be fixed in
a subsequent commit.

Note that this requires us to use `chdir_notify_register()` instead of
`chdir_notify_reparent()`, as there is no infrastructure to unregister the
latter.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 refs/files-backend.c    | 22 +++++++++++++++++++---
 refs/packed-backend.c   | 16 +++++++++++++++-
 refs/reftable-backend.c | 16 +++++++++++++++-
 3 files changed, 49 insertions(+), 5 deletions(-)

diff --git a/refs/files-backend.c b/refs/files-backend.c
index a4c7858787..296981584b 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -100,6 +100,23 @@ static void clear_loose_ref_cache(struct files_ref_store *refs)
 	}
 }
 
+static void files_ref_store_reparent(const char *name UNUSED,
+				     const char *old_cwd,
+				     const char *new_cwd,
+				     void *payload)
+{
+	struct files_ref_store *refs = payload;
+	char *tmp;
+
+	tmp = reparent_relative_path(old_cwd, new_cwd, refs->base.gitdir);
+	free(refs->base.gitdir);
+	refs->base.gitdir = tmp;
+
+	tmp = reparent_relative_path(old_cwd, new_cwd, refs->gitcommondir);
+	free(refs->gitcommondir);
+	refs->gitcommondir = tmp;
+}
+
 /*
  * Create a new submodule ref cache and add it to the internal
  * set of caches.
@@ -128,9 +145,7 @@ static struct ref_store *files_ref_store_init(struct repository *repo,
 
 	repo_config_get_bool(repo, "core.prefersymlinkrefs", &refs->prefer_symlink_refs);
 
-	chdir_notify_reparent("files-backend $GIT_DIR", &refs->base.gitdir);
-	chdir_notify_reparent("files-backend $GIT_COMMONDIR",
-			      &refs->gitcommondir);
+	chdir_notify_register(NULL, files_ref_store_reparent, refs);
 
 	strbuf_release(&refdir);
 
@@ -182,6 +197,7 @@ static void files_ref_store_release(struct ref_store *ref_store)
 	free(refs->gitcommondir);
 	ref_store_release(refs->packed_ref_store);
 	free(refs->packed_ref_store);
+	chdir_notify_unregister(NULL, files_ref_store_reparent, refs);
 }
 
 static void files_reflog_path(struct files_ref_store *refs,
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 0acde48c45..499cb55dfa 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -211,6 +211,19 @@ static size_t snapshot_hexsz(const struct snapshot *snapshot)
 	return snapshot->refs->base.repo->hash_algo->hexsz;
 }
 
+static void packed_ref_store_reparent(const char *name UNUSED,
+				      const char *old_cwd,
+				      const char *new_cwd,
+				      void *payload)
+{
+	struct packed_ref_store *refs = payload;
+	char *tmp;
+
+	tmp = reparent_relative_path(old_cwd, new_cwd, refs->path);
+	free(refs->path);
+	refs->path = tmp;
+}
+
 /*
  * Since packed-refs is only stored in the common dir, don't parse the
  * payload and rely on the files-backend to set 'gitdir' correctly.
@@ -229,7 +242,7 @@ struct ref_store *packed_ref_store_init(struct repository *repo,
 
 	strbuf_addf(&sb, "%s/packed-refs", gitdir);
 	refs->path = strbuf_detach(&sb, NULL);
-	chdir_notify_reparent("packed-refs", &refs->path);
+	chdir_notify_register(NULL, packed_ref_store_reparent, refs);
 	return ref_store;
 }
 
@@ -274,6 +287,7 @@ static void packed_ref_store_release(struct ref_store *ref_store)
 	clear_snapshot(refs);
 	rollback_lock_file(&refs->lock);
 	delete_tempfile(&refs->tempfile);
+	chdir_notify_unregister(NULL, packed_ref_store_reparent, refs);
 	free(refs->path);
 }
 
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index 4ae22922de..8c93070677 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -365,6 +365,19 @@ static int reftable_be_config(const char *var, const char *value,
 	return 0;
 }
 
+static void reftable_be_reparent(const char *name UNUSED,
+				 const char *old_cwd,
+				 const char *new_cwd,
+				 void *payload)
+{
+	struct reftable_ref_store *refs = payload;
+	char *tmp;
+
+	tmp = reparent_relative_path(old_cwd, new_cwd, refs->base.gitdir);
+	free(refs->base.gitdir);
+	refs->base.gitdir = tmp;
+}
+
 static struct ref_store *reftable_be_init(struct repository *repo,
 					  const char *payload,
 					  const char *gitdir,
@@ -447,7 +460,7 @@ static struct ref_store *reftable_be_init(struct repository *repo,
 			goto done;
 	}
 
-	chdir_notify_reparent("reftables-backend $GIT_DIR", &refs->base.gitdir);
+	chdir_notify_register(NULL, reftable_be_reparent, refs);
 
 done:
 	assert(refs->err != REFTABLE_API_ERROR);
@@ -474,6 +487,7 @@ static void reftable_be_release(struct ref_store *ref_store)
 		free(be);
 	}
 	strmap_clear(&refs->worktree_backends, 0);
+	chdir_notify_unregister(NULL, reftable_be_reparent, refs);
 }
 
 static int reftable_be_create_on_disk(struct ref_store *ref_store,

-- 
2.55.0.rc0.786.g65d90a0328.dirty


^ permalink raw reply related

* [PATCH v3 3/8] setup: don't apply "GIT_REFERENCE_BACKEND" without a repository
From: Patrick Steinhardt @ 2026-06-18  6:54 UTC (permalink / raw)
  To: git; +Cc: Karthik Nayak, Jeff King, Justin Tobler
In-Reply-To: <20260618-b4-pks-refs-avoid-chdir-notify-reparent-v3-0-2a5669e8f486@pks.im>

When discovering a repository we eventually also apply the
"GIT_REFERENCE_BACKEND" environment variable to the repository. There's
two problems with that:

  - We do this unconditionally, which is rather pointless: we really
    only have to configure the repository when we have found one.

  - We have already applied the repository format at that point in time,
    so we need to manually reapply it.

Move the logic around so that we only apply the environment variable
when a repository was discovered. This also allows us to drop the
explcit call to `repo_set_ref_storage_format()` because we now adjust
the format before we apply it via `apply_repository_format()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 setup.c | 39 +++++++++++++++++++--------------------
 1 file changed, 19 insertions(+), 20 deletions(-)

diff --git a/setup.c b/setup.c
index 2748155964..79125db565 100644
--- a/setup.c
+++ b/setup.c
@@ -1906,7 +1906,6 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
 	static struct strbuf cwd = STRBUF_INIT;
 	struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT, report = STRBUF_INIT;
 	const char *prefix = NULL;
-	const char *ref_backend_uri;
 	struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
 
 	/*
@@ -2032,6 +2031,25 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
 
 		if (startup_info->have_repository) {
 			struct strbuf err = STRBUF_INIT;
+			const char *ref_backend_uri;
+
+			/*
+			 * The env variable should override the repository config
+			 * for 'extensions.refStorage'.
+			 */
+			ref_backend_uri = getenv(GIT_REFERENCE_BACKEND_ENVIRONMENT);
+			if (ref_backend_uri) {
+				char *format;
+
+				free(repo_fmt.ref_storage_payload);
+
+				parse_reference_uri(ref_backend_uri, &format, &repo_fmt.ref_storage_payload);
+				repo_fmt.ref_storage_format = ref_storage_format_by_name(format);
+				if (repo_fmt.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+					die(_("unknown ref storage format: '%s'"), format);
+
+				free(format);
+			}
 
 			if (apply_repository_format(repo, &repo_fmt,
 						    APPLY_REPOSITORY_FORMAT_HONOR_ENV, &err) < 0)
@@ -2057,25 +2075,6 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
 		setenv(GIT_PREFIX_ENVIRONMENT, "", 1);
 	}
 
-	/*
-	 * The env variable should override the repository config
-	 * for 'extensions.refStorage'.
-	 */
-	ref_backend_uri = getenv(GIT_REFERENCE_BACKEND_ENVIRONMENT);
-	if (ref_backend_uri) {
-		char *backend, *payload;
-		enum ref_storage_format format;
-
-		parse_reference_uri(ref_backend_uri, &backend, &payload);
-		format = ref_storage_format_by_name(backend);
-		if (format == REF_STORAGE_FORMAT_UNKNOWN)
-			die(_("unknown ref storage format: '%s'"), backend);
-		repo_set_ref_storage_format(repo, format, payload);
-
-		free(backend);
-		free(payload);
-	}
-
 	setup_original_cwd(repo);
 
 	strbuf_release(&dir);

-- 
2.55.0.rc0.786.g65d90a0328.dirty


^ permalink raw reply related

* [PATCH v3 2/8] setup: stop applying repository format twice
From: Patrick Steinhardt @ 2026-06-18  6:54 UTC (permalink / raw)
  To: git; +Cc: Karthik Nayak, Jeff King, Justin Tobler
In-Reply-To: <20260618-b4-pks-refs-avoid-chdir-notify-reparent-v3-0-2a5669e8f486@pks.im>

When discovering the repository in "setup.c" we apply the final
repository format multiple times:

  - Once via `repository_format_configure()`, where we apply the hash
    algorithm and ref storage format to both `struct repository_format`
    and `struct repository`.

  - And once via `apply_repository_format()`, where we apply these two
    settings from `struct repository_format` to `struct repository`.

With the current flow both of these are in fact necessary. But this is
only because we call `repository_format_configure()` after we have
called `apply_repository_format()`. Consequently, if we only changed the
repository format in `repository_format_configure()` it would never
propagate to the repository.

Refactor the code so that we first configure the repository format
before applying it to the repository so that we can stop setting the
hash and reference storage format multiple times.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 setup.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/setup.c b/setup.c
index a9db1f2c23..2748155964 100644
--- a/setup.c
+++ b/setup.c
@@ -2710,8 +2710,7 @@ static int read_default_format_config(const char *key, const char *value,
 	return ret;
 }
 
-static void repository_format_configure(struct repository *repo,
-					struct repository_format *repo_fmt,
+static void repository_format_configure(struct repository_format *repo_fmt,
 					int hash, enum ref_storage_format ref_format)
 {
 	struct default_format_config cfg = {
@@ -2748,7 +2747,6 @@ static void repository_format_configure(struct repository *repo,
 	} else if (cfg.hash != GIT_HASH_UNKNOWN) {
 		repo_fmt->hash_algo = cfg.hash;
 	}
-	repo_set_hash_algo(repo, repo_fmt->hash_algo);
 
 	env = getenv("GIT_DEFAULT_REF_FORMAT");
 	if (repo_fmt->version >= 0 &&
@@ -2786,9 +2784,6 @@ static void repository_format_configure(struct repository *repo,
 
 		free(backend);
 	}
-
-	repo_set_ref_storage_format(repo, repo_fmt->ref_storage_format,
-				    repo_fmt->ref_storage_payload);
 }
 
 int init_db(struct repository *repo,
@@ -2830,10 +2825,10 @@ int init_db(struct repository *repo,
 	 * is an attempt to reinitialize new repository with an old tool.
 	 */
 	check_repository_format_gently(repo_get_git_dir(repo), &repo_fmt, NULL);
+	repository_format_configure(&repo_fmt, hash, ref_storage_format);
 	if (apply_repository_format(repo, &repo_fmt, APPLY_REPOSITORY_FORMAT_HONOR_ENV, &err) < 0)
 		die("%s", err.buf);
 	startup_info->have_repository = 1;
-	repository_format_configure(repo, &repo_fmt, hash, ref_storage_format);
 
 	/*
 	 * Ensure `core.hidedotfiles` is processed. This must happen after we

-- 
2.55.0.rc0.786.g65d90a0328.dirty


^ permalink raw reply related

* Re: [PATCH v2 4/8] refs: unregister reference stores from "chdir_notify"
From: Patrick Steinhardt @ 2026-06-18  6:54 UTC (permalink / raw)
  To: Justin Tobler; +Cc: git, Karthik Nayak, Jeff King
In-Reply-To: <ajLdIY_fxkKDTBaW@denethor>

On Wed, Jun 17, 2026 at 01:02:23PM -0500, Justin Tobler wrote:
> On 26/06/15 03:56PM, Patrick Steinhardt wrote:
> > When creating reference stores we register them with the "chdir_notify"
> > subsystem. This is required because some of the paths we track may be
> > relative paths, so we have to reparent them in case the current working
> > directory changes.
> > 
> > But while we register the reference stores, we never unregister them.
> > This can have multiple outcomes:
> > 
> >   - For a repository's main reference database we essentially keep the
> >     pointer alive. We never free that database, either, and our leak
> >     checker doesn't notice because it's still registered.
> > 
> >   - For submodule and worktree reference databases we do eventually free
> >     them in `repo_clear()`, so we may keep pointers to free'd memory
> >     registered. We never notice though as we don't tend to chdir around
> >     in the middle of the process.
> > 
> > We never noticed either of these symptoms, but they are obviously bad.
> > 
> > Partially fix those issues by unregistering the reference stores when
> > releasing them. The leak of the main reference database will be fixed in
> > a subsequent commit.
> > 
> > Note that this requires us to use `chdir_notify_register()` instead of
> > `chdir_notify_reparent()`, as there is no infrastructure to unregister the
> > latter. It ultimately doesn't matter much though: in a subsequent commit
> > we'll drop this infrastructure completely. We merely require this step
> > here so that we can fix the memory leaks ahead of time.
> 
> Since this version of the series dropped the last patch which stopped
> using `chdir_notify_reparent()`, does the log message here need to be
> updated?

True, will do.

Patrick

^ permalink raw reply

* [PATCH v3 1/8] setup: inline `check_and_apply_repository_format()`
From: Patrick Steinhardt @ 2026-06-18  6:54 UTC (permalink / raw)
  To: git; +Cc: Karthik Nayak, Jeff King, Justin Tobler
In-Reply-To: <20260618-b4-pks-refs-avoid-chdir-notify-reparent-v3-0-2a5669e8f486@pks.im>

We have two callsites of `check_and_apply_repository_format()`. In a
subsequent commit we'll want to adapt one of those callsites to change
the order in which we read and apply the repository format, at which
point the helper function will not really be a good fit for us anymore.

Inline the function to both of the callsites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 setup.c | 47 ++++++++++++++++-------------------------------
 1 file changed, 16 insertions(+), 31 deletions(-)

diff --git a/setup.c b/setup.c
index b4652651df..a9db1f2c23 100644
--- a/setup.c
+++ b/setup.c
@@ -1788,32 +1788,6 @@ int apply_repository_format(struct repository *repo,
 	return 0;
 }
 
-/*
- * Check the repository format version in the path found in repo_get_git_dir(repo),
- * and die if it is a version we don't understand. Generally one would
- * set_git_dir() before calling this, and use it only for "are we in a valid
- * repo?".
- *
- * If successful and fmt is not NULL, fill fmt with data.
- */
-static void check_and_apply_repository_format(struct repository *repo,
-					      struct repository_format *fmt,
-					      enum apply_repository_format_flags flags)
-{
-	struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
-	struct strbuf err = STRBUF_INIT;
-
-	if (!fmt)
-		fmt = &repo_fmt;
-
-	check_repository_format_gently(repo_get_git_dir(repo), fmt, NULL);
-	if (apply_repository_format(repo, fmt, flags, &err) < 0)
-		die("%s", err.buf);
-	startup_info->have_repository = 1;
-
-	clear_repository_format(&repo_fmt);
-}
-
 const char *enter_repo(struct repository *repo, const char *path, unsigned flags)
 {
 	static struct strbuf validated_path = STRBUF_INIT;
@@ -1887,9 +1861,17 @@ const char *enter_repo(struct repository *repo, const char *path, unsigned flags
 	}
 
 	if (is_git_directory(".")) {
+		struct repository_format fmt = REPOSITORY_FORMAT_INIT;
+		struct strbuf err = STRBUF_INIT;
+
 		set_git_dir(repo, ".", 0);
-		check_and_apply_repository_format(repo, NULL,
-						  APPLY_REPOSITORY_FORMAT_HONOR_ENV);
+		check_repository_format_gently(".", &fmt, NULL);
+		if (apply_repository_format(repo, &fmt, APPLY_REPOSITORY_FORMAT_HONOR_ENV, &err) < 0)
+			die("%s", err.buf);
+		startup_info->have_repository = 1;
+
+		clear_repository_format(&fmt);
+		strbuf_release(&err);
 		return path;
 	}
 
@@ -2820,6 +2802,7 @@ int init_db(struct repository *repo,
 	int exist_ok = flags & INIT_DB_EXIST_OK;
 	char *original_git_dir = real_pathdup(git_dir, 1);
 	struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
+	struct strbuf err = STRBUF_INIT;
 
 	if (real_git_dir) {
 		struct stat st;
@@ -2846,9 +2829,10 @@ int init_db(struct repository *repo,
 	 * config file, so this will not fail.  What we are catching
 	 * is an attempt to reinitialize new repository with an old tool.
 	 */
-	check_and_apply_repository_format(repo, &repo_fmt,
-					  APPLY_REPOSITORY_FORMAT_HONOR_ENV);
-
+	check_repository_format_gently(repo_get_git_dir(repo), &repo_fmt, NULL);
+	if (apply_repository_format(repo, &repo_fmt, APPLY_REPOSITORY_FORMAT_HONOR_ENV, &err) < 0)
+		die("%s", err.buf);
+	startup_info->have_repository = 1;
 	repository_format_configure(repo, &repo_fmt, hash, ref_storage_format);
 
 	/*
@@ -2904,6 +2888,7 @@ int init_db(struct repository *repo,
 	}
 
 	clear_repository_format(&repo_fmt);
+	strbuf_release(&err);
 	free(original_git_dir);
 	return 0;
 }

-- 
2.55.0.rc0.786.g65d90a0328.dirty


^ permalink raw reply related

* [PATCH v3 0/8] refs: stop using `chdir_notify_reparent()`
From: Patrick Steinhardt @ 2026-06-18  6:54 UTC (permalink / raw)
  To: git; +Cc: Karthik Nayak, Jeff King, Justin Tobler
In-Reply-To: <20260610-b4-pks-refs-avoid-chdir-notify-reparent-v1-0-56c864b01c43@pks.im>

Hi,

this patch series is a follow-up of the discussion at [1]. It converts
the reference backends to always use absolute paths internally, which
then allows us to drop the calls to `chdir_notify_reparent()`.

Unfortunately, the series has grown quite a bit larger than anticipated.
This is due to a couple of weirdnesses in how the reference database is
constructed with an "onbranch" condition. We essentially construct the
refdb twice and loose one, but we never noticed because the chdir
notification subsystem kept the pointer to it reachable.

Note that the first couple patches that touch "setup.c" aren't strictly
required. They are a remnant of a previous iteration where I tried to
solve the issue in a different way. But I ultimately figured that these
changes are worth it by themselves as they simplify "setup.c" a bit.

This series is built on top of 1ff279f340 (The 13th batch, 2026-06-09)
with ps/setup-centralize-odb-creation at 42b9d3dc9d (setup: construct
object database in `apply_repository_format()`, 2026-06-04) merged into
it.

Changes in v3:
  - Reduce the scope of applying the GIT_REFERENCE_BACKEND environment
    variable even further so that we really only do this when we end up
    applying the reference format.
  - Fix a commit message that still referred to the dropped last commit.
  - Link to v2: https://patch.msgid.link/20260615-b4-pks-refs-avoid-chdir-notify-reparent-v2-0-f4854aa99859@pks.im

Changes in v2:
  - Drop the last patch. This seemingly destroys the whole purpose of
    the patch series, but after Peff's hint that this is actually a
    performance optimization I'm less inclined to drop the chdir_notify
    infra. I still think that the remainder of the patches make sense
    standalone, as they simplify "setup.c" and clean memory leaks. Going
    forward I'd like to investigate the idea of introducing a `struct
    fsroot` infrastructure that uses the platform-equivalent of openat
    et al.
  - Improve a couple of commit messages.
  - Link to v1: https://patch.msgid.link/20260610-b4-pks-refs-avoid-chdir-notify-reparent-v1-0-56c864b01c43@pks.im

Thanks!

Patrick

[1]: <aifAVpxanV31KUpC@pks.im>

---
Patrick Steinhardt (8):
      setup: inline `check_and_apply_repository_format()`
      setup: stop applying repository format twice
      setup: don't apply "GIT_REFERENCE_BACKEND" without a repository
      refs: unregister reference stores from "chdir_notify"
      chdir-notify: drop unused `chdir_notify_reparent()`
      repository: free main reference database
      refs: fix recursing `get_main_ref_store()` with "onbranch" config
      refs: drop local buffer in `refs_compute_filesystem_location()`

 chdir-notify.c          | 26 --------------
 chdir-notify.h          |  6 +---
 refs.c                  | 28 ++++++++++-----
 refs/files-backend.c    | 22 ++++++++++--
 refs/packed-backend.c   | 16 ++++++++-
 refs/reftable-backend.c | 16 ++++++++-
 repository.c            |  5 +++
 setup.c                 | 95 +++++++++++++++++++------------------------------
 8 files changed, 112 insertions(+), 102 deletions(-)

Range-diff versus v2:

1:  ea89bedaa2 = 1:  2be38c1e02 setup: inline `check_and_apply_repository_format()`
2:  b87f1db13b = 2:  7fdcd81bb7 setup: stop applying repository format twice
3:  f72a8dc251 ! 3:  2162480668 setup: don't apply "GIT_REFERENCE_BACKEND" without a repository
    @@ setup.c: const char *setup_git_directory_gently(struct repository *repo, int *no
      
      	/*
     @@ setup.c: const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
    - 	    startup_info->have_repository ||
    - 	    /* GIT_DIR_EXPLICIT */
    - 	    getenv(GIT_DIR_ENVIRONMENT)) {
    -+		const char *ref_backend_uri;
    -+
    - 		if (!repo->gitdir) {
    - 			const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
    - 			if (!gitdir)
    -@@ setup.c: const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
    - 			setup_git_env_internal(repo, gitdir);
    - 		}
      
    -+		/*
    -+		 * The env variable should override the repository config
    -+		 * for 'extensions.refStorage'.
    -+		 */
    -+		ref_backend_uri = getenv(GIT_REFERENCE_BACKEND_ENVIRONMENT);
    -+		if (ref_backend_uri) {
    -+			char *format;
    + 		if (startup_info->have_repository) {
    + 			struct strbuf err = STRBUF_INIT;
    ++			const char *ref_backend_uri;
     +
    -+			free(repo_fmt.ref_storage_payload);
    ++			/*
    ++			 * The env variable should override the repository config
    ++			 * for 'extensions.refStorage'.
    ++			 */
    ++			ref_backend_uri = getenv(GIT_REFERENCE_BACKEND_ENVIRONMENT);
    ++			if (ref_backend_uri) {
    ++				char *format;
     +
    -+			parse_reference_uri(ref_backend_uri, &format, &repo_fmt.ref_storage_payload);
    -+			repo_fmt.ref_storage_format = ref_storage_format_by_name(format);
    -+			if (repo_fmt.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
    -+				die(_("unknown ref storage format: '%s'"), format);
    ++				free(repo_fmt.ref_storage_payload);
     +
    -+			free(format);
    -+		}
    ++				parse_reference_uri(ref_backend_uri, &format, &repo_fmt.ref_storage_payload);
    ++				repo_fmt.ref_storage_format = ref_storage_format_by_name(format);
    ++				if (repo_fmt.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
    ++					die(_("unknown ref storage format: '%s'"), format);
     +
    - 		if (startup_info->have_repository) {
    - 			struct strbuf err = STRBUF_INIT;
    ++				free(format);
    ++			}
      
    + 			if (apply_repository_format(repo, &repo_fmt,
    + 						    APPLY_REPOSITORY_FORMAT_HONOR_ENV, &err) < 0)
     @@ setup.c: const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
      		setenv(GIT_PREFIX_ENVIRONMENT, "", 1);
      	}
4:  17bdcdb4c5 ! 4:  14daa680b1 refs: unregister reference stores from "chdir_notify"
    @@ Commit message
     
         Note that this requires us to use `chdir_notify_register()` instead of
         `chdir_notify_reparent()`, as there is no infrastructure to unregister the
    -    latter. It ultimately doesn't matter much though: in a subsequent commit
    -    we'll drop this infrastructure completely. We merely require this step
    -    here so that we can fix the memory leaks ahead of time.
    +    latter.
     
         Signed-off-by: Patrick Steinhardt <ps@pks.im>
     
5:  c2f13a487e = 5:  89fe37ebe1 chdir-notify: drop unused `chdir_notify_reparent()`
6:  730e4caeda = 6:  4a96b70db4 repository: free main reference database
7:  1dda77cd19 = 7:  e48fc2d69d refs: fix recursing `get_main_ref_store()` with "onbranch" config
8:  6d969bb023 = 8:  37935d50c8 refs: drop local buffer in `refs_compute_filesystem_location()`

---
base-commit: 255322df35357168daefec8523a3cdc849edd6c1
change-id: 20260609-b4-pks-refs-avoid-chdir-notify-reparent-a4eaf1edbcab


^ permalink raw reply

* Re: [PATCH v2 3/8] setup: don't apply "GIT_REFERENCE_BACKEND" without a repository
From: Patrick Steinhardt @ 2026-06-18  6:53 UTC (permalink / raw)
  To: Justin Tobler; +Cc: git, Karthik Nayak, Jeff King
In-Reply-To: <ajLapsLze_zF-dsS@denethor>

On Wed, Jun 17, 2026 at 12:43:02PM -0500, Justin Tobler wrote:
> On 26/06/15 03:56PM, Patrick Steinhardt wrote:
> > @@ -2030,6 +2031,24 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
> >  			setup_git_env_internal(repo, gitdir);
> >  		}
> >  
> > +		/*
> > +		 * The env variable should override the repository config
> > +		 * for 'extensions.refStorage'.
> > +		 */
> > +		ref_backend_uri = getenv(GIT_REFERENCE_BACKEND_ENVIRONMENT);
> > +		if (ref_backend_uri) {
> > +			char *format;
> > +
> > +			free(repo_fmt.ref_storage_payload);
> > +
> > +			parse_reference_uri(ref_backend_uri, &format, &repo_fmt.ref_storage_payload);
> > +			repo_fmt.ref_storage_format = ref_storage_format_by_name(format);
> > +			if (repo_fmt.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
> > +				die(_("unknown ref storage format: '%s'"), format);
> > +
> > +			free(format);
> > +		}
> > +
> >  		if (startup_info->have_repository) {
> >  			struct strbuf err = STRBUF_INIT;
> 
> Hmmm, we only invoke `apply_repository_format()` if we indeed have a
> repository (having just GIT_DIR_ENVIRONMENT set isn't enough). Should we
> instead nest this logic right above `apply_repository_format()` in the
> same block?

Yup, that makes sense indeed.

Patrick

^ permalink raw reply

* Re: [PATCH v2 0/6] Support hashing objects larger than 4GB on Windows
From: Patrick Steinhardt @ 2026-06-18  6:31 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Philip Oakley, Johannes Schindelin
In-Reply-To: <pull.2138.v2.git.1781621398.gitgitgadget@gmail.com>

On Tue, Jun 16, 2026 at 02:49:51PM +0000, Johannes Schindelin via GitGitGadget wrote:
> Philip Oakley has contributed these patches ~4.5 years ago, and they have
> been carried in Git for Windows ever since.
> 
> Now that there are already other patch series flying around that try to
> address various aspects about >4GB objects (which aren't handled well by Git
> until it stops forcing unsigned long to do size_t's job), it seems a good
> time to upstream these patches, too, at long last.
> 
> Changes since v1:
> 
>  * Rebased to current master to resolve the conflicts with
>    ps/odb-source-loose
>  * Dropped the !LONG_IS_64BIT prereq from the added/touched tests, as it is
>    now no longer needed

Thanks, this addresses all of my feedback.

Patrick

^ permalink raw reply

* Re: [PATCH] osxkeychain: fix build with Rust
From: Patrick Steinhardt @ 2026-06-18  6:30 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Johannes Schindelin via GitGitGadget, git, Johannes Schindelin
In-Reply-To: <xmqq8q8d1ixq.fsf@gitster.g>

On Wed, Jun 17, 2026 at 04:54:09AM -0700, Junio C Hamano wrote:
> "Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
> writes:
> 
> > From: Johannes Schindelin <johannes.schindelin@gmx.de>
> >
> > Without NO_RUST defined, the varint encoder/decoder lives in the
> > RUST_LIB, which needs to be linked. Symptom:
> >
> > cc [... -o contrib/credential/osxkeychain/git-credential-osxkeychain [...]
> > Undefined symbols for architecture x86_64:
> >   "_decode_varint", referenced from:
> >       _read_untracked_extension in libgit.a[x86_64][63](dir.o)
> >       _read_untracked_extension in libgit.a[x86_64][63](dir.o)
> >       _read_one_dir in libgit.a[x86_64][63](dir.o)
> >       _read_one_dir in libgit.a[x86_64][63](dir.o)
> >       _load_cache_entry_block in libgit.a[x86_64][174](read-cache.o)
> >   "_encode_varint", referenced from:
> >       _write_untracked_extension in libgit.a[x86_64][63](dir.o)
> >       _write_untracked_extension in libgit.a[x86_64][63](dir.o)
> >       _write_untracked_extension in libgit.a[x86_64][63](dir.o)
> >       _write_one_dir in libgit.a[x86_64][63](dir.o)
> >       _write_one_dir in libgit.a[x86_64][63](dir.o)
> >       _do_write_index in libgit.a[x86_64][174](read-cache.o)
> > ld: symbol(s) not found for architecture x86_64
> >
> > While it is curious why these functions are needed at all (osxkeychain
> > does not read or write the index), the compile error is a real problem.
> >
> > Instead of trying to play games to add `GITLIBS` while filtering out
> > `common-main.o`, replace the `$(LIB_FILE) $(EXTLIBS)` construct with the
> > much shorter `$(LIBS)` construct that _already_ filters out
> > `common-main.o` and adds the Rust library when needed.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> 
> Hmph, we do not build this at GitHub Actions based CI?  Just being
> curious.

We build it with Meson, but not with our Makefile. And in Meson things
are working alright.

> Let me take this directly to 'master' before tagging -rc1.  Thanks.

Makes sense.

Patrick

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox