Git development
 help / color / mirror / Atom feed
* [PATCH 03/11] reftable/block: check deflateInit() return value
From: Johannes Schindelin via GitGitGadget @ 2026-07-14 22:48 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Johannes Schindelin
In-Reply-To: <pull.2179.git.1784069325.gitgitgadget@gmail.com>

From: Johannes Schindelin <johannes.schindelin@gmx.de>

block_writer_init() allocates a z_stream and calls deflateInit()
to prepare it for compressing log records. The return value of
deflateInit() is silently discarded. If zlib initialization fails
(e.g., Z_MEM_ERROR when the system is under memory pressure), the
z_stream is left in an undefined state.

Subsequent deflate() calls in block_writer_finish() then operate
on this uninitialized stream. Depending on the zlib
implementation, this can produce silently corrupted compressed
data (which would be written to the reftable file and discovered
only when a later reader fails to inflate) or crash outright.

The function already uses REFTABLE_ZLIB_ERROR for deflate()
failures later in the code path (lines 171, 199), so returning
the same error code for deflateInit() failure is consistent.

Pointed out by Coverity.

Assisted-by: Claude Opus 4.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 reftable/block.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/reftable/block.c b/reftable/block.c
index 920b3f4486..ec81fd0493 100644
--- a/reftable/block.c
+++ b/reftable/block.c
@@ -87,7 +87,8 @@ int block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *block,
 		REFTABLE_CALLOC_ARRAY(bw->zstream, 1);
 		if (!bw->zstream)
 			return REFTABLE_OUT_OF_MEMORY_ERROR;
-		deflateInit(bw->zstream, 9);
+		if (deflateInit(bw->zstream, 9) != Z_OK)
+			return REFTABLE_ZLIB_ERROR;
 	}
 
 	return 0;
-- 
gitgitgadget


^ permalink raw reply related

* [PATCH 04/11] reftable tests: check reftable_table_init_ref_iterator() return
From: Johannes Schindelin via GitGitGadget @ 2026-07-14 22:48 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Johannes Schindelin
In-Reply-To: <pull.2179.git.1784069325.gitgitgadget@gmail.com>

From: Johannes Schindelin <johannes.schindelin@gmx.de>

test_reftable_table__seek_once() and test_reftable_table__reseek()
both call reftable_table_init_ref_iterator() without checking its
return value. This function returns an int error code (0 on
success, negative on failure). Every other reftable function call
in these same tests checks the return via cl_assert_equal_i() or
cl_assert(), making this omission inconsistent.

If the iterator initialization ever fails (e.g., due to a memory
allocation failure in the reftable internals), the test would
proceed to seek and read with an uninitialized iterator, producing
misleading test results or crashes rather than a clear assertion
failure.

Check the return value via cl_assert_equal_i(ret, 0), consistent
with the surrounding code.

Pointed out by Coverity.

Assisted-by: Claude Opus 4.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 t/unit-tests/u-reftable-table.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/t/unit-tests/u-reftable-table.c b/t/unit-tests/u-reftable-table.c
index fae478ee04..6f444f8cf9 100644
--- a/t/unit-tests/u-reftable-table.c
+++ b/t/unit-tests/u-reftable-table.c
@@ -29,7 +29,8 @@ void test_reftable_table__seek_once(void)
 	ret = reftable_table_new(&table, &source, "name");
 	cl_assert(!ret);
 
-	reftable_table_init_ref_iterator(table, &it);
+	ret = reftable_table_init_ref_iterator(table, &it);
+	cl_assert_equal_i(ret, 0);
 	ret = reftable_iterator_seek_ref(&it, "");
 	cl_assert(!ret);
 	ret = reftable_iterator_next_ref(&it, &ref);
@@ -71,7 +72,8 @@ void test_reftable_table__reseek(void)
 	ret = reftable_table_new(&table, &source, "name");
 	cl_assert(!ret);
 
-	reftable_table_init_ref_iterator(table, &it);
+	ret = reftable_table_init_ref_iterator(table, &it);
+	cl_assert_equal_i(ret, 0);
 
 	for (size_t i = 0; i < 5; i++) {
 		ret = reftable_iterator_seek_ref(&it, "");
-- 
gitgitgadget


^ permalink raw reply related

* [PATCH 05/11] last-modified: handle repo_parse_commit() failures
From: Johannes Schindelin via GitGitGadget @ 2026-07-14 22:48 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Johannes Schindelin
In-Reply-To: <pull.2179.git.1784069325.gitgitgadget@gmail.com>

From: Johannes Schindelin <johannes.schindelin@gmx.de>

last_modified_run() and process_parent() call repo_parse_commit()
without checking the return value at three sites. When a commit
object is corrupt or unavailable (e.g., a shallow clone boundary
or a missing object in a partial clone), the parse fails and the
commit's internal fields (parents, tree, date) are not populated.

The consequences depend on which call site fails:

At line 417 (the main walk loop), c->parents stays NULL after a
failed parse. The parent-walking loop at line 440 simply does not
execute, silently treating the unparsable commit as a root commit.
This produces incorrect "last modified" results: paths changed in
ancestors beyond the corrupt commit are attributed to the wrong
commit or not reported at all.

At line 423 (the --not exclusion walk), n->parents stays NULL,
causing the exclusion walk to stop prematurely. Commits that
should be excluded from the output may be incorrectly included.

At line 293 (process_parent), the parent's tree and parents are
unavailable, so diff operations against it produce wrong results
and the parent's own ancestors are never enqueued for walking.

Skip unparsable commits by checking the return value and
continuing to the next iteration (or returning early in
process_parent). This matches the defensive pattern used in other
revision walkers such as limit_list() and get_revision_internal().

Pointed out by Coverity.

Assisted-by: Claude Opus 4.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/last-modified.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/builtin/last-modified.c b/builtin/last-modified.c
index 5478182f2e..fe012b0c2e 100644
--- a/builtin/last-modified.c
+++ b/builtin/last-modified.c
@@ -290,7 +290,8 @@ static void process_parent(struct last_modified *lm,
 {
 	struct bitmap *active_p;
 
-	repo_parse_commit(lm->rev.repo, parent);
+	if (repo_parse_commit(lm->rev.repo, parent))
+		return;
 	active_p = active_paths_for(lm, parent);
 
 	/*
@@ -414,12 +415,14 @@ static int last_modified_run(struct last_modified *lm)
 		 * Otherwise, make sure that 'c' isn't reachable from anything
 		 * in the '--not' queue.
 		 */
-		repo_parse_commit(lm->rev.repo, c);
+		if (repo_parse_commit(lm->rev.repo, c))
+			continue;
 
 		while ((n = prio_queue_get(&not_queue))) {
 			struct commit_list *np;
 
-			repo_parse_commit(lm->rev.repo, n);
+			if (repo_parse_commit(lm->rev.repo, n))
+				continue;
 
 			for (np = n->parents; np; np = np->next) {
 				if (!(np->item->object.flags & PARENT2)) {
-- 
gitgitgadget


^ permalink raw reply related

* [PATCH 06/11] compat/pread: check initial lseek for errors
From: Johannes Schindelin via GitGitGadget @ 2026-07-14 22:48 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Johannes Schindelin
In-Reply-To: <pull.2179.git.1784069325.gitgitgadget@gmail.com>

From: Johannes Schindelin <johannes.schindelin@gmx.de>

git_pread() saves the current file offset via lseek(fd, 0,
SEEK_CUR) and later restores it. If the initial lseek fails
(e.g., the fd is a pipe or otherwise non-seekable),
current_offset is -1. This negative value is later passed to
lseek(fd, -1, SEEK_SET) at line 16, which sets the file position
to an unintended location (or fails with EINVAL on some
platforms).

Check the initial lseek return value and return -1 immediately
if it fails, consistent with the error handling for the other
lseek calls in the same function.

Pointed out by Coverity.

Assisted-by: Claude Opus 4.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/pread.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/compat/pread.c b/compat/pread.c
index 484e6d4c71..ac7d058cb8 100644
--- a/compat/pread.c
+++ b/compat/pread.c
@@ -7,6 +7,8 @@ ssize_t git_pread(int fd, void *buf, size_t count, off_t offset)
         ssize_t rc;
 
         current_offset = lseek(fd, 0, SEEK_CUR);
+	if (current_offset < 0)
+		return -1;
 
         if (lseek(fd, offset, SEEK_SET) < 0)
                 return -1;
-- 
gitgitgadget


^ permalink raw reply related

* [PATCH 07/11] transport-helper: check dup() return in get_exporter
From: Johannes Schindelin via GitGitGadget @ 2026-07-14 22:48 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Johannes Schindelin
In-Reply-To: <pull.2179.git.1784069325.gitgitgadget@gmail.com>

From: Johannes Schindelin <johannes.schindelin@gmx.de>

get_exporter() duplicates helper->in via dup() and stores the
result in fastexport->out. If dup() fails (fd exhaustion), it
returns -1. The child_process machinery interprets out = -1 as
"create a pipe for stdout", which would silently change the
fast-export process's output wiring: instead of sending data
back through the helper's input fd, it would write to a new pipe
that nobody reads from.

Check the return value and report the error before proceeding.

Pointed out by Coverity.

Assisted-by: Claude Opus 4.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 transport-helper.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/transport-helper.c b/transport-helper.c
index 80f90eb7ba..31883b244e 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -487,6 +487,8 @@ static int get_exporter(struct transport *transport,
 	/* we need to duplicate helper->in because we want to use it after
 	 * fastexport is done with it. */
 	fastexport->out = dup(helper->in);
+	if (fastexport->out < 0)
+		return error_errno(_("could not dup helper output fd"));
 	strvec_push(&fastexport->args, "fast-export");
 	strvec_push(&fastexport->args, "--use-done-feature");
 	strvec_push(&fastexport->args, data->signed_tags ?
-- 
gitgitgadget


^ permalink raw reply related

* [PATCH 08/11] transport-helper: warn when export-marks file cannot be finalized
From: Johannes Schindelin via GitGitGadget @ 2026-07-14 22:48 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Johannes Schindelin
In-Reply-To: <pull.2179.git.1784069325.gitgitgadget@gmail.com>

From: Johannes Schindelin <johannes.schindelin@gmx.de>

When push_refs_with_export() finalizes a successful push, it writes
the fast-export marks file to a .tmp sibling and rename()s it into
place. The return value of rename() is currently ignored. If the
rename fails (permission denied, full disk, or an antivirus product
locking the destination on Windows), the .tmp file is left behind
and the existing export_marks file remains stale; the next
fast-export operation that resumes from it then silently operates on
inconsistent bookkeeping.

The push itself succeeded by that point, so promoting this to a
fatal error would be inappropriate. Emit warning_errno() naming both
paths so the user can recover manually, and keep returning 0.

Flagged by Coverity as CID 1427723 ("Unchecked return value").

Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 transport-helper.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/transport-helper.c b/transport-helper.c
index 31883b244e..ed0543f1ad 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -1184,7 +1184,9 @@ static int push_refs_with_export(struct transport *transport,
 
 	if (data->export_marks) {
 		strbuf_addf(&buf, "%s.tmp", data->export_marks);
-		rename(buf.buf, data->export_marks);
+		if (rename(buf.buf, data->export_marks))
+			warning_errno(_("could not rename '%s' to '%s'"),
+				      buf.buf, data->export_marks);
 		strbuf_release(&buf);
 	}
 
-- 
gitgitgadget


^ permalink raw reply related

* [PATCH 09/11] bisect: check strbuf_getline_lf return when reading terms
From: Johannes Schindelin via GitGitGadget @ 2026-07-14 22:48 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Johannes Schindelin
In-Reply-To: <pull.2179.git.1784069325.gitgitgadget@gmail.com>

From: Johannes Schindelin <johannes.schindelin@gmx.de>

get_terms() in builtin/bisect.c and read_bisect_terms() in
bisect.c both read the BISECT_TERMS file but do not check the
strbuf_getline_lf() return values. If the file is truncated
(e.g., a partial write from a crash or disk-full condition),
strbuf_getline_lf returns EOF and the strbuf remains empty.
strbuf_detach then returns an empty string, and the term names
silently become "" instead of the expected "bad"/"good" or
custom terms.

In get_terms(), check for EOF and return -1 on truncation,
matching the existing -1 return for a missing file.

In read_bisect_terms(), die with a descriptive message when a
line cannot be read, consistent with the die_errno for a
non-ENOENT open failure in the same function. Unlike get_terms(),
read_bisect_terms() returns void and uses die() for all error
paths, so the die is the appropriate error handling here.

Pointed out by Coverity.

Assisted-by: Claude Opus 4.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 bisect.c         |  6 ++++--
 builtin/bisect.c | 10 ++++++++--
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/bisect.c b/bisect.c
index 94c7028d2a..c2ef5da462 100644
--- a/bisect.c
+++ b/bisect.c
@@ -1019,10 +1019,12 @@ void read_bisect_terms(char **read_bad, char **read_good)
 			die_errno(_("could not read file '%s'"), filename);
 		}
 	} else {
-		strbuf_getline_lf(&str, fp);
+		if (strbuf_getline_lf(&str, fp) == EOF)
+			die(_("could not read bad term from file '%s'"), filename);
 		free(*read_bad);
 		*read_bad = strbuf_detach(&str, NULL);
-		strbuf_getline_lf(&str, fp);
+		if (strbuf_getline_lf(&str, fp) == EOF)
+			die(_("could not read good term from file '%s'"), filename);
 		free(*read_good);
 		*read_good = strbuf_detach(&str, NULL);
 	}
diff --git a/builtin/bisect.c b/builtin/bisect.c
index 798e28f501..fe66d84382 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -498,9 +498,15 @@ static int get_terms(struct bisect_terms *terms)
 	}
 
 	free_terms(terms);
-	strbuf_getline_lf(&str, fp);
+	if (strbuf_getline_lf(&str, fp) == EOF) {
+		res = -1;
+		goto finish;
+	}
 	terms->term_bad = strbuf_detach(&str, NULL);
-	strbuf_getline_lf(&str, fp);
+	if (strbuf_getline_lf(&str, fp) == EOF) {
+		res = -1;
+		goto finish;
+	}
 	terms->term_good = strbuf_detach(&str, NULL);
 
 finish:
-- 
gitgitgadget


^ permalink raw reply related

* [PATCH 10/11] bisect: check get_terms return at all call sites
From: Johannes Schindelin via GitGitGadget @ 2026-07-14 22:48 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Johannes Schindelin
In-Reply-To: <pull.2179.git.1784069325.gitgitgadget@gmail.com>

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Six callers of get_terms() silently discard its return value. When
get_terms fails (missing or truncated BISECT_TERMS file), the term
strings remain NULL or empty, causing confusing downstream
behavior: commands like "bisect next" or "bisect run" proceed with
empty term strings, producing nonsensical ref names (refs/bisect/
with no suffix) and misleading error messages.

Add checks at each call site so that a failed get_terms produces a
clear "no terms defined" error, matching the pattern already used
in bisect_terms() at line 512. The check tests the term pointers
rather than the return value because some callers (bisect skip,
legacy bad/good) call set_terms before get_terms, and the
set_terms values should survive a get_terms failure.

Pointed out by Coverity.

Assisted-by: Claude Opus 4.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/builtin/bisect.c b/builtin/bisect.c
index fe66d84382..15a2a30f89 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -1057,6 +1057,8 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
 	*word_end = '\0'; /* NUL-terminate the word */
 
 	get_terms(terms);
+	if (!terms->term_bad || !terms->term_good)
+		return error(_("no terms defined"));
 	if (check_and_set_terms(terms, p))
 		return -1;
 
@@ -1383,6 +1385,8 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref
 		return error(_("'%s' requires 0 arguments"),
 			     "git bisect next");
 	get_terms(&terms);
+	if (!terms.term_bad || !terms.term_good)
+		return error(_("no terms defined"));
 	res = bisect_next(&terms, prefix);
 	free_terms(&terms);
 	return res;
@@ -1417,6 +1421,8 @@ static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUS
 
 	set_terms(&terms, "bad", "good");
 	get_terms(&terms);
+	if (!terms.term_bad || !terms.term_good)
+		return error(_("no terms defined"));
 	res = bisect_skip(&terms, argc, argv);
 	free_terms(&terms);
 	return res;
@@ -1429,6 +1435,8 @@ static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix
 	struct bisect_terms terms = { 0 };
 
 	get_terms(&terms);
+	if (!terms.term_bad || !terms.term_good)
+		return error(_("no terms defined"));
 	res = bisect_visualize(&terms, argc, argv);
 	free_terms(&terms);
 	return res;
@@ -1443,6 +1451,8 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE
 	if (!argc)
 		return error(_("'%s' failed: no command provided."), "git bisect run");
 	get_terms(&terms);
+	if (!terms.term_bad || !terms.term_good)
+		return error(_("no terms defined"));
 	res = bisect_run(&terms, argc, argv);
 	free_terms(&terms);
 	return res;
@@ -1482,6 +1492,8 @@ int cmd_bisect(int argc,
 
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
+		if (!terms.term_bad || !terms.term_good)
+			return error(_("no terms defined"));
 		if (check_and_set_terms(&terms, argv[0]) ||
 		    !one_of(argv[0], terms.term_good, terms.term_bad, NULL))
 			usage_msg_optf(_("unknown command: '%s'"), git_bisect_usage,
-- 
gitgitgadget


^ permalink raw reply related

* [PATCH 11/11] bisect: handle dup() failure when redirecting stdout
From: Johannes Schindelin via GitGitGadget @ 2026-07-14 22:48 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Johannes Schindelin
In-Reply-To: <pull.2179.git.1784069325.gitgitgadget@gmail.com>

From: Johannes Schindelin <johannes.schindelin@gmx.de>

To capture the output of each verdict command, bisect_run()
temporarily redirects stdout to a temporary file via the classic
dup(1) / dup2() pair, restoring it afterwards. The return value of
dup(1) is not checked, however. When it fails, the saved descriptor
is -1, which is then passed to close() (the issue Coverity flags),
and the matching dup2() that is meant to restore stdout also fails,
leaving the process with stdout still pointing at the temporary file
for the remainder of the run.

Treat a failed dup(1) as a fatal error for this bisect step: close
the temporary file descriptor, report the error via error_errno(),
and break out of the loop so the existing cleanup path handles the
rest, just as on other failure paths in this function.

Reported by Coverity as CID 1508242 ("Improper use of negative
value").

Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/builtin/bisect.c b/builtin/bisect.c
index 15a2a30f89..801daf8c78 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -1308,6 +1308,11 @@ static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)
 
 		fflush(stdout);
 		saved_stdout = dup(1);
+		if (saved_stdout < 0) {
+			res = error_errno(_("could not duplicate stdout"));
+			close(temporary_stdout_fd);
+			break;
+		}
 		dup2(temporary_stdout_fd, 1);
 
 		res = bisect_state(terms, 1, &new_state);
-- 
gitgitgadget

^ permalink raw reply related

* Re: [PATCH GSoC v17 00/13] cat-file: add remote-object-info to batch-command
From: Pablo Sabater @ 2026-07-14 22:50 UTC (permalink / raw)
  To: Junio C Hamano, Pablo Sabater
  Cc: chandrapratap3519, chriscool, eric.peijian, git, jltobler,
	karthik.188, peff, toon
In-Reply-To: <xmqq8q7dto8d.fsf@gitster.g>

On Tue Jul 14, 2026 at 8:33 PM CEST, Junio C Hamano wrote:
> Pablo Sabater <pabloosabaterr@gmail.com> writes:
>
>> This patch series is a continuation of Eric Ju's
>> (eric.peijian@gmail.com) and Calvin Wan's (calvinwan@google.com) patch
>> series [1] and [2] respectively.
>
> Yuck.  I thought we had this marked as "Will merge to 'next'?" for
> some time and this morning I pushed out a merge to 'next' of v16.
> I'll revert the merge and replace.

Hi!

Sorry, I'm confused about the last line about 'next' and the replace.

You gave me feedback for v17 10th commit:

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

Should I send a v18 or a new patch on top of 'next'?

The fix is simple and I already have it on my local, I just want to do
whatever is better.

Regards,
Pablo.

^ permalink raw reply

* Re: [PATCH v2 02/10] sequencer: move definition of is_final_fixup()
From: Andrei Rybak @ 2026-07-14 22:50 UTC (permalink / raw)
  To: phillip.wood123
  Cc: farid.m.zakaria, git, gitster, oswald.buddenhagen, phillip.wood,
	u.kleine-koenig
In-Reply-To: <02670f57e7d81d4ff7341fecff3ef04b9fdc0102.1783948637.git.phillip.wood@dunelm.org.uk>

> Move this function earlier in the file in preparation for adding a
> new caller in a later commit.
> 
> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> ---
>  sequencer.c | 30 +++++++++++++++---------------
>  1 file changed, 15 insertions(+), 15 deletions(-)
> 
> diff --git a/sequencer.c b/sequencer.c
> index 57855b0066a..32a09b6e87d 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -4627,21 +4627,6 @@ static int do_update_refs(struct repository *r, int quiet)
>  	strbuf_release(&update_msg);
>  	strbuf_release(&error_msg);
>  	return res;
> -}
> -
> -static int is_final_fixup(struct todo_list *todo_list)
> -{
> -	int i = todo_list->current;
> -
> -	if (!is_fixup(todo_list->items[i].command))
> -		return 0;
> -
> -	while (++i < todo_list->nr)
> -		if (is_fixup(todo_list->items[i].command))
> -			return 0;
> -		else if (!is_noop(todo_list->items[i].command))
> -			break;
> -	return 1;
>  }
>  
>  static enum todo_command peek_command(struct todo_list *todo_list, int offset)
> @@ -4925,6 +4910,21 @@ static int reread_todo_if_changed(struct repository *r,

4910 is greater than 4627, the function is_final_fixup() seems to have been
moved _later_ in the file.  But the commit message says "Move this function
earlier in the file".  Am I missing something?

>  	strbuf_release(&buf);
>  
>  	return 0;
> +}
> +
> +static int is_final_fixup(struct todo_list *todo_list)
> +{
> +	int i = todo_list->current;
> +
> +	if (!is_fixup(todo_list->items[i].command))
> +		return 0;
> +
> +	while (++i < todo_list->nr)
> +		if (is_fixup(todo_list->items[i].command))
> +			return 0;
> +		else if (!is_noop(todo_list->items[i].command))
> +			break;
> +	return 1;
>  }
>  
>  static const char rescheduled_advice[] =
> -- 
> 2.54.0.200.gfd8d68259e3

^ permalink raw reply

* What's cooking in git.git (Jul 2026, #06)
From: Junio C Hamano @ 2026-07-15  0:00 UTC (permalink / raw)
  To: git

Here are the topics that have been cooking in my tree.  Commits
prefixed with '+' are in 'next' (being in 'next' is a sign that a
topic is stable enough to be used and is a candidate to be in a
future release).  Commits prefixed with '-' are only in 'seen', and
aren't considered "accepted" at all.  They may be annotated with a URL
to a message that raises issues but they are by no means exhaustive.
A topic without enough support may be discarded after a long period
of no activity (of course, it can be resubmitted when new interest
arises).

The second batch of topics have now graduated to the 'master'
branch.

Copies of the source code to Git live in many repositories, and the
following is a list of the ones I push into or their mirrors.  Some
repositories have only a subset of branches.

With maint, master, next, seen, todo:

	git://git.kernel.org/pub/scm/git/git.git/
	git://repo.or.cz/alt-git.git/
	https://kernel.googlesource.com/pub/scm/git/git/
	https://github.com/git/git/
	https://gitlab.com/git-scm/git/

With all the integration branches and topics broken out:

	https://github.com/gitster/git/

Even though the preformatted documentation in HTML and man format
are not sources, they are published in these repositories for
convenience (replace "htmldocs" with "manpages" for the manual
pages):

	git://git.kernel.org/pub/scm/git/git-htmldocs.git/
	https://github.com/gitster/git-htmldocs.git/

Release tarballs are available at:

	https://www.kernel.org/pub/software/scm/git/

--------------------------------------------------
[Graduated to 'master']

* ad/gpg-strip-cr-before-lf (2026-06-24) 1 commit
  (merged to 'next' on 2026-07-06 at b099249efd)
 + gpg-interface: fix strip_cr_before_lf to only remove CR before LF

 The GPG and SSH signature parsing code has been corrected to strip
 carriage return characters only when they immediately precede line
 feeds, instead of unconditionally stripping all carriage returns.

 Graduated to 'master'.
 source: <20260624093618.17456-1-antonio.destefani08@gmail.com>


* hn/branch-push-slip-advice (2026-06-27) 2 commits
  (merged to 'next' on 2026-07-06 at acdff65ac5)
 + push: suggest <remote> <branch> for a slash slip
 + branch: suggest <remote>/<branch> on upstream slip

 When 'git push origin/main' or 'git branch origin main' is run, the
 command is now recognized as a potential typo, and advice has been
 added to offer a typo fix.

 Graduated to 'master'.
 cf. <xmqqfr272lq7.fsf@gitster.g>
 source: <pull.2331.v3.git.git.1782583345.gitgitgadget@gmail.com>


* jk/format-patch-leakfix (2026-06-29) 2 commits
  (merged to 'next' on 2026-07-06 at 35aff0d609)
 + format-patch: fix leak of rev_info in prepare_bases()
 + t: move LSan errors from stdout to stderr

 A memory leak in the '--base' handling of 'git format-patch' has been
 plugged, and the leak reporting of the test suite when running under a
 TAP harness has been improved.

 Graduated to 'master'.
 cf. <akOZy-BygZS8fqPM@pks.im>
 source: <20260630063944.GA3733670@coredump.intra.peff.net>


* jk/reftable-leakfix (2026-06-28) 1 commit
  (merged to 'next' on 2026-07-06 at 55ce81f2d5)
 + reftable: fix unlikely leak on API error

 A memory leak in the 'reftable_writer_new()' initialization function
 has been fixed by delaying the allocation of 'struct reftable_writer'
 until after input options are validated.

 Graduated to 'master'.
 cf. <akIPBJLtPqDjQt-A@pks.im>
 source: <20260628090314.GA661068@coredump.intra.peff.net>


* kk/prio-queue-get-put-fusion (2026-06-08) 2 commits
  (merged to 'next' on 2026-07-06 at aa748c4564)
 + prio-queue: fold lazy_queue into prio_queue for automatic get+put fusion
 + prio-queue: rename .nr to .nr_ and add accessor helpers
 (this branch is used by kk/prio-queue-cascade-sift.)

 The lazy priority queue optimization pattern (deferring actual removal
 in 'prio_queue_get()' to allow get+put fusion) has been folded
 directly into 'prio_queue' itself, speeding up commit traversal
 workflows and simplifying callers.

 Graduated to 'master'.
 cf. <xmqqh5mjrbgq.fsf@gitster.g>
 source: <pull.2140.v4.git.1780945851.gitgitgadget@gmail.com>


* ps/odb-generalize-prepare (2026-06-22) 3 commits
  (merged to 'next' on 2026-07-06 at 6132517517)
 + odb: introduce `odb_prepare()`
 + odb/source: generalize `reprepare()` callback
 + Merge branch 'ps/odb-source-packed' into ps/odb-generalize-prepare

 The 'reprepare()' callback for object database sources has been
 generalized into a 'prepare()' callback with an optional flush cache
 flag, and a new 'odb_prepare()' wrapper has been introduced to allow
 pre-opening object database sources.

 Graduated to 'master'.
 cf. <87ik704f1j.fsf@emacs.iotcl.com>
 source: <20260622-b4-pks-odb-generalize-prepare-v1-0-d2a5c5d13144@pks.im>

--------------------------------------------------
[New Topics]

* tb/send-pack-no-ref-delta (2026-07-12) 4 commits
 - send-pack: honor `no-ref-delta` capability
 - pack-objects: support reuse with `--no-ref-delta`
 - pack-objects: introduce `--no-ref-delta`
 - t/helper: teach pack-deltas to list delta entries

 'git send-pack' has been taught to refrain from sending 'REF_DELTA'
 encoded packfiles when the other side asks it to.

 Needs review.
 source: <alQ7WKITYDXfiVn9@com-79390>


* cc/doc-fast-export-synopsis-fix (2026-07-13) 1 commit
 - fast-export: standardize usage string and SYNOPSIS

 The usage string and SYNOPSIS for 'git fast-export' have been
 standardized to make them consistent with each other and with other
 commands.

 Will merge to 'next'?
 cf. <alX5Nl8uX4ctVqo3@pks.im>
 source: <20260713124153.245268-1-christian.couder@gmail.com>


* sk/t1100-modernize (2026-07-14) 2 commits
 - t1100: move creation of expected output into setup test
 - t1100: modernize test style

 The test script 't/t1100-commit-tree-options.sh' has been modernized
 by converting test cases to the modern style (using single quotes and
 tab indentation) and moving the creation of the expected file inside
 the setup test so it runs under the protection of the test harness.

 Will merge to 'next'?
 cf. <xmqq4ii1v7x0.fsf@gitster.g>
 source: <20260714122033.61947-1-diy2903@gmail.com>


* tn/packfile-uri-concurrency (2026-07-13) 2 commits
 - fetch-pack: accept "pack" output for packfile URIs
 - http: use unique tempfiles for packfile URI downloads

 Concurrent downloads of packfiles via packfile URIs have been
 supported by using unique temporary files, preventing corruption when
 multiple processes fetch the same pack.  The 'fetch-pack' command has
 also been updated to tolerate pre-existing '.keep' files.

 Expecting a reroll.
 cf. <alaAi4vNwi-KabYV@com-76773>
 source: <alVn-QmK3K91_tkH@com-76773>


* rs/strbuf-avoid-redundant-reset (2026-07-14) 1 commit
 - strbuf: avoid redundant reset in strbuf_getwholeline()

 A redundant 'strbuf_reset()' call in the 'HAVE_GETDELIM' path of
 'strbuf_getwholeline()' has been removed, as 'getdelim()' overwrites
 the buffer and the length is updated afterwards.

 Will merge to 'next'?
 cf. <xmqq8q7dv82b.fsf@gitster.g>
 source: <d4ffe7fb-f782-4f06-9e3b-f72729d1e225@web.de>


* rs/tempfile-wo-the-repository (2026-07-14) 5 commits
 - use repo_hold_lock_file_for_update{,_mode,_timeout}() with custom repos
 - tempfile: stop using the_repository
 - lockfile: add repo_hold_lock_file_for_update{,_timeout}{,_mode}()
 - refs/packed: use repo_create_tempfile()
 - tempfile: add repo_create_tempfile{,_mode}()

 The tempfile and lockfile APIs have been refactored to stop depending
 on the 'the_repository' global variable, and their callers have been
 updated to use the repository-aware variants.

 Needs review.
 source: <20260714175956.54601-1-l.s.r@web.de>

--------------------------------------------------
[Stalled]

* kh/doc-trailers (2026-06-10) 10 commits
 - doc: interpret-trailers: document comment line treatment
 - doc: interpret-trailers: commit to “trailer block” term
 - doc: interpret-trailers: join new-trailers again
 - doc: interpret-trailers: add key format example
 - doc: interpret-trailers: explain key format
 - doc: interpret-trailers: explain the format after the intro
 - doc: interpret-trailers: not just for commit messages
 - doc: interpret-trailers: use “metadata” in Name as well
 - doc: interpret-trailers: replace “lines” with “metadata”
 - doc: interpret-trailers: stop fixating on RFC 822

 Documentation for 'git interpret-trailers' has been updated to explain
 the format of trailer keys (alphanumeric characters and hyphens),
 replace outdated terminology, define key terms upfront, and document
 how comment lines in the input are treated.

 Expecting a reroll for too long, stalled.
 cf. <729baf6b-53ea-4e8d-95ab-5935667e66c2@app.fastmail.com>
 source: <V3_CV_doc_int-tr_key_format.8a3@msgid.xyz>


* sn/rebase-update-refs-symrefs (2026-06-03) 1 commit
 - rebase: skip branch symref aliases

 'git rebase --update-refs' has been taught to resolve local branch
 symrefs to their referents before queuing updates, ensuring aliases of
 the current branch are skipped and duplicate updates are avoided to
 prevent failures when branch aliases are present.

 Waiting for response(s) to review comment(s) for too long, stalled.
 cf. <f982c386-e329-4ab0-b695-e540bcb9de3d@gmail.com>
 source: <pull.2126.v2.git.1780482436865.gitgitgadget@gmail.com>


* ap/http-redirect-wwwauth-fix (2026-06-02) 1 commit
 - http: preserve wwwauth_headers across redirects

 When 'cURL' follows a redirect, the 'WWW-Authenticate' headers from
 the redirect target were lost because 'credential_from_url()' cleared
 the credential state.  This has been fixed by preserving the collected
 headers across the redirect update.

 Will discard.
 cf. <xmqqmrw2zavx.fsf@gitster.g>
 source: <20260602161150.1527493-1-aplattner@nvidia.com>


* jt/config-lock-timeout (2026-05-17) 1 commit
 - config: retry acquiring config.lock, configurable via core.configLockTimeout

 Configuration file locking has been updated to retry for a short
 period, avoiding failures when multiple processes attempt to update
 the configuration simultaneously.

 Waiting for response(s) to review comment(s) for too long, stalled.
 cf. <agrIrGwSMFlKTx9x@pks.im>
 source: <20260517132111.1014901-1-joerg@thalheim.io>

--------------------------------------------------
[Cooking]

* js/pack-objects-delta-size-t (2026-07-09) 12 commits
 - git-zlib: widen `git_deflate_bound()` to `size_t`
 - t/helper/test-pack-deltas: widen `do_compress()`'s maxsize local to `size_t`
 - http-push: widen `start_put()`'s size local from `ssize_t` to `size_t`
 - diff: widen `deflate_it()`'s bound local from int to `size_t`
 - archive-zip: widen `zlib_deflate_raw()`'s maxsize local to `size_t`
 - packfile, git-zlib: widen `use_pack()` and zstream avail fields to `size_t`
 - delta: widen `create_delta()` and `diff_delta()` to `size_t`
 - pack-objects: widen `mem_usage` and `try_delta()`'s out-param to `size_t`
 - pack-objects: widen `free_unpacked()` return to `size_t`
 - pack-objects: widen delta-cache accounting to `size_t`
 - delta: widen `create_delta_index()` parameter to `size_t`
 - diff-delta: widen `struct delta_index`' size fields to `size_t`

 The pack-objects and delta-encoding code paths have been updated to
 use 'size_t' instead of 'unsigned long' for object sizes and offset
 limits, avoiding potential truncation issues on 64-bit Windows.

 Needs review.
 source: <pull.2175.git.1783615780.gitgitgadget@gmail.com>


* cl/b4-cover-change-id (2026-07-10) 1 commit
  (merged to 'next' on 2026-07-13 at 15c7ad9a3f)
 + b4: include change-id in cover template

 The in-tree 'b4' cover letter template has been updated to include the
 'change-id' trailer, ensuring that sent tags generated by 'b4' contain
 the required tracking information for subsequent runs.

 Will merge to 'master'.
 source: <20260710-add-change-id-to-b4-template-v1-1-1bd37a25064e@black-desk.cn>


* ps/odb-stream-double-close-fix (2026-07-10) 1 commit
  (merged to 'next' on 2026-07-13 at dd2c5795b7)
 + object-file: fix closing object stream twice

 The stream-based object signature verification path has been
 corrected to avoid double-closing the stream on read errors.

 Will merge to 'master'.
 source: <20260710-pks-odb-stream-double-close-v1-1-d5fa233a37c7@pks.im>


* pz/fetch-submodule-errors-config (2026-07-14) 4 commits
 - fixup! fetch: add fetch.submoduleErrors to make submodule fetch errors non-fatal
 - fixup! fetch: add fetch.submoduleErrors to make submodule fetch errors non-fatal
 - fetch: add fetch.submoduleErrors to make submodule fetch errors non-fatal
 - submodule: fix premature failure in recursive submodule fetch

 The 'git fetch' command has been updated to allow configuring how
 submodule fetch errors are handled.  A new configuration variable
 'fetch.submoduleErrors' and a corresponding '--submodule-errors'
 command-line option have been introduced, allowing users to make
 submodule fetch errors non-fatal (warn instead of fail).
 Additionally, a premature failure during recursive submodule fetches
 has been fixed by deferring the error until the OID-based retry phase
 also fails.

 Needs review.
 cf. <xmqqldbdvb3x.fsf@gitster.g>
 source: <20260714132959.3368867-1-paulius.zaleckas@gmail.com>


* gr/add-e-use-apply-api (2026-07-10) 1 commit
 - builtin/add.c: replace run_command() with direct apply_all_patches() call

 The application of the edited patch in 'git add -e' has been
 refactored to use the internal apply API directly, avoiding the need
 to spawn a 'git apply' subprocess.

 Needs review.
 source: <20260711061246.58079-1-gatlavishweshwarreddy26@gmail.com>


* fz/rebase-autosquash-empty (2026-07-11) 1 commit
 . sequencer: honor --empty when a fixup!/squash! empties its target

 A commit that is emptied by melding a 'fixup!' or 'squash!' commit
 during 'git rebase --autosquash' is now handled according to the
 '--empty' option, allowing it to be dropped, kept, or to halt the
 rebase.

 Expecting a reroll.
 cf. <DJXL4KSUEAD4.1EE4ERHJZ00TR@gmail.com>
 source: <20260711-fz-autosquash-empty-v3-1-d227b63eb511@gmail.com>


* dm/submodule-update-i-shorthand (2026-07-07) 1 commit
 - submodule--helper: accept '-i' shorthand for update --init

 The '-i' shorthand for the '--init' option, which was accepted by the
 'git submodule update' command until it was broken in a modernization
 of the option-parsing code, has been restored.

 Will merge to 'next'.
 cf. <xmqq8q7ltf51.fsf@gitster.g>
 source: <20260708-submodule-init-v1-1-719456077262@atmark-techno.com>


* hf/unpack-trees-quadratic-scan (2026-07-08) 1 commit
  (merged to 'next' on 2026-07-12 at 744f1aede4)
 + unpack-trees: avoid quadratic index scan in next_cache_entry()

 The cache-scanning loop in 'next_cache_entry()' has been optimized
 to avoid rescanning already-unpacked index entries, preventing a
 quadratic performance slow-down when diffing the working tree
 against a commit with a pathspec matching early index entries.

 Will merge to 'master'.
 cf. <xmqqpl0xqh3n.fsf@gitster.g>
 source: <pull.2353.v2.git.git.1783546933992.gitgitgadget@gmail.com>


* jc/relnotes-2.55-rust-fix (2026-07-07) 1 commit
  (merged to 'next' on 2026-07-10 at 444d202a75)
 + Rust: fix description in Release Notes to 2.55

 A description in the release notes for Git 2.55.0 has been
 retroactively updated to clarify that Rust support is enabled by
 default, but still optional, and will become mandatory in Git 3.0.

 Will merge to 'master'.
 source: <xmqqpl0y4rpg.fsf@gitster.g>


* jc/submitting-patches-abandoning (2026-07-08) 1 commit
  (merged to 'next' on 2026-07-10 at 41b9b65b23)
 + SubmittingPatches: document how to retract a topic

 The 'SubmittingPatches' document has been updated to explicitly
 describe the expectation for contributors to retract or abandon their
 patch series when they are no longer pursuing it.

 Will merge to 'master'.
 cf. <ak6U07K1dQPlXxIp@nixos>
 source: <xmqqpl0xv25e.fsf@gitster.g>


* jk/git-hash-cleanups (2026-07-07) 8 commits
  (merged to 'next' on 2026-07-09 at 12a4856545)
 + hash: check ctx->active flag in all wrapper functions
 + http: use idempotent git_hash_discard()
 + csum-file: use idempotent git_hash_discard()
 + hash: make git_hash_discard() idempotent
 + hash: document function pointers and wrappers
 + hash: convert remaining direct function calls
 + hash: use git_hash_init() consistently
 + Merge branch 'jk/hash-algo-leak-fixes' into jk/git-hash-cleanups
 (this branch uses jk/hash-algo-leak-fixes.)

 The 'git_hash_*()' wrappers have been updated to be used consistently
 across the codebase instead of direct calls to members of 'struct
 git_hash_algo', and 'git_hash_discard()' has been made idempotent to
 simplify cleanups.

 Will merge to 'master'.
 cf. <ak4E4-jmgYFSI75O@pks.im>
 source: <20260708035235.GA41491@coredump.intra.peff.net>


* mm/lib-httpd-cgi-safe (2026-07-10) 3 commits
 - t/README: document writing concurrency-safe helpers
 - t/lib-httpd: make http-429 first-request check atomic
 - t/lib-httpd: fix apply-one-time-script race under concurrent requests

 CGI helper scripts used by HTTP-related test scripts have been updated
 to use atomic filesystem operations, preventing race conditions when
 Apache handles concurrent requests.

 Needs review.
 source: <pull.2171.v2.git.1783704657.gitgitgadget@gmail.com>


* mm/sideband-ansi-sgr-colon-fix (2026-05-13) 1 commit
  (merged to 'next' on 2026-07-09 at fd2b979b73)
 + sideband: allow ANSI SGR with colon-separated subfields

 The sideband demultiplexer has been updated to recognize ANSI SGR
 escape sequences that use colon-separated subfields (e.g., for
 256-color or true-color codes).

 Will merge to 'master'.
 cf. <8addf7c0-ae39-f1c0-20ab-52114702aaf6@gmx.de>
 source: <20260513070803.163546-1-grawity@nullroute.lt>


* ps/odb-pluggable-housekeeping (2026-07-12) 12 commits
 - odb: make optimizations pluggable
 - builtin/gc: fix signedness issues in ODB-related functionality
 - builtin/gc: refactor ODB optimizations to operate on "files" source
 - builtin/gc: introduce `odb_optimize_required()`
 - builtin/gc: move geometric repacking into `odb_optimize()`
 - builtin/gc: introduce object database optimization options
 - builtin/gc: inline config values specific to the "files" backend
 - builtin/gc: make repack arguments self-contained
 - builtin/gc: extract object database optimizations into separate function
 - builtin/gc: move worktree and rerere tasks before object optimizations
 - odb: run "pre-auto-gc" hook for all maintenance tasks
 - t7900: simplify how we check for maintenance tasks

 Object database housekeeping in 'git gc' and 'git maintenance' has
 been refactored to be pluggable.  The files-backend specific logic,
 including incremental and geometric repacking as well as object
 pruning, has been moved out of the command implementation and into the
 files object database source, enabling future alternative object
 database backends to implement their own housekeeping services.

 Needs review.
 cf. <xmqqwluyyhv1.fsf@gitster.g>
 source: <20260713-b4-pks-odb-optimize-v2-0-9c2c3ee94b38@pks.im>


* tc/bundle-uri-empty-fix (2026-07-08) 2 commits
  (merged to 'next' on 2026-07-12 at 9da32fdaf7)
 + bundle-uri: stop sending invalid bundle configuration
 + bundle-uri: drain remaining response on invalid bundle-uri lines

 The client-side parser of the server-advertised bundle-URI list has
 been updated to drain the remaining response in order to avoid
 protocol desynchronization when the server sends a misconfigured list.
 Also, the server-side has been taught to omit empty configuration
 values instead of sending invalid key-value lines.

 Will merge to 'master'.
 cf. <xmqqtsq9qj5k.fsf@gitster.g>
 source: <20260708-toon-bundle-uri-no-uri-v2-0-09a03d8db556@iotcl.com>


* gr/t1410-reflog-exit-code (2026-07-08) 1 commit
  (merged to 'next' on 2026-07-10 at d0cf55ea54)
 + t1410-reflog.sh: avoid suppressing git's exit code in pipelines

 The pipelines in 't1410-reflog.sh' have been replaced with the
 'test_stdout_line_count' helper to avoid suppressing the exit code of
 'git' commands, ensuring failures are not hidden from the test suite.

 Will merge to 'master'.
 cf. <xmqqtsq8p18x.fsf@gitster.g>
 source: <20260709051229.40363-1-gatlavishweshwarreddy26@gmail.com>


* js/coverity-fixes-null-safety (2026-07-10) 12 commits
  (merged to 'next' on 2026-07-12 at 8d093f411d)
 + shallow: give write_one_shallow() its own hex buffer
 + shallow: fix NULL dereference
 + bisect: ensure non-NULL `head` before using it
 + pack-bitmap: handle missing bitmap for base MIDX
 + revision: avoid dereferencing NULL in `add_parents_only()`
 + replay: die when --onto does not peel to a commit
 + bisect: handle NULL commit in `bisect_successful()`
 + mailsplit: move NULL check before first use of file handle
 + reftable/stack: guard against NULL list_file in stack_destroy
 + remote: guard `remote_tracking()` against NULL remote
 + diff: handle NULL return from repo_get_commit_tree()
 + diffcore-break: guard against NULLed queue entries in merge loop

 Various code paths have been hardened against potential NULL-pointer
 dereferences and invalid file descriptor accesses flagged by
 Coverity.

 Will merge to 'master'.
 cf. <xmqqa4ryg84e.fsf@gitster.g>
 source: <pull.2174.v2.git.1783683577.gitgitgadget@gmail.com>


* ps/odb-for-each-object-filter (2026-07-13) 10 commits
 - builtin/cat-file: filter objects via object database
 - odb: introduce object filters to `odb_for_each_object()`
 - pack-bitmap: introduce function to open bitmap for a single source
 - pack-bitmap: drop `_1` suffix from functions that open bitmaps
 - pack-bitmap: iterate object sources when opening bitmaps
 - pack-bitmap: allow aborting iteration of bitmapped objects
 - pack-objects: drop unused return value from add_object_entry()
 - pack-bitmap: mark object filter as `const`
 - odb/source-packed: improve lookup when enumerating objects
 - Merge branch 'ps/odb-drop-whence' into ps/odb-for-each-object-filter
 (this branch uses ps/odb-drop-whence.)

 The object database enumeration interface 'odb_for_each_object()'
 has been taught to accept object filters, allowing the underlying
 backends to optimize the traversal by using reachability bitmaps
 when available.  'git cat-file --batch-all-objects' has been updated
 to use this generic interface, simplifying its code and avoiding
 direct access to ODB backend internals.

 Will merge to 'next'?
 cf. <alW0KzSZuZnHmOZD@com-79390>
 source: <20260713-pks-odb-for-each-object-filter-v3-0-b3c65c641073@pks.im>


* ps/refs-wo-the-repository (2026-07-09) 8 commits
 - refs: remove remaining uses of `the_repository`
 - worktree: pass repository to public functions
 - worktree: pass repository to file-local functions
 - worktree: refactor code to use available repositories
 - refs/files: drop `USE_THE_REPOSITORY_VARIABLE`
 - refs/packed: drop `USE_THE_REPOSITORY_VARIABLE`
 - refs/packed: de-globalize handling of "core.packedRefsTimeout"
 - Merge branch 'ps/refs-writing-subcommands' into ps/refs-wo-the-repository
 (this branch uses ps/refs-writing-subcommands.)

 The ref subsystem and the worktree API have been refactored to pass a
 repository pointer down the call chain, allowing them to drop
 references to the global 'the_repository' variable.  As part of this,
 the handling of the 'core.packedRefsTimeout' configuration has been
 moved into the per-repository ref store structure.

 Expecting a reroll.
 cf. <alCJpxAQwpTQ4g93@pks.im>
 source: <20260709-pks-refs-wo-the-repository-v1-0-1ad6f27529c9@pks.im>


* kk/commit-graph-topo-levels-fix (2026-07-09) 2 commits
  (merged to 'next' on 2026-07-12 at 295a5f9b34)
 + commit-graph: propagate topo_levels slab to all chain layers
 + commit-graph: add trace2 instrumentation for generation DFS

 The 'topo_levels' slab was propagated only to the topmost layer of a
 split commit-graph chain, causing topological levels for commits in
 base layers to be recomputed during incremental writes.  This has been
 corrected.

 Will merge to 'master'.
 cf. <alFu8gZURKhYr1VE@com-79390>
 source: <pull.2170.v2.git.1783609382.gitgitgadget@gmail.com>


* ds/sparse-index-ita-crash (2026-07-06) 1 commit
 - sparse-index: avoid crash on intent-to-add entry outside the cone

 A crash in the sparse-index collapse code when encountering an
 invalidated cache-tree node (due to an intent-to-add path) has been
 fixed by avoiding collapsing such subtrees.

 Needs review.
 source: <pull.2167.git.1783345853272.gitgitgadget@gmail.com>


* ij/subtree-reject-v2-config (2026-07-06) 2 commits
 - git-subtree: Bail out if we find output from Rust rewrite (test)
 - git-subtree: Bail out if we find output from Rust rewrite

 The shell script implementation of 'git subtree' has been updated to
 check for the presence of the configuration file of the new Rust
 implementation, preventing users from accidentally running the old
 script on repositories already managed by the new tool.

 Expecting a reroll.
 cf. <27219.20156.438730.881821@chiark.greenend.org.uk>
 source: <20260706115816.20267-1-ijackson@chiark.greenend.org.uk>


* kk/reftable-tombstone-quadratic-fix (2026-07-10) 2 commits
  (merged to 'next' on 2026-07-12 at 4e60bb0027)
 + reftable: fix quadratic behavior in the presence of tombstones
 + t/perf: add perf test for ref tombstone scenarios

 The performance of ref updates and reads using the 'reftable' backend
 in the presence of many deletion tombstone records has been optimized
 by removing the tombstone suppression flag from the merged iterator
 and instead skipping tombstones at higher-level call sites where
 iteration bounds are known.

 Will merge to 'master'.
 cf. <alECc90WZ9RPqMaA@pks.im>
 source: <pull.2166.v3.git.1783679767.gitgitgadget@gmail.com>


* rs/blame-abbrev-marks (2026-07-06) 1 commit
  (merged to 'next' on 2026-07-08 at e4962bd3d5)
 + blame: reserve mark column only if necessary

 The alignment of commit object name abbreviations in 'git blame'
 output has been optimized to reserve a column for marks (caret,
 question mark, or asterisk) only when such marks are actually shown.

 Will merge to 'master'.
 cf. <xmqqzf0397u1.fsf@gitster.g>
 source: <92991b5e-0667-4315-89d5-1514a5499297@web.de>


* jm/t0213-skip-emulated-ancestry-tests (2026-07-06) 1 commit
 - t0213: skip ancestry tests under user-mode emulation

 The 'TRACE2_ANCESTRY' prerequisite in the 't0213' test script has been
 refined to avoid failures under user-mode emulation, by verifying that
 the ancestry collector reports the expected process names rather than
 the emulator binary name.

 Needs review.
 source: <pull.2168.git.1783359242130.gitgitgadget@gmail.com>


* bc/parse-options-exit-0-on-help (2026-07-07) 4 commits
  (merged to 'next' on 2026-07-10 at 775654e447)
 + parse-options: exit 0 on -h
 + rev-parse: have --parseopt callers exit 0 on --help
 + parse-options: add a separate case for help output on error
 + t1517: skip svn tests if svn is not installed

 Option parsing with 'git rev-parse --parseopt' and in most 'git'
 subcommands has been updated to exit with 0 (instead of 129) when the
 help option ('-h' or '--help') is requested directly by the user,
 aligning with standard Unix convention.

 Will merge to 'master'.
 cf. <20260708035930.GB41684@coredump.intra.peff.net>
 source: <20260708001557.3581080-1-sandals@crustytoothpaste.net>


* mg/meson-hook-list-buildfix (2026-07-01) 1 commit
  (merged to 'next' on 2026-07-08 at 10763a0ebc)
 + meson: restore hook-list.h to builtin_sources

 A racy build failure under Meson has been corrected by ensuring that
 the generated header file 'hook-list.h' is built before compiling
 files in 'builtin_sources' that depend on it.

 Will merge to 'master'.
 cf. <akZGJP1kVtjBFN_e@pks.im>
 source: <20260701193928.358825-1-floppym@gentoo.org>


* zy/apply-abandoned-header-fix (2026-07-01) 1 commit
 - apply: avoid leaking abandoned git-header state

 A candidate 'git diff' header parsed by 'git apply' has been isolated
 in a temporary structure, preventing any partially parsed state from
 polluting the main patch structure and causing assertions to trip if
 the header is ultimately rejected.

 Needs review.
 source: <20260702041759.51572-1-zhihao.yao@njit.edu>


* jk/hash-algo-leak-fixes (2026-07-02) 9 commits
  (merged to 'next' on 2026-07-09 at 7db7b74972)
 + hash: add platform-specific discard functions
 + hash: fix memory leak copying sha256 gcrypt handles
 + http: discard hash in dumb-http http_object_request
 + check_stream_oid(): discard hash on read error
 + patch-id: discard hash when done
 + csum-file: provide a function to release checkpoints
 + csum-file: always finalize or discard hash
 + hash: add discard primitive
 + csum-file: drop discard_hashfile()
 (this branch is used by jk/git-hash-cleanups.)

 Various code paths that initialize a cryptographic hash context but
 bail out or finish without calling 'git_hash_final()' have been taught
 to call 'git_hash_discard()' to release allocated resources, fixing
 memory leaks when Git is built with non-default backends like
 'OpenSSL' or 'libgcrypt'.

 Will merge to 'master'.
 cf. <aktIIKuReMxJmDsi@pks.im>
 source: <20260702075234.GA1548258@coredump.intra.peff.net>


* ml/t9811-replace-test-f (2026-07-11) 2 commits
 - t9811: replace 'test -f' and '! test -f' with 'test_path_*'
 - t9811: break long && chains into multiple lines

 The test script 't/t9811-git-p4-label-import.sh' has been
 modernized to use 'test_path_is_file' and 'test_path_is_missing'
 instead of raw 'test -f' and '! test -f' calls.

 Will merge to 'next'?
 cf. <alTHrUEh4_O5ROeu@pks.im>
 source: <20260711160447.99708-1-marcelomlage@usp.br>


* ps/t-fixes-for-git-test-long (2026-07-05) 9 commits
  (merged to 'next' on 2026-07-09 at c5b13248c8)
 + gitlab-ci: enable "GIT_TEST_LONG"
 + gitlab-ci: disable RAM disk on macOS jobs
 + t: use `test_bool_env` to parse GIT_TEST_LONG
 + t7900: clean up large EXPENSIVE repository
 + t7508: skip EXPENSIVE test that is broken without SIZE_T_IS_64BIT
 + t5608: reduce maximum disk usage
 + t4141: fix inefficient use of dd(1)
 + t0021: skip EXPENSIVE test that is broken without SIZE_T_IS_64BIT
 + README: add GitLab CI badge to make it more discoverable

 Various test scripts have been updated to clean up large temporary
 files and repositories, reducing peak disk usage during testing.
 Also, expensive tests have been disabled on platforms that lack
 sufficient resources (like 32-bit platforms and Windows CI runners),
 and the long test suite has been enabled in GitLab CI.

 Will merge to 'master'.
 cf. <20260707043026.GB677056@coredump.intra.peff.net>
 source: <20260706-b4-pks-t-fixes-for-GIT-TEST-LONG-v3-0-4f6c5a37fd1f@pks.im>


* ih/precompose-flex-array (2026-07-04) 1 commit
  (merged to 'next' on 2026-07-09 at 737a87f65e)
 + precompose_utf8: use a flex array for d_name

 The UTF-8 precomposition wrapper on macOS has been updated to use a
 flexible array member to represent the name of a directory entry,
 preventing fortified libc checks from failing when the name is
 reallocated to be larger than 'NAME_MAX' bytes.

 Will merge to 'master'.
 cf. <20260703050800.GA29216@tb-raspi4>
 source: <20260704233724.16928-1-ihar.hrachyshka@gmail.com>


* sn/osxkeychain-rust-universal (2026-07-07) 3 commits
  (merged to 'next' on 2026-07-10 at fe82b5d188)
 + contrib: wire up osxkeychain in contrib/Makefile on macOS
 + Makefile: support universal macOS builds via RUST_TARGETS
 + Makefile: add $(RUST_LIB) prerequisite to osxkeychain

 The build system has been updated to support building universal macOS
 binaries when 'Rust' is enabled, by compiling separate static archives
 for each target triple listed in 'RUST_TARGETS' and combining them
 using the macOS 'lipo' tool.  The 'git-credential-osxkeychain' helper
 has been updated to link against '$(RUST_LIB)' when 'Rust' is enabled.

 Will merge to 'master'.
 cf. <xmqq4ii9teym.fsf@gitster.g>
 source: <pull.2288.v8.git.git.1783480879.gitgitgadget@gmail.com>


* cl/conditional-config-on-worktree-path (2026-07-09) 2 commits
 - config: add "worktree" and "worktree/i" includeIf conditions
 - config: refactor include_by_gitdir() into include_by_path()

 The '[includeIf "condition"]' conditional inclusion facility for
 configuration files has been taught to use the location of the
 worktree in its condition.

 Will merge to 'next'?
 cf. <alTJCTKR9jOWfgbk@pks.im>
 source: <20260710-includeif-worktree-v8-0-04686d8a616c@black-desk.cn>


* kk/commit-reach-find-all-fix (2026-06-29) 2 commits
  (merged to 'next' on 2026-07-10 at 0444c74d81)
 + commit-reach: guard !FIND_ALL early exit with generation ordering check
 + t6600: add test for merge-base early exit with clock skew
 (this branch is used by kk/merge-base-exhaustion.)

 The early-exit optimization in 'paint_down_to_common()' has been
 gated on the queue being generation-ordered, fixing a bug where
 'git merge-base' (without '--all') could return incorrect results
 on repositories with v1 commit graphs and clock skew.

 Will merge to 'master'.
 cf. <xmqqjyr5v1gu.fsf@gitster.g>
 source: <pull.2162.git.1782739162.gitgitgadget@gmail.com>


* bl/t7412-use-test-path-helpers (2026-06-29) 1 commit
 - submodule absorbgitdirs tests: use test_* helper functions

 The test script 't7412' that tests 'git submodule absorbgitdirs' has
 been modernized to use 'test_path_is_file', 'test_path_is_dir', and
 'test_path_is_missing' helper functions instead of raw 'test -[fde]'
 commands.

 Waiting for response(s) to review comment(s).
 cf. <akTKHfKPsP3-Rn31@pks.im>
 source: <20260630020220.1559190-1-bblima@usp.br>


* ps/setup-split-discovery-and-setup (2026-07-07) 16 commits
  (merged to 'next' on 2026-07-10 at 1691a942ab)
 + setup: mark `set_git_work_tree()` as file-local
 + setup: pass worktree to `init_db()`
 + setup: drop redundant configuration of `startup_info->have_repository`
 + setup: make repository discovery self-contained
 + setup: propagate prefix via repository discovery
 + setup: drop static `cwd` variable
 + setup: move prefix into repository
 + setup: embed repository format in discovery
 + setup: introduce explicit repository discovery
 + setup: split up concerns of `setup_git_env_internal()`
 + setup: unify setup of shallow file
 + setup: mark bogus worktree in `apply_repository_format()`
 + setup: rename `check_repository_format_gently()`
 + Merge branch 'jk/repo-info-path-keys' into ps/setup-split-discovery-and-setup
 + Merge branch 'ps/setup-drop-global-state' into ps/setup-split-discovery-and-setup
 + Merge branch 'ps/refs-onbranch-fixes' into ps/setup-split-discovery-and-setup

 The repository discovery and repository configuration phases, which
 were previously intertwined in 'setup.c', have been split.  Repository
 discovery has been updated to populate a 'struct repo_discovery'
 without modifying the repository state, which is then taken by
 repository configuration to initialize the repository, paving the way
 for clean unification of repository configuration.

 Will merge to 'master'.
 cf. <87h5m9om0j.fsf@emacs.iotcl.com>
 source: <20260707-pks-setup-split-discovery-and-setup-v2-0-aab372cd227c@pks.im>


* pw/rebase-drop-notes-with-commit (2026-07-13) 10 commits
 - sequencer: do not record dropped commits as rewritten
 - sequencer: use an enum to represent result of picking a commit
 - sequencer: simplify pick_one_commit()
 - sequencer: remove unnecessary condition in pick_one_commit()
 - sequencer: simplify handing of fixup with conflicts
 - sequencer: remove unnecessary "or" in pick_one_commit()
 - sequencer: never reschedule on failed commit
 - sequencer: be more careful with external merge
 - sequencer: move definition of is_final_fixup()
 - t3400: restore coverage for note copying with apply backend

 The rebase post-rewrite notes-copying logic has been corrected.  When
 a commit is dropped during rebase (e.g., because its changes are
 already upstream), it is no longer recorded as rewritten, preventing
 its notes from being copied to an unrelated commit.

 Needs review.
 cf. <alTxn7MmX3aH_7gp@ugly.lan>
 source: <cover.1783948637.git.phillip.wood@dunelm.org.uk>


* jk/bloom-leak-fixes (2026-06-30) 3 commits
  (merged to 'next' on 2026-07-08 at 3b9a1cda3f)
 + line-log: drop extra copy of range with bloom filters
 + revision: avoid leaking bloom keyvecs with multiple traversals
 + bloom: make bloom-filter slab initialization idempotent

 Various memory leaks in the Bloom-filter code paths that are exposed
 when running tests with the 'GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=1'
 environment variable have been plugged.

 Will merge to 'master'.
 cf. <b641aed4-ad52-477b-b1d8-9d8e470be46f@gmail.com>
 cf. <xmqqo6gqobrt.fsf@gitster.g>
 source: <20260701063538.GA2579765@coredump.intra.peff.net>


* js/ci-dockerized-pid-limit (2026-07-04) 1 commit
  (merged to 'next' on 2026-07-09 at cd80e673a5)
 + ci(dockerized): raise the PID limit for private repositories

 Dockerized CI jobs running in private GitHub repositories have been
 adjusted to use explicit process and file limits, preventing resource
 exhaustion errors on private runners.

 Will merge to 'master'.
 cf. <xmqqh5medmzh.fsf@gitster.g>
 source: <pull.2164.v2.git.1783155124926.gitgitgadget@gmail.com>


* js/coverity-fixes (2026-07-05) 12 commits
  (merged to 'next' on 2026-07-09 at 1823fe297c)
 + mingw: make `exit_process()` own the process handle on all paths
 + fsmonitor: plug token-data leak on early daemon-startup failures
 + reftable/table: release filter on error path
 + imap-send: avoid leaking the IMAP upload buffer
 + worktree: fix resource leaks when branch creation fails
 + submodule: fix cwd leak in `get_superproject_working_tree()`
 + dir: free allocations on parse-error paths in `read_one_dir()`
 + line-log: avoid redundant copy that leaks in process_ranges
 + run-command: avoid `close(-1)` in `start_command()` error paths
 + download_https_uri_to_file(): do not leak fd upon failure
 + loose: avoid closing invalid fd on error path
 + load_one_loose_object_map(): fix resource leak

 Various resource leaks, invalid file descriptor closures, and process
 handle ownership issues flagged by Coverity have been fixed.

 Will merge to 'master'.
 cf. <xmqqa4s238lg.fsf@gitster.g>
 source: <pull.2163.v2.git.1783239870.gitgitgadget@gmail.com>


* tb/repack-geometric-cruft (2026-06-28) 11 commits
 - SQUASH??? bare grep !???
 - repack: support combining '--geometric' with '--cruft'
 - pack-objects: support '--refs-snapshot' with 'follow-reachable'
 - pack-objects: introduce '--stdin-packs=follow-reachable'
 - pack-objects: extract `stdin_packs_add_all_pack_entries()`
 - repack-geometry: drop unused redundant-pack removal
 - repack: delete geometric packs via existing_packs
 - repack: teach MIDX retention about geometric rollups
 - repack: mark geometric progression of packs as retained
 - repack: extract `locate_existing_pack()` helper
 - repack: unconditionally exclude non-kept packs

 'git repack' has been taught to accept '--geometric' and '--cruft'
 together.  When both are given, non-cruft packs are rolled up by the
 geometric repack as usual, while a separate cruft pack is written to
 collect unreachable objects.

 Waiting for response(s) to review comment(s).
 cf. <aj8cOhH6hGVZIFft@nand.local>
 source: <cover.1782500507.git.me@ttaylorr.com>


* jt/receive-pack-use-odb-transactions (2026-07-10) 11 commits
 - builtin/receive-pack: stage incoming objects via ODB transactions
 - builtin/receive-pack: drop redundant tmpdir env
 - odb/transaction: introduce ODB transaction flags
 - odb/transaction: add transaction env interface
 - odb/transaction: propagate commit errors
 - odb/transaction: propagate begin errors
 - object-file: propagate files transaction errors
 - object-file: drop check for inflight transactions
 - object-file: embed transaction flush logic in commit function
 - object-file: rename files transaction fsync function
 - object-file: rename files transaction prepare function

 'git receive-pack' has been refactored to use ODB transaction
 interfaces instead of directly managing 'tmp_objdir' for staging
 incoming objects, bringing it closer to being ODB backend agnostic.

 Will merge to 'next'.
 cf. <alR1P-RGZNmjyiUE@pks.im>
 source: <20260710163722.2962278-1-jltobler@gmail.com>


* ps/odb-drop-whence (2026-07-02) 7 commits
  (merged to 'next' on 2026-07-08 at f43ee51cc3)
 + odb: document object info fields
 + odb: drop `whence` field from object info
 + treewide: convert users of `whence` to the new source field
 + odb: add `source` field to struct object_info_source
 + odb: make backend-specific fields optional
 + packfile: thread odb_source_packed through packed_object_info()
 + Merge branch 'ps/odb-source-packed' into ps/odb-drop-whence
 (this branch is used by ps/odb-for-each-object-filter.)

 The 'whence' field in 'struct object_info' has been removed.  The
 backend-specific object information retrieval has been refactored into
 an opt-in 'struct object_info_source' structure.

 Will merge to 'master'.
 cf. <xmqqv7b0rmt6.fsf@gitster.g>
 source: <20260702-b4-pks-odb-drop-whence-v2-0-b0af7468ad95@pks.im>


* ps/reftable-hardening (2026-07-03) 12 commits
  (merged to 'next' on 2026-07-10 at b8f4dd0ab9)
 + reftable/table: fix OOB read on truncated table
 + reftable/table: fix NULL pointer access when seeking to bogus offsets
 + reftable/block: fix OOB read with bogus restart offset
 + reftable/block: fix use of uninitialized memory when binsearch fails
 + reftable/block: fix OOB read with bogus restart count
 + reftable/block: fix OOB read with bogus block size
 + reftable/block: fix OOB write with bogus inflated log size
 + t/unit-tests: introduce test helper to write reftable blocks
 + reftable/record: don't abort when decoding invalid ref value type
 + reftable/basics: fix OOB read on binary search of empty range
 + oss-fuzz: add fuzzer for parsing reftables
 + meson: support building fuzzers with libFuzzer

 The reftable code has been hardened against corrupted tables by
 fixing out-of-bounds writes, out-of-bounds reads, and abort calls
 during parsing.

 Will merge to 'master'.
 cf. <877bn5obz9.fsf@emacs.iotcl.com>
 source: <20260703-pks-reftable-hardening-v3-0-b87c555b9920@pks.im>


* jc/history-message-prep-fix (2026-06-29) 1 commit
  (merged to 'next' on 2026-07-06 at 00534a21ce)
 + history: streamline message preparation and plug file stream leak

 A write file stream resource leak has been fixed as part of a code
 cleanup.

 Will merge to 'master'.
 cf. <akO1mhi2u2PntLbt@pks.im>
 source: <xmqqmrwdxrat.fsf@gitster.g>


* ty/migrate-excludes-file (2026-07-13) 10 commits
 - repository: adjust the comment of config_values_private_
 - environment: move object_creation_mode into repo_config_values
 - environment: move autorebase into repo_config_values
 - environment: move push_default into repo_config_values
 - environment: migrate apply_default_whitespace and apply_default_ignorewhitespace
 - environment: move askpass_program into repo_config_values
 - environment: move pager_program into repo_config_values
 - environment: move editor_program into repo_config_values
 - environment: move excludes_file into repo_config_values
 - repository: introduce repo_config_values_clear()

 The 'excludes_file' and various other global configuration variables
 (including 'editor_program', 'pager_program', 'askpass_program', and
 'push_default') have been migrated into the per-repository structure.

 Needs review.
 source: <20260714032525.1611141-1-cat@malon.dev>


* dk/meson-enable-use-nsec-build (2026-06-20) 1 commit
 - meson: wire up USE_NSEC build knob

 The 'USE_NSEC' build knob, which enables support for sub-second file
 timestamp resolution, has been wired up to the Meson build system.

 Will discard.
 cf. <45F2C180-1DE1-4371-869B-BF605B64E01A@gmail.com>
 source: <c4c5ade901ff95b0f95939ea818870e4f3d59da1.1781971201.git.ben.knoble+github@gmail.com>


* ps/libgit-in-subdir (2026-07-12) 3 commits
 - Move libgit.a sources into separate "lib/" directory
 - t/helper: prepare "test-example-tap.c" for introduction of "lib/"
 - Merge branch 'ps/odb-source-packed' into ps/libgit-in-subdir

 The source files for 'libgit.a' have been moved into a new 'lib/'
 directory to clean up the top-level directory and clearly separate
 library code.

 Needs review.
 cf. <alR9GDNTbdjWB4dq@szeder.dev>
 source: <20260713-pks-libgit-in-subdir-v4-0-696240876eb1@pks.im>


* ty/migrate-ignorecase (2026-06-19) 2 commits
  (merged to 'next' on 2026-07-12 at 39e9fdb93f)
 + config: use repo_ignore_case() to access core.ignorecase
 + environment: move ignore_case into repo_config_values

 The global configuration variable 'ignore_case' (representing the
 'core.ignorecase' configuration) has been migrated into 'struct
 repo_config_values' to tie it to a specific repository instance.

 Will merge to 'master'.
 cf. <xmqqechaga7p.fsf@gitster.g>
 source: <20260619155152.642760-1-cat@malon.dev>


* mm/line-log-limited-ops (2026-06-27) 7 commits
 - diffcore-pickaxe: scope -G to the -L tracked range
 - diff: support --check with -L line ranges
 - line-log: support diff stat formats with -L
 - diff: extract a line-range diff helper for reuse
 - diff: emit -L hunk headers via xdiff's formatter
 - diff: simplify the line-range filter by classifying removals immediately
 - diff: rename and group the line-range filter for clarity

 The 'git log -L<range>:<path>' command has been taught to limit
 various 'diff' operations, such as '--stat', '--check', and '-G', to
 the specified range and path.

 Needs review.
 source: <pull.2152.v2.git.1782581342.gitgitgadget@gmail.com>


* hn/history-squash (2026-07-10) 5 commits
 - history: re-edit a squash with every message
 - sequencer: share the squash message marker helpers and flags
 - history: add squash subcommand to fold a range
 - history: give commit_tree_ext a message template
 - history: extract helper for a commit's parent tree

 The experimental 'git history' command has been taught a new 'squash'
 subcommand to fold a range of commits into a single commit, with any
 descendants replayed on top.

 Expecting a reroll.
 cf. <CAHwyqnVYQ6Sk=4ot6=5AbUdqxCrwS15xt_+wX3DB1h369CSqsA@mail.gmail.com>
 source: <pull.2337.v8.git.git.1783674396.gitgitgadget@gmail.com>


* ps/refs-writing-subcommands (2026-07-06) 5 commits
  (merged to 'next' on 2026-07-08 at f001147283)
 + builtin/refs: add "rename" subcommand
 + builtin/refs: add "create" subcommand
 + builtin/refs: add "update" subcommand
 + builtin/refs: add "delete" subcommand
 + builtin/refs: drop `the_repository`
 (this branch is used by ps/refs-wo-the-repository.)

 The 'git refs' toolbox has been extended with new 'create', 'delete',
 'update', and 'rename' subcommands to create, delete, update, and
 rename references, respectively.

 Will merge to 'master'.
 source: <20260706-pks-refs-writing-subcommands-v4-0-d51f6ce7f830@pks.im>


* wy/doc-myfirstcontribution-trim-quotes (2026-06-11) 1 commit
  (merged to 'next' on 2026-07-12 at adeaa999b6)
 + MyFirstContribution: mention trimming quoted text in replies

 The contributor guide has been updated to advise new contributors to
 trim irrelevant quoted text when replying to review comments, matching
 the existing advice given to reviewers.

 Will merge to 'master'.
 cf. <xmqqcxxwljue.fsf@gitster.g>
 source: <080402ff0ac8127b654dccea59a1bf643df62a5c.1781186476.git.wy@wyuan.org>


* tb/midx-incremental-custom-base (2026-06-12) 3 commits
 - midx-write: include packs above custom incremental base
 - midx: pass custom '--base' through incremental writes
 - t5334: expose shared `nth_line()` helper

 The 'git multi-pack-index write --incremental' command has been
 corrected to properly honor the '--base' option.  Previously, the
 custom base was ignored by the normal write path; packs from layers
 above the selected base were incorrectly skipped by the pack exclusion
 logic, and reachability closure for bitmaps was broken.

 Needs review.
 source: <cover.1781294771.git.me@ttaylorr.com>


* mm/test-grep-lint (2026-07-05) 6 commits
  (merged to 'next' on 2026-07-10 at 1916c07bf5)
 + t: add greplint to detect bare grep assertions
 + t: convert grep assertions to test_grep
 + t: fix Lexer line count for $() inside double-quoted strings
 + t: extract chainlint's parser into shared module
 + t: fix grep assertions missing file arguments
 + t/README: document test_grep helper

 The test suite has been updated to use the 'test_grep' helper instead
 of bare 'grep' for test assertions, allowing file contents to be
 printed on failure for easier debugging.  A new 'greplint' linter has
 been introduced to detect and prevent new bare 'grep' assertions from
 being added to the test suite.

 Will merge to 'master'.
 cf. <xmqqtsqedxmt.fsf@gitster.g>
 source: <pull.2135.v4.git.1783314119.gitgitgadget@gmail.com>


* td/ref-filter-memoize-contains (2026-06-12) 3 commits
 - commit-reach: die on contains walk errors
 - ref-filter: memoize --contains with generations
 - commit-reach: reject cycles in contains walk

 'git branch --contains' and 'git for-each-ref --contains' have been
 optimized to use the memoized commit traversal previously used only by
 'git tag --contains', significantly speeding up connectivity checks
 across many candidate refs with shared history.

 Needs review.
 cf. <xmqqqzlpulkp.fsf@gitster.g>
 source: <20260612-ref-filter-memoized-contains-v4-0-5ed39fd001dd@gmail.com>


* tc/replay-linearize (2026-07-07) 3 commits
  (merged to 'next' on 2026-07-09 at 371c2e9c3b)
 + replay: offer an option to linearize the commit topology
 + replay: resolve the replay base outside pick_regular_commit()
 + replay: add helper to put entry into replayed_commits

 The 'git replay' command has been taught the '--linearize' option to
 drop merge commits and linearize the replayed history, mimicking 'git
 rebase --no-rebase-merges'.

 Will merge to 'master'?
 cf. <xmqq5x2qz42z.fsf@gitster.g>
 cf. <CABPp-BGzU9KHGF1nipi2HZaa1AiikMKGGaapQzHVH06wO4V1ww@mail.gmail.com>
 source: <20260707-toon-git-replay-drop-merges-v7-0-808ab9b4afa6@iotcl.com>


* ps/cat-file-remote-object-info (2026-07-14) 13 commits
 - cat-file: make remote-object-info allow-list dynamic
 - cat-file: validate remote atoms with an allow-list
 - cat-file: add remote-object-info to batch-command
 - transport: add client support for object-info
 - serve: advertise object-info feature
 - fetch-pack: move fetch initialization
 - connect: make write_fetch_command_and_capabilities() more generic
 - fetch-pack: move write_fetch_command_and_capabilities() to connect.c
 - fetch-pack: drop static advertise_sid variable
 - fetch-pack: fix hash_algo variable type
 - t1006: split test utility functions into new 'lib-cat-file.sh'
 - cat-file: declare loop counter inside for()
 - transport-helper: fix memory leak of helper on disconnect

 The 'remote-object-info' command has been added to 'git cat-file
 --batch-command', allowing clients to request object metadata
 (currently size) from a remote server via protocol v2 without
 downloading the entire object.  Format placeholders are dynamically
 filtered on the client based on server-advertised capabilities,
 returning empty strings for inapplicable or unsupported fields.

 Needs review.
 cf. <xmqq8q7dto8d.fsf@gitster.g>
 source: <20260714-ps-eric-work-rebase-v17-0-afabfc83260e@gmail.com>


* mm/diff-process-hunks (2026-06-14) 6 commits
 - blame: consult diff process for no-hunk detection
 - diff: bypass diff process with --no-ext-diff and in format-patch
 - diff: add long-running diff process via diff.<driver>.process
 - sub-process: separate process lifecycle from hashmap management
 - userdiff: add diff.<driver>.process config
 - xdiff: support external hunks via xpparam_t

 A new 'diff.<driver>.process' configuration has been introduced to
 allow a long-running external process to act as a hunk provider,
 enabling external tools to control which lines Git considers changed
 while leaving all output formatting (word diff, color, blame, etc.) to
 Git's standard pipeline.

 Expecting a reroll for too long, stalled.
 cf. <CAC2Qwm+P=fZOtpfMPeMiSXf3Afk6OLYpTP8Br78_PRA8WNL1Wg@mail.gmail.com>
 source: <pull.2120.v4.git.1781463564.gitgitgadget@gmail.com>


* ty/migrate-trust-executable-bit (2026-06-19) 3 commits
 - environment: move trust_executable_bit into repo_config_values
 - read-cache: move 'ce_mode_from_stat()' to 'read-cache.c'
 - read-cache: remove redundant extern declarations

 The 'trust_executable_bit' (coming from 'core.filemode'
 configuration) has been migrated into 'repo_config_values' to tie it
 to a specific repository instance.

 Needs review.
 cf. <xmqqcxx9ukvw.fsf@gitster.g>
 source: <20260619162105.648495-1-cat@malon.dev>


* ps/history-drop (2026-07-01) 11 commits
  (merged to 'next' on 2026-07-08 at 6fb84708a4)
 + builtin/history: implement "drop" subcommand
 + builtin/history: split handling of ref updates into two phases
 + replay: expose `replay_result_queue_update()`
 + reset: stop assuming that the caller passes in a clean index
 + reset: allow the caller to specify the current HEAD object
 + reset: introduce ability to skip updating HEAD
 + reset: introduce dry-run mode
 + reset: modernize flags passed to `reset_working_tree()`
 + reset: rename `reset_head()`
 + reset: drop `USE_THE_REPOSITORY_VARIABLE`
 + read-cache: split out function to drop unmerged entries to stage 0

 The experimental 'git history' command has been taught a new 'drop'
 subcommand to remove a commit, with its descendants replayed onto its
 parent.

 Will merge to 'master'.
 cf. <xmqq1pdmprbk.fsf@gitster.g>
 cf. <CAP8UFD3OAktVQsLuqBNFH2uhEO31PH8ZF3ZT1ZW8k++XE8YLPw@mail.gmail.com>
 source: <20260701-b4-pks-history-drop-v8-0-19b5cdf1facd@pks.im>


* za/completion-hide-dotfiles (2026-06-20) 2 commits
 - completion: hide dotfiles by default for path completion
 - completion: hide dotfiles for selected path completion

 Path completion for commands like 'git rm' and 'git mv' has been
 updated to hide dotfiles by default unless the user explicitly starts
 the path with a dot, matching standard shell-completion behavior.

 Waiting for response(s) to review comment(s), stalled.
 cf. <xmqqik71t3nr.fsf@gitster.g>
 source: <pull.2311.v3.git.git.1781978156.gitgitgadget@gmail.com>


* ec/commit-fixup-options (2026-05-26) 2 commits
 - commit: allow -c/-C for all kinds of --fixup
 - commit: allow -m/-F for all kinds of --fixup

 Support for '-m', '-F', '-c', or '-C' options to supply a commit log
 message from outside the editor has been added for all 'git commit
 --fixup' variations.

 Needs review.
 source: <cover.1779792311.git.erik@cervined.in>


* kh/doc-replay-config (2026-06-05) 4 commits
 - doc: replay: move “default” to the right-hand side
 - doc: replay: use a nested description list
 - doc: replay: improve config description
 - doc: link to config for git-replay(1)

 Documentation for 'git replay' has been updated to refer to its
 configuration variables.

 Waiting for response(s) to review comment(s).
 cf. <87cxwxofgv.fsf@emacs.iotcl.com>
 source: <V3_CV_doc_replay_config.780@msgid.xyz>


* hn/branch-delete-merged (2026-07-14) 7 commits
 - branch: add --dry-run for --delete-merged
 - branch: add branch.<name>.deleteMerged opt-out
 - branch: add --delete-merged <branch>
 - branch: prepare delete_branches for a bulk caller
 - branch: let delete_branches skip unmerged branches on bulk refusal
 - branch: convert delete_branches() to a flags argument
 - branch: add --forked filter for --list mode

 The 'git branch' command has been taught the '--delete-merged' option
 to remove local branches that are already merged to their tracked
 remote-tracking branches.

 Needs review.
 source: <pull.2285.v19.git.git.1784053493.gitgitgadget@gmail.com>


* hn/checkout-track-fetch (2026-06-24) 2 commits
 - checkout: extend --track with a "fetch" mode to refresh start-point
 - branch: expose helpers for finding the remote owning a tracking ref

 The 'git checkout --track=...' command has been taught to optionally
 fetch the branch from the remote the new branch will work with.

 Waiting for response(s) to review comment(s).
 cf. <CAL71e4MiijEiM26TKJcOYT7L4pfQeMM_F2oT3U3igP-wOZm2Ag@mail.gmail.com>
 source: <pull.2281.v15.git.git.1782338098.gitgitgadget@gmail.com>


* ps/shift-root-in-graph (2026-07-14) 7 commits
 - graph: add --[no-]graph-indent and log.graphIndent
 - graph: move config reading into graph_read_config()
 - graph: wrap cascading commits after 4 columns
 - graph: indent visual root in graph
 - graph: add a 2 commit buffer for lookahead
 - revision: add next_commit_to_show()
 - lib-log-graph: move check_graph function

 'git log --graph' has been modified to visually distinguish parentless
 'root' commits (and commits that become roots due to history
 simplification) by indenting them, preventing them from appearing
 falsely related to unrelated commits rendered immediately above them.

 Needs review.
 source: <20260714-ps-pre-commit-indent-v12-0-d50938e006df@gmail.com>


* kk/merge-base-exhaustion (2026-07-11) 11 commits
 - commit-reach: remove commit-date ordering fallback
 - commit-reach: move min_generation check into paint_queue_get()
 - commit-reach: terminate merge-base walk when one paint side is exhausted
 - commit-reach: introduce struct paint_state with per-side counters
 - t6600: add clock-skew topologies and step counts for edge cases
 - commit-reach: add trace2 instrumentation to paint_down_to_common()
 - t6099, t6600: add side-exhaustion regression tests
 - t6600: add test cases for side-exhaustion edge cases
 - test-lib-functions: improve diagnostic output for trace2 data assertions
 - Documentation/technical: add paint-down-to-common doc
 - Merge branch 'kk/commit-reach-find-all-fix' into kk/merge-base-exhaustion
 (this branch uses kk/commit-reach-find-all-fix.)

 The merge-base computation has been optimized by stopping the walk
 early when one side's exclusive commits in the queue are exhausted,
 yielding significant speedups for queries with one-sided histories.

 Needs review.
 source: <pull.2149.v6.git.1783776466.gitgitgadget@gmail.com>

--------------------------------------------------
[Discarded]

* kk/prio-queue-cascade-sift (2026-07-08) 3 commits
 . prio-queue: use cascade for unfused gets
 . prio-queue: extract sift_up() from prio_queue_put()
 . Merge branch 'kk/prio-queue-get-put-fusion' into kk/prio-queue-cascade-sift

 'prio_queue_get()' has been optimized by using a cascade-down approach
 (promoting the smaller child at each level and sifting up the last
 element from the leaf vacancy), whereby the number of comparisons per
 extract-min operation is halved in the common case.

 Retracted.
 cf. <CAL71e4PRVYfUWc-c+6XHTwtADqrbub9ykbo+rPyramDhJw=Rfg@mail.gmail.com>
 source: <pull.2132.v3.git.1783532989.gitgitgadget@gmail.com>

^ permalink raw reply

* Re: [PATCH GSoC v17 00/13] cat-file: add remote-object-info to batch-command
From: Junio C Hamano @ 2026-07-15  0:58 UTC (permalink / raw)
  To: Pablo Sabater
  Cc: chandrapratap3519, chriscool, eric.peijian, git, jltobler,
	karthik.188, peff, toon
In-Reply-To: <DJYNU7D4A7C8.3Q2Q4DX27RXC0@gmail.com>

"Pablo Sabater" <pabloosabaterr@gmail.com> writes:

> You gave me feedback for v17 10th commit:
>
> https://lore.kernel.org/git/xmqqik6htpv4.fsf@gitster.g/
>
> Should I send a v18 or a new patch on top of 'next'?
>
> The fix is simple and I already have it on my local, I just want to do
> whatever is better.

I had v16 merged (prematurely) to 'next' and then saw v17, so I
reverted the merge, which means 'next' no longer has your topic.

And v17, as a brand new iteration, is not in, and will stay out of,
'next' until we are happy with it.  If you have an updated v18,
please send it as a whole replacement.

Thanks.  How close are we to the finish line, by the way?


^ permalink raw reply

* Re: [PATCH 05/11] last-modified: handle repo_parse_commit() failures
From: Junio C Hamano @ 2026-07-15  1:15 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget; +Cc: git, Johannes Schindelin
In-Reply-To: <f728be4dacb0b9781ef6589a0d2c48009aa31e9e.1784069325.git.gitgitgadget@gmail.com>

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> Skip unparsable commits by checking the return value and
> continuing to the next iteration (or returning early in
> process_parent). This matches the defensive pattern used in other
> revision walkers such as limit_list() and get_revision_internal().
> ...
> @@ -414,12 +415,14 @@ static int last_modified_run(struct last_modified *lm)
>  		 * Otherwise, make sure that 'c' isn't reachable from anything
>  		 * in the '--not' queue.
>  		 */
> -		repo_parse_commit(lm->rev.repo, c);
> +		if (repo_parse_commit(lm->rev.repo, c))
> +			continue;

Shouldn't this be

			goto cleanup;

instead?  'n' pulled out of not_queue may be unparseable and when we
ignore it, don't we still want to clean up the active_paths slab for
commit 'c'?

>  		while ((n = prio_queue_get(&not_queue))) {
>  			struct commit_list *np;
>  
> -			repo_parse_commit(lm->rev.repo, n);
> +			if (repo_parse_commit(lm->rev.repo, n))
> +				continue;
>  
>  			for (np = n->parents; np; np = np->next) {
>  				if (!(np->item->object.flags & PARENT2)) {

^ permalink raw reply

* Re: [PATCH 09/11] bisect: check strbuf_getline_lf return when reading terms
From: Junio C Hamano @ 2026-07-15  1:17 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget; +Cc: git, Johannes Schindelin
In-Reply-To: <17c382fdf46eada79ce03a7604dd7e0454d8bea4.1784069325.git.gitgitgadget@gmail.com>

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> diff --git a/builtin/bisect.c b/builtin/bisect.c
> index 798e28f501..fe66d84382 100644
> --- a/builtin/bisect.c
> +++ b/builtin/bisect.c
> @@ -498,9 +498,15 @@ static int get_terms(struct bisect_terms *terms)
>  	}
>  
>  	free_terms(terms);
> -	strbuf_getline_lf(&str, fp);
> +	if (strbuf_getline_lf(&str, fp) == EOF) {
> +		res = -1;
> +		goto finish;
> +	}
>  	terms->term_bad = strbuf_detach(&str, NULL);
> -	strbuf_getline_lf(&str, fp);
> +	if (strbuf_getline_lf(&str, fp) == EOF) {
> +		res = -1;
> +		goto finish;
> +	}

We want to clean-up terms->term_bad when we fail to read the second
line after reading the first line successfully, no?

>  	terms->term_good = strbuf_detach(&str, NULL);
>  
>  finish:

^ permalink raw reply

* [PATCH v1] repository: move fetch_if_missing into struct repository
From: Tian Yuchen @ 2026-07-15  1:18 UTC (permalink / raw)
  To: git
  Cc: ps, five231003, hariom18599, Tian Yuchen, Christian Couder,
	Ayush Chandekar, Olamide Caleb Bello

The global variable 'fetch_if_missing' controls whether a missing
object check should prompt a lazy fetch from a promisor remote.
In order to continue the libification effort, move it into
'struct repository' and initialize it to 1 by default to keep the
previous behavior.

Subsystems that already pass around a repository pointer, are
updated to read this flag directly from their respective 'repo'
instances. For the rest, we access 'the_repository'.

Note that in builtin/fsck.c and builtin/index-pack.c, when running
related commands with the '-h' parameter, the 'repo' pointer is not
passed in. To prevent null pointer dereferences, we defer
operations on the repo in until after parameter parsing is complete.

Additionally, update the partial clone documentation to reflect
that this is now a per-repository flag.

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>
---
 Documentation/technical/partial-clone.adoc |  2 +-
 builtin/fetch-pack.c                       |  2 +-
 builtin/fsck.c                             |  6 +++---
 builtin/index-pack.c                       |  9 +++++----
 builtin/pack-objects.c                     | 14 +++++++-------
 builtin/prune.c                            |  2 +-
 builtin/rev-list.c                         | 10 +++++-----
 git.c                                      |  2 +-
 midx-write.c                               |  2 +-
 odb.c                                      |  4 +---
 odb.h                                      |  8 --------
 repository.c                               |  1 +
 repository.h                               |  6 ++++++
 revision.c                                 |  2 +-
 setup.c                                    |  2 +-
 15 files changed, 35 insertions(+), 37 deletions(-)

diff --git a/Documentation/technical/partial-clone.adoc b/Documentation/technical/partial-clone.adoc
index e513e391ea..18718a3840 100644
--- a/Documentation/technical/partial-clone.adoc
+++ b/Documentation/technical/partial-clone.adoc
@@ -159,7 +159,7 @@ and prefetch those objects in bulk.
 - `repack` in GC has been updated to not touch promisor packfiles at all,
   and to only repack other objects.
 
-- The global variable "fetch_if_missing" is used to control whether an
+- The per-repository flag "fetch_if_missing" is used to control whether an
   object lookup will attempt to dynamically fetch a missing object or
   report an error.
 +
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index 316badd969..c5edd7b80f 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -67,7 +67,7 @@ int cmd_fetch_pack(int argc,
 	struct packet_reader reader;
 	enum protocol_version version;
 
-	fetch_if_missing = 0;
+	the_repository->fetch_if_missing = 0;
 
 	packet_trace_identity("fetch-pack");
 
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 248f8ff5a0..aa31c69486 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -1017,15 +1017,15 @@ int cmd_fsck(int argc,
 		.ref = NULL
 	};
 
-	/* fsck knows how to handle missing promisor objects */
-	fetch_if_missing = 0;
-
 	errors_found = 0;
 	disable_replace_refs();
 	save_commit_buffer = 0;
 
 	argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
 
+	/* fsck knows how to handle missing promisor objects */
+	repo->fetch_if_missing = 0;
+
 	fsck_options_init(&fsck_walk_options, repo, FSCK_OPTIONS_DEFAULT);
 	fsck_walk_options.walk = mark_object;
 
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 0793dc595c..721d576938 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1881,7 +1881,7 @@ static void repack_local_links(void)
 int cmd_index_pack(int argc,
 		   const char **argv,
 		   const char *prefix,
-		   struct repository *repo UNUSED)
+		   struct repository *repo)
 {
 	int i, fix_thin_pack = 0, verify = 0, stat_only = 0, rev_index;
 	const char *curr_index;
@@ -1898,15 +1898,16 @@ int cmd_index_pack(int argc,
 	int report_end_of_input = 0;
 	int hash_algo = 0;
 
+	show_usage_if_asked(argc, argv, index_pack_usage);
+
 	/*
 	 * index-pack never needs to fetch missing objects except when
 	 * REF_DELTA bases are missing (which are explicitly handled). It only
 	 * accesses the repo to do hash collision checks and to check which
 	 * REF_DELTA bases need to be fetched.
 	 */
-	fetch_if_missing = 0;
-
-	show_usage_if_asked(argc, argv, index_pack_usage);
+	if (repo)
+		repo->fetch_if_missing = 0;
 
 	disable_replace_refs();
 
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 8a1709a1ab..c6536b1f65 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -4059,7 +4059,7 @@ static void add_unreachable_loose_objects(struct rev_info *revs);
 
 static void read_stdin_packs(enum stdin_packs_mode mode, int rev_list_unpacked)
 {
-	int prev_fetch_if_missing = fetch_if_missing;
+	int prev_fetch_if_missing = the_repository->fetch_if_missing;
 	struct rev_info revs;
 
 	/*
@@ -4067,7 +4067,7 @@ static void read_stdin_packs(enum stdin_packs_mode mode, int rev_list_unpacked)
 	 * walk is best-effort though we don't want to perform backfill fetches
 	 * for them.
 	 */
-	fetch_if_missing = 0;
+	the_repository->fetch_if_missing = 0;
 
 	repo_init_revisions(the_repository, &revs, NULL);
 	/*
@@ -4115,7 +4115,7 @@ static void read_stdin_packs(enum stdin_packs_mode mode, int rev_list_unpacked)
 	trace2_data_intmax("pack-objects", the_repository, "stdin_packs_hints",
 			   stdin_packs_hints_nr);
 
-	fetch_if_missing = prev_fetch_if_missing;
+	the_repository->fetch_if_missing = prev_fetch_if_missing;
 }
 
 static void add_cruft_object_entry(const struct object_id *oid, enum object_type type,
@@ -4451,14 +4451,14 @@ static int option_parse_missing_action(const struct option *opt UNUSED,
 
 	if (!strcmp(arg, "allow-any")) {
 		arg_missing_action = MA_ALLOW_ANY;
-		fetch_if_missing = 0;
+		the_repository->fetch_if_missing = 0;
 		fn_show_object = show_object__ma_allow_any;
 		return 0;
 	}
 
 	if (!strcmp(arg, "allow-promisor")) {
 		arg_missing_action = MA_ALLOW_PROMISOR;
-		fetch_if_missing = 0;
+		the_repository->fetch_if_missing = 0;
 		fn_show_object = show_object__ma_allow_promisor;
 		return 0;
 	}
@@ -5247,7 +5247,7 @@ int cmd_pack_objects(int argc,
 				  exclude_promisor_objects_best_effort,
 				  "--exclude-promisor-objects-best-effort");
 	if (exclude_promisor_objects) {
-		fetch_if_missing = 0;
+		the_repository->fetch_if_missing = 0;
 
 		/* --stdin-packs handles promisor objects separately. */
 		if (!stdin_packs) {
@@ -5256,7 +5256,7 @@ int cmd_pack_objects(int argc,
 		}
 	} else if (exclude_promisor_objects_best_effort) {
 		use_internal_rev_list = 1;
-		fetch_if_missing = 0;
+		the_repository->fetch_if_missing = 0;
 		option_parse_missing_action(NULL, "allow-any", 0);
 		/* revs configured below */
 	}
diff --git a/builtin/prune.c b/builtin/prune.c
index 55635a891f..a7e4678d11 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -194,7 +194,7 @@ int cmd_prune(int argc,
 	if (show_progress == -1)
 		show_progress = isatty(2);
 	if (exclude_promisor_objects) {
-		fetch_if_missing = 0;
+		repo->fetch_if_missing = 0;
 		revs.exclude_promisor_objects = 1;
 	}
 
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 8f63003709..a6a0c5559e 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -509,25 +509,25 @@ static inline int parse_missing_action_value(const char *value)
 
 	if (!strcmp(value, "allow-any")) {
 		arg_missing_action = MA_ALLOW_ANY;
-		fetch_if_missing = 0;
+		the_repository->fetch_if_missing = 0;
 		return 1;
 	}
 
 	if (!strcmp(value, "print")) {
 		arg_missing_action = MA_PRINT;
-		fetch_if_missing = 0;
+		the_repository->fetch_if_missing = 0;
 		return 1;
 	}
 
 	if (!strcmp(value, "print-info")) {
 		arg_missing_action = MA_PRINT_INFO;
-		fetch_if_missing = 0;
+		the_repository->fetch_if_missing = 0;
 		return 1;
 	}
 
 	if (!strcmp(value, "allow-promisor")) {
 		arg_missing_action = MA_ALLOW_PROMISOR;
-		fetch_if_missing = 0;
+		the_repository->fetch_if_missing = 0;
 		return 1;
 	}
 
@@ -745,7 +745,7 @@ int cmd_rev_list(int argc,
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 		if (!strcmp(arg, "--exclude-promisor-objects")) {
-			fetch_if_missing = 0;
+			the_repository->fetch_if_missing = 0;
 			revs.exclude_promisor_objects = 1;
 		} else if (skip_prefix(arg, "--missing=", &arg)) {
 			parse_missing_action_value(arg);
diff --git a/git.c b/git.c
index 36f08891ef..315d2e160e 100644
--- a/git.c
+++ b/git.c
@@ -202,7 +202,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
 			if (envchanged)
 				*envchanged = 1;
 		} else if (!strcmp(cmd, "--no-lazy-fetch")) {
-			fetch_if_missing = 0;
+			the_repository->fetch_if_missing = 0;
 			setenv(NO_LAZY_FETCH_ENVIRONMENT, "1", 1);
 			if (envchanged)
 				*envchanged = 1;
diff --git a/midx-write.c b/midx-write.c
index 19e1cd10b7..e7313c9d2c 100644
--- a/midx-write.c
+++ b/midx-write.c
@@ -865,7 +865,7 @@ static void find_commits_for_midx_bitmap(struct commit_stack *commits,
 	 * complain later that we don't have reachability closure (and fail
 	 * appropriately).
 	 */
-	fetch_if_missing = 0;
+	ctx->repo->fetch_if_missing = 0;
 	revs.exclude_promisor_objects = 1;
 
 	if (prepare_revision_walk(&revs))
diff --git a/odb.c b/odb.c
index 965ef68e4e..664256e1a4 100644
--- a/odb.c
+++ b/odb.c
@@ -528,8 +528,6 @@ void disable_obj_read_lock(void)
 	pthread_mutex_destroy(&obj_read_mutex);
 }
 
-int fetch_if_missing = 1;
-
 static int register_all_submodule_sources(struct object_database *odb)
 {
 	int ret = odb->submodule_source_paths.nr;
@@ -595,7 +593,7 @@ static int do_oid_object_info_extended(struct object_database *odb,
 			continue;
 
 		/* Check if it is a missing object */
-		if (fetch_if_missing && repo_has_promisor_remote(odb->repo) &&
+		if (odb->repo->fetch_if_missing && repo_has_promisor_remote(odb->repo) &&
 		    !already_retried &&
 		    !(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) {
 			promisor_remote_get_direct(odb->repo, real, 1);
diff --git a/odb.h b/odb.h
index 0030467a52..1dca583fcb 100644
--- a/odb.h
+++ b/odb.h
@@ -14,14 +14,6 @@ struct repository;
 struct strbuf;
 struct strvec;
 
-/*
- * Set this to 0 to prevent odb_read_object_info_extended() from fetching missing
- * blobs. This has a difference only if extensions.partialClone is set.
- *
- * Its default value is 1.
- */
-extern int fetch_if_missing;
-
 /*
  * Compute the exact path an alternate is at and returns it. In case of
  * error NULL is returned and the human readable error is added to `err`
diff --git a/repository.c b/repository.c
index 187dd471c4..b959f7a028 100644
--- a/repository.c
+++ b/repository.c
@@ -73,6 +73,7 @@ void initialize_repository(struct repository *repo)
 	ALLOC_ARRAY(repo->index, 1);
 	index_state_init(repo->index, repo);
 	repo->check_deprecated_config = true;
+	repo->fetch_if_missing = 1;
 	repo_config_values_init(&repo->config_values_private_);
 
 	/*
diff --git a/repository.h b/repository.h
index 36e2db2633..e8bd6ef0e7 100644
--- a/repository.h
+++ b/repository.h
@@ -169,6 +169,12 @@ struct repository {
 	/* True if commit-graph has been disabled within this process. */
 	int commit_graph_disabled;
 
+	/*
+	 * Controls whether the repository should lazily fetch missing
+	 * objects from promisor remotes. Defaults to 1.
+	 */
+	int fetch_if_missing;
+
 	/*
 	 * Lazily-populated cache mapping hook event names to configured hooks.
 	 * NULL until first hook use.
diff --git a/revision.c b/revision.c
index e91d7e1f11..bb645654c3 100644
--- a/revision.c
+++ b/revision.c
@@ -2714,7 +2714,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 		revs->ignore_missing = 1;
 	} else if (opt && opt->allow_exclude_promisor_objects &&
 		   !strcmp(arg, "--exclude-promisor-objects")) {
-		if (fetch_if_missing)
+		if (revs->repo->fetch_if_missing)
 			BUG("exclude_promisor_objects can only be used when fetch_if_missing is 0");
 		revs->exclude_promisor_objects = 1;
 	} else {
diff --git a/setup.c b/setup.c
index b4652651df..ce2a80ac31 100644
--- a/setup.c
+++ b/setup.c
@@ -1064,7 +1064,7 @@ static void setup_git_env_internal(struct repository *repo,
 		set_alternate_shallow_file(repo, shallow_file, 0);
 
 	if (git_env_bool(NO_LAZY_FETCH_ENVIRONMENT, 0))
-		fetch_if_missing = 0;
+		the_repository->fetch_if_missing = 0;
 }
 
 static void set_git_dir_1(struct repository *repo, const char *path)
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3] show-branch: convert per-branch flags to commit-slab
From: Gatla Vishweshwar Reddy @ 2026-07-15  1:47 UTC (permalink / raw)
  To: git; +Cc: Gatla Vishweshwar Reddy
In-Reply-To: <20260714220042.GC4095533@coredump.intra.peff.net>

show-branch uses commit->object.flags to store per-branch
reachability bits, one bit per branch starting at REV_SHIFT.
The flags word has only a fixed number of available bits, limiting
the number of branches that can be shown simultaneously to MAX_REVS.

Convert the per-branch bits to a dedicated commit-slab using uint64_t
as the element type, initialized with a stride via
init_commit_rev_flags_with_stride(). Keep the UNINTERESTING bit in
object.flags where it belongs, as it is used for revision walking and
does not need to be in the per-branch slab. With UNINTERESTING removed
from the slab, REV_SHIFT becomes 0 and all 64 bits of uint64_t are
available for branch tracking, lifting MAX_REVS from 27 to 64 branches.

Add helper functions get_rev_flags_ptr(), peek_rev_flags_ptr(),
has_any_rev_flags(), or_rev_flag_bit(), test_rev_flag_bit(), and
has_all_rev_flags() to encapsulate per-bit slab access cleanly.
Update all bit operations to use UINT64_C(1) for correct 64-bit shifts.
Initialize and clear the slab in cmd_show_branch().

Signed-off-by: Gatla Vishweshwar Reddy <gatlavishweshwarreddy26@gmail.com>
---

Changes in v3:
- Keep UNINTERESTING in object.flags as suggested by Junio
- Slab stores only per-branch bits with REV_SHIFT=0
- All 64 bits of uint64_t available for branches, MAX_REVS=64
- Fix uint64_t flag in omit_in_dense() (was int)
- Fix indentation in show_merge_base()
- Replace all_mask/all_revs with has_all_rev_flags() helper
- Use UINT64_C(1) for all bit shifts

In response to Junio:
- UNINTERESTING kept in object.flags; slab is per-branch bits only

In response to Jeff King:
- init_commit_rev_flags_with_stride() is used as foundation.
  Current stride=1 gives 64 branches. Dynamic stride for >64
  branches can be added as a follow-up.

 builtin/show-branch.c | 143 ++++++++++++++++++++++++------------------
 1 file changed, 83 insertions(+), 60 deletions(-)

diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index f02831b085..70436007ec 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -34,16 +34,9 @@ static enum git_colorbool showbranch_use_color = GIT_COLOR_UNKNOWN;

 static struct strvec default_args = STRVEC_INIT;

-/*
- * TODO: convert this use of commit->object.flags to commit-slab
- * instead to store a pointer to ref name directly. Then use the same
- * UNINTERESTING definition from revision.h here.
- */
 #define UNINTERESTING	01
-
-#define REV_SHIFT	 2
-#define MAX_REVS	(FLAG_BITS - REV_SHIFT) /* should not exceed bits_per_int - REV_SHIFT */
-
+#define REV_SHIFT	 0
+#define MAX_REVS	(sizeof(uint64_t) * 8)
 #define DEFAULT_REFLOG	4

 static const char *get_color_code(int idx)
@@ -79,11 +72,56 @@ struct commit_name {
 define_commit_slab(commit_name_slab, struct commit_name *);
 static struct commit_name_slab name_slab;

+define_commit_slab(commit_rev_flags, uint64_t);
+static struct commit_rev_flags rev_flags_slab;
+static int flags_stride; /* number of uint64_t words per commit */
+
 static struct commit_name *commit_to_name(struct commit *commit)
 {
 	return *commit_name_slab_at(&name_slab, commit);
 }

+static uint64_t *get_rev_flags_ptr(struct commit *commit)
+{
+	return commit_rev_flags_at(&rev_flags_slab, commit);
+}
+
+static uint64_t *peek_rev_flags_ptr(struct commit *commit)
+{
+	return commit_rev_flags_peek(&rev_flags_slab, commit);
+}
+
+static int has_any_rev_flags(struct commit *commit)
+{
+	uint64_t *f = peek_rev_flags_ptr(commit);
+	int i;
+	if (!f)
+		return 0;
+	for (i = 0; i < flags_stride; i++)
+		if (f[i])
+			return 1;
+	return 0;
+}
+
+static void or_rev_flag_bit(struct commit *commit, int branch)
+{
+	get_rev_flags_ptr(commit)[branch / 64] |= UINT64_C(1) << (branch % 64);
+}
+
+static int test_rev_flag_bit(struct commit *commit, int branch)
+{
+	uint64_t *f = peek_rev_flags_ptr(commit);
+	return f && !!(f[branch / 64] & (UINT64_C(1) << (branch % 64)));
+}
+
+static int has_all_rev_flags(struct commit *commit, int num_rev)
+{
+	int i;
+	for (i = 0; i < num_rev; i++)
+		if (!test_rev_flag_bit(commit, i))
+			return 0;
+	return 1;
+}

 /* Name the commit as nth generation ancestor of head_name;
  * we count only the first-parent relationship for naming purposes.
@@ -215,7 +253,7 @@ static void name_commits(struct commit_list *list,

 static int mark_seen(struct commit *commit, struct commit_list **seen_p)
 {
-	if (!commit->object.flags) {
+	if (!has_any_rev_flags(commit)) {
 		commit_list_insert(commit, seen_p);
 		return 1;
 	}
@@ -226,34 +264,34 @@ static void join_revs(struct prio_queue *queue,
 		      struct commit_list **seen_p,
 		      int num_rev, int extra)
 {
-	int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
-	int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
-
 	while (queue->nr) {
 		struct commit_list *parents;
 		int still_interesting = !!interesting(queue);
 		struct commit *commit = prio_queue_peek(queue);
 		bool get_pending = true;
-		int flags = commit->object.flags & all_mask;

 		if (!still_interesting && extra <= 0)
 			break;

 		mark_seen(commit, seen_p);
-		if ((flags & all_revs) == all_revs)
-			flags |= UNINTERESTING;
+		if (has_all_rev_flags(commit, num_rev))
+			commit->object.flags |= UNINTERESTING;
 		parents = commit->parents;

 		while (parents) {
 			struct commit *p = parents->item;
-			int this_flag = p->object.flags;
 			parents = parents->next;
-			if ((this_flag & flags) == flags)
+			if (has_all_rev_flags(p, num_rev))
 				continue;
 			repo_parse_commit(the_repository, p);
 			if (mark_seen(p, seen_p) && !still_interesting)
 				extra--;
-			p->object.flags |= flags;
+			{
+				int _b;
+				for (_b = 0; _b < num_rev; _b++)
+					if (test_rev_flag_bit(commit, _b))
+						or_rev_flag_bit(p, _b);
+			}
 			if (get_pending)
 				prio_queue_replace(queue, p);
 			else
@@ -263,7 +301,6 @@ static void join_revs(struct prio_queue *queue,
 		if (get_pending)
 			prio_queue_get(queue);
 	}
-
 	/*
 	 * Postprocess to complete well-poisoning.
 	 *
@@ -278,7 +315,7 @@ static void join_revs(struct prio_queue *queue,
 			struct commit *c = s->item;
 			struct commit_list *parents;

-			if (((c->object.flags & all_revs) != all_revs) &&
+			if (!has_all_rev_flags(c, num_rev) &&
 			    !(c->object.flags & UNINTERESTING))
 				continue;

@@ -410,8 +447,8 @@ static int append_ref(const char *refname, const struct object_id *oid,
 				return 0;
 	}
 	if (MAX_REVS <= ref_name_cnt) {
-		warning(Q_("ignoring %s; cannot handle more than %d ref",
-			   "ignoring %s; cannot handle more than %d refs",
+		warning(Q_("ignoring %s; cannot handle more than %zu ref",
+			   "ignoring %s; cannot handle more than %zu refs",
 			   MAX_REVS), refname, MAX_REVS);
 		return 0;
 	}
@@ -511,15 +548,12 @@ static int rev_is_head(const char *head, const char *name)

 static int show_merge_base(const struct commit_list *seen, int num_rev)
 {
-	int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
-	int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
 	int exit_status = 1;

 	for (const struct commit_list *s = seen; s; s = s->next) {
 		struct commit *commit = s->item;
-		int flags = commit->object.flags & all_mask;
-		if (!(flags & UNINTERESTING) &&
-		    ((flags & all_revs) == all_revs)) {
+		if (!(commit->object.flags & UNINTERESTING) &&
+			has_all_rev_flags(commit, num_rev)) {
 			puts(oid_to_hex(&commit->object.oid));
 			exit_status = 0;
 			commit->object.flags |= UNINTERESTING;
@@ -528,17 +562,13 @@ static int show_merge_base(const struct commit_list *seen, int num_rev)
 	return exit_status;
 }

-static int show_independent(struct commit **rev,
-			    int num_rev,
-			    unsigned int *rev_mask)
+static int show_independent(struct commit **rev, int num_rev)
 {
 	int i;

 	for (i = 0; i < num_rev; i++) {
 		struct commit *commit = rev[i];
-		unsigned int flag = rev_mask[i];
-
-		if (commit->object.flags == flag)
+		if (test_rev_flag_bit(commit, i))
 			puts(oid_to_hex(&commit->object.oid));
 		commit->object.flags |= UNINTERESTING;
 	}
@@ -603,13 +633,12 @@ static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
 	 * Otherwise, if it is a merge that is reachable from only one
 	 * tip, it is not that interesting.
 	 */
-	int i, flag, count;
+	int i, count;
 	for (i = 0; i < n; i++)
 		if (rev[i] == commit)
 			return 0;
-	flag = commit->object.flags;
 	for (i = count = 0; i < n; i++) {
-		if (flag & (1u << (i + REV_SHIFT)))
+		if (test_rev_flag_bit(commit, i))
 			count++;
 	}
 	if (count == 1)
@@ -648,10 +677,8 @@ int cmd_show_branch(int ac,
 	char *reflog_msg[MAX_REVS] = {0};
 	struct commit_list *seen = NULL;
 	struct prio_queue queue = { compare_commits_by_commit_date };
-	unsigned int rev_mask[MAX_REVS];
 	int num_rev, i, extra = 0;
 	int all_heads = 0, all_remotes = 0;
-	int all_mask, all_revs;
 	enum rev_sort_order sort_order = REV_SORT_IN_GRAPH_ORDER;
 	char *head;
 	struct object_id head_oid;
@@ -713,7 +740,8 @@ int cmd_show_branch(int ac,
 	const char **args_copy = NULL;
 	int ret;

-	init_commit_name_slab(&name_slab);
+	flags_stride = (MAX_REVS + 63) / 64;
+	init_commit_rev_flags_with_stride(&rev_flags_slab, flags_stride);

 	repo_config(the_repository, git_show_branch_config, NULL);

@@ -779,8 +807,8 @@ int cmd_show_branch(int ac,
 			die(_("--reflog option needs one branch name"));

 		if (MAX_REVS < reflog)
-			die(Q_("only %d entry can be shown at one time.",
-			       "only %d entries can be shown at one time.",
+			die(Q_("only %zu entry can be shown at one time.",
+			       "only %zu entries can be shown at one time.",
 			       MAX_REVS), MAX_REVS);
 		if (!repo_dwim_ref(the_repository, *av, strlen(*av), &oid,
 				   &ref, 0))
@@ -870,11 +898,11 @@ int cmd_show_branch(int ac,

 	for (num_rev = 0; ref_name[num_rev]; num_rev++) {
 		struct object_id revkey;
-		unsigned int flag = 1u << (num_rev + REV_SHIFT);
+		int first_seen;

 		if (MAX_REVS <= num_rev)
-			die(Q_("cannot handle more than %d rev.",
-			       "cannot handle more than %d revs.",
+			die(Q_("cannot handle more than %zu rev.",
+			       "cannot handle more than %zu revs.",
 			       MAX_REVS), MAX_REVS);
 		if (repo_get_oid(the_repository, ref_name[num_rev], &revkey))
 			die(_("'%s' is not a valid ref."), ref_name[num_rev]);
@@ -885,17 +913,15 @@ int cmd_show_branch(int ac,
 		repo_parse_commit(the_repository, commit);
 		mark_seen(commit, &seen);

-		/* rev#0 uses bit REV_SHIFT, rev#1 uses bit REV_SHIFT+1,
-		 * and so on.  REV_SHIFT bits from bit 0 are used for
-		 * internal bookkeeping.
+		/* rev#0 uses bit 0, rev#1 uses bit 1,
+		 * and so on.  All bits are available for branch tracking.
 		 */
-		commit->object.flags |= flag;
-		if (commit->object.flags == flag)
+		first_seen = !has_any_rev_flags(commit);
+		or_rev_flag_bit(commit, num_rev);
+		if (first_seen)
 			prio_queue_put(&queue, commit);
 		rev[num_rev] = commit;
 	}
-	for (i = 0; i < num_rev; i++)
-		rev_mask[i] = rev[i]->object.flags;

 	if (0 <= extra)
 		join_revs(&queue, &seen, num_rev, extra);
@@ -908,7 +934,7 @@ int cmd_show_branch(int ac,
 	}

 	if (independent) {
-		ret = show_independent(rev, num_rev, rev_mask);
+		ret = show_independent(rev, num_rev);
 		goto out;
 	}

@@ -958,13 +984,9 @@ int cmd_show_branch(int ac,
 	if (!sha1_name && !no_name)
 		name_commits(seen, rev, ref_name, num_rev);

-	all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
-	all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
-
 	for (struct commit_list *l = seen; l; l = l->next) {
 		struct commit *commit = l->item;
-		int this_flag = commit->object.flags;
-		int is_merge_point = ((this_flag & all_revs) == all_revs);
+		int is_merge_point = has_all_rev_flags(commit, num_rev);

 		shown_merge_point |= is_merge_point;

@@ -973,14 +995,14 @@ int cmd_show_branch(int ac,
 					  commit->parents->next);
 			if (topics &&
 			    !is_merge_point &&
-			    (this_flag & (1u << REV_SHIFT)))
+			    test_rev_flag_bit(commit, 0))
 				continue;
 			if (!sparse && is_merge &&
 			    omit_in_dense(commit, rev, num_rev))
 				continue;
 			for (i = 0; i < num_rev; i++) {
 				int mark;
-				if (!(this_flag & (1u << (i + REV_SHIFT))))
+				if (!test_rev_flag_bit(commit, i))
 					mark = ' ';
 				else if (is_merge)
 					mark = '-';
@@ -1010,6 +1032,7 @@ int cmd_show_branch(int ac,
 		free(reflog_msg[i]);
 	commit_list_free(seen);
 	clear_prio_queue(&queue);
+	clear_commit_rev_flags(&rev_flags_slab);
 	free(args_copy);
 	free(head);
 	return ret;
--
2.54.0


^ permalink raw reply related

* Re: [PATCH v1] repository: move fetch_if_missing into struct repository
From: Junio C Hamano @ 2026-07-15  3:27 UTC (permalink / raw)
  To: Tian Yuchen
  Cc: git, ps, five231003, hariom18599, Christian Couder,
	Ayush Chandekar, Olamide Caleb Bello
In-Reply-To: <20260715011850.3181131-1-cat@malon.dev>

Tian Yuchen <cat@malon.dev> writes:

> The global variable 'fetch_if_missing' controls whether a missing
> object check should prompt a lazy fetch from a promisor remote.
> In order to continue the libification effort, move it into
> 'struct repository' and initialize it to 1 by default to keep the
> previous behavior.
> ...
> diff --git a/setup.c b/setup.c
> index b4652651df..ce2a80ac31 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -1064,7 +1064,7 @@ static void setup_git_env_internal(struct repository *repo,
>  		set_alternate_shallow_file(repo, shallow_file, 0);
>  
>  	if (git_env_bool(NO_LAZY_FETCH_ENVIRONMENT, 0))
> -		fetch_if_missing = 0;
> +		the_repository->fetch_if_missing = 0;
>  }

Could a caller pass a "repo" that is not the_repository?  In other
words, shouldn't this be

		repo->fetch_if_missing = 0;

instead?

^ permalink raw reply

* Re: [PATCH v4 0/3] environment: migrate 'trust_executable_bit' into 'repo_config_values'
From: Tian Yuchen @ 2026-07-15  3:28 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: git, ps, Christian Couder, Ayush Chandekar, Olamide Caleb Bello
In-Reply-To: <xmqqcxx9ukvw.fsf@gitster.g>

On 6/30/26 04:55, Junio C Hamano wrote:
> Tian Yuchen <cat@malon.dev> writes:
> 
>> The 'core.filemode' (stored as 'trust_executable_bit') configuration
>> act as a core filesystem capability flag.
> 
> This unfortunately hasn't heard any responses since June 19th.  Are
> there remaining issues with it?  Or do people fundamentally have
> objections against this change?  Or things are too busy in general
> that there are more patches than there are folks willing to review
> them?

Seems that no many people are viewing this. Let me send V5 which 
includes a new commit and a few changes.

Hope this helps.

Thanks, yuchen

^ permalink raw reply

* Re: [PATCH v3] show-branch: convert per-branch flags to commit-slab
From: Junio C Hamano @ 2026-07-15  3:34 UTC (permalink / raw)
  To: Gatla Vishweshwar Reddy; +Cc: git
In-Reply-To: <20260715015158.48559-1-gatlavishweshwarreddy26@gmail.com>

Gatla Vishweshwar Reddy <gatlavishweshwarreddy26@gmail.com> writes:

> +static int show_independent(struct commit **rev, int num_rev)
>  {
>  	int i;
>
>  	for (i = 0; i < num_rev; i++) {
>  		struct commit *commit = rev[i];
> -		unsigned int flag = rev_mask[i];
> -
> -		if (commit->object.flags == flag)
> +		if (test_rev_flag_bit(commit, i))
>  			puts(oid_to_hex(&commit->object.oid));
>  		commit->object.flags |= UNINTERESTING;
>  	}

These two perform different actions, do they not?  The original code
insists that the commit is reachable from only one tip (i.e., that
the commit's flag word has only a single bit set, corresponding to
the i-th revision).  This is why the implementation does not use:

		if (commit->object.flags & flag)

By contrast, the updated version merely checks whether the bit for
the i-th revision is set, without verifying that all other bits are
cleared.

Or am I misreading the patch?

Thanks.

^ permalink raw reply

* Re: [PATCH 1/2] git-subtree: Bail out if we find output from Rust rewrite [and 1 more messages]
From: Colin Stagner @ 2026-07-15  3:47 UTC (permalink / raw)
  To: Ian Jackson; +Cc: git, Johannes Schindelin
In-Reply-To: <27216.58259.815175.923629@chiark.greenend.org.uk>

Nothing here impacts the patch under review, so this is a bit OT, but...

On 7/10/26 07:20, Ian Jackson wrote:
> Colin Stagner writes ("Re: [PATCH 1/2] git-subtree: Bail out if we find output from Rust rewrite [and 1 more messages]"):
> 
>> git-subtree.sh doesn't really deal in "upstreams" in the git-branch or
>> git-merge sense.
> 
> I'm using "upstream" in the wider sense; here, when you import a
> depedency you're downstream of it.
>
> I want a term that talks about the logical (even, social) relationship
> between the two projects; and it should be one that makes sense from
> the point of view of the upstream.  Talking about the file position
> within the downstream tree doesn't make sense from the upstream's
> point of view.
It may be useful to differentiate between command documentation like 
git-merge(1) and tutorial documentation like gitworkflows(7).

The man page for `merge` reads like: "So you want to merge THIS into 
THAT? Here's how to do it." The banner-line example is merging a topic 
branch into master, but the "social" aspect of this is not front-and-center.

Other common terms used in merges include "ours" (HEAD) and "theirs" 
(MERGE_HEAD, "branch head," "commit [that is being merged]").

gitworkflows(7) discusses the social relationships of branches, 
including the "merge upwards" workflow. Here is where we find more 
social terms like "upstream" and "downstream:"

     The merge workflow works by copying branches between
     upstream and downstream. Upstream can merge
     contributions into the official history;
     downstream base their work on the official history.

But "upwards" or "upstream" is merely in the direction of increasing 
stability or acceptance. This makes the terms "upstream" and 
"downstream" very broad and inclusive. An upstream branch might be in 
the same repo, a parent repo of a fork, or an entirely different repo. 
The repo might be yours or belong to someone else.

Branches are branches, wherever they are.


> I think the dependency relationship is inherent in git-subtree's usual
> use cases: suppose a project A gets merged with git-subtree into a
> subdirectory S of project B, so that B.git:/S/ is a copy of A.git:/
> 
> Then I think almost invariably, this is because A has B as a
> dependency.  And A has B as an upstream.

"Dependencies" are perhaps a bit beyond Git's usual scope as I 
understand it.

For subtree merges, it is possible that "largely unrelated" minirepos 
are being collected together just to make them a monorepo. I have also 
used subtree merges within a single repo. This is handy to keep a 
subproject isolated on its own branch for reuse elsewhere.

For splits, it's possible that history is split just to meet the needs 
of some other build system. I've observed this in the wild with AUR. 
I've seen multiple AUR packages stored together [1], but they must be 
`subtree split` first with aurpublish [2]. AUR users have been on-list 
before to report trouble with `subtree split` that I inadvertently 
caused [3]. They may be very interested in your rewrite.

In conclusion,

* Documentation is hard!

* Consider focusing "command-level" documentation more on mechanics. Use 
very specific terms like "branch," "(sub)tree," "merge-base," etc.

* Consider using "upstream" and "downstream" in the context of the 
"merging upwards" workflow from gitworkflows(7). It is not necessary for 
these to be in another repo or even a different "project."

These are just my recommendations, and they're not relevant for this 
patch series.


>> I haven't tried it, but I think if --squash is in use, then attempting
>> an unmarked subtree merge will probably die with "unrelated history"
>> warnings.
> 
> I think that's not guaranteed if squash merges and non-squash merges
> are interleaved.

Probably true.


Colin

[1]: https://github.com/christian-heusel/aur

[2]: https://github.com/eli-schwartz/aurpublish

[3]: <755578cb-07e0-4b40-aa90-aacf4d45ccaa@heusel.eu>



^ permalink raw reply

* [PATCH v5 0/4] environment: migrate 'trust_executable_bit' and 'has_symlinks' into 'repo_config_values'
From: Tian Yuchen @ 2026-07-15  3:54 UTC (permalink / raw)
  To: git; +Cc: ps, cirnovskyv, Tian Yuchen
In-Reply-To: <20260619162105.648495-1-cat@malon.dev>

This series moves 'trust_executable_bit' and 'has_symlinks' into
'struct repo_config_values' to tie them to the specific repository
instance they were read from. Eager parsing is maintained because
these two flags are heavily consulted in hot paths.

Note: 'repo_config_values()' still does not support any struct
repository other than the_repository due to how deeply these flags
are accessed. In other words, this series of patches is laying
the groundwork for the eventual elimination of the_repository.

Previous related work:

[PATCH 2/6] config: add trust_executable_bit to global config [1]
[PATCH] Refactor 'trust_executable_bit' to repository-scoped setting [2]
(This previous attempt was unsuccessful because the target location
selected was 'struct repo_settings', which our analysis indicated
was not the optimal choice. For further details, please see: [3])

[PATCH 5/6] config: move has_symlinks [4]

RFC:

 - I wonder if there is a better way to deal with compat/mingw.c in
 commit 4/4. Is it possible not to introduce a fallback variable?

Change since V4:

 - the migration of has_symlinks is back [5], as a commit 4/4;

 - drop the comment for repo_executable_bit();

 - do not always pass the_repository to the getters. Use 'repo' when possible. 

Thanks!

[1] https://lore.kernel.org/git/837b5360b40f992351f489a0ae05fedf49884c6e.1685716420.git.gitgitgadget@gmail.com/
[2] https://lore.kernel.org/git/20260301190017.53539-1-dronarajgyawali@gmail.com/
[3] https://lore.kernel.org/git/xmqq1pht6nyx.fsf@gitster.g/
[4] https://lore.kernel.org/git/a154008619790f7a60f2bba91db7b0fe29e67e1a.1685716420.git.gitgitgadget@gmail.com/
[5] https://lore.kernel.org/git/xmqq7bokebct.fsf@gitster.g/

Tian Yuchen (4):
  read-cache: remove redundant extern declarations
  read-cache: move 'ce_mode_from_stat()' to 'read-cache.c'
  environment: move trust_executable_bit into repo_config_values
  environment: move has_symlinks into repo_config_values

 apply.c        |  4 ++--
 combine-diff.c |  2 +-
 compat/mingw.c |  7 ++++---
 entry.c        |  2 +-
 environment.c  | 28 ++++++++++++++++++++++++----
 environment.h  |  9 +++++++--
 read-cache.c   | 33 ++++++++++++++++++++++++++-------
 read-cache.h   | 16 ++--------------
 8 files changed, 67 insertions(+), 34 deletions(-)

-- 
2.43.0


^ permalink raw reply

* [PATCH v5 1/4] read-cache: remove redundant extern declarations
From: Tian Yuchen @ 2026-07-15  3:54 UTC (permalink / raw)
  To: git
  Cc: ps, cirnovskyv, Tian Yuchen, Christian Couder, Ayush Chandekar,
	Olamide Caleb Bello
In-Reply-To: <20260715035501.48271-1-cat@malon.dev>

The 'read-cache.c' file already includes 'environment.h', which provides
the extern declarations for variables like 'trust_executable_bit' and
'has_symlinks'.

Remove the redundant extern declarations inside 'st_mode_from_ce()' to
clean up the code.

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>
---
 read-cache.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/read-cache.c b/read-cache.c
index 38a04b8de3..c44e4d128f 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -204,8 +204,6 @@ void fill_stat_cache_info(struct index_state *istate, struct cache_entry *ce, st
 
 static unsigned int st_mode_from_ce(const struct cache_entry *ce)
 {
-	extern int trust_executable_bit, has_symlinks;
-
 	switch (ce->ce_mode & S_IFMT) {
 	case S_IFLNK:
 		return has_symlinks ? S_IFLNK : (S_IFREG | 0644);
-- 
2.43.0


^ permalink raw reply related

* [PATCH v5 2/4] read-cache: move 'ce_mode_from_stat()' to 'read-cache.c'
From: Tian Yuchen @ 2026-07-15  3:54 UTC (permalink / raw)
  To: git
  Cc: ps, cirnovskyv, Tian Yuchen, Christian Couder, Ayush Chandekar,
	Olamide Caleb Bello
In-Reply-To: <20260715035501.48271-1-cat@malon.dev>

The ce_mode_from_stat() function is declared as a static inline function
in 'read-cache.h'. As we want to migrate configuration variables, this
helper function will need access to corresponding repository-specific
configuration logic. Move the implementation to 'read-cache.c' to
cleanly encapsulate its dependencies.

Note that the 'extern int trust_executable_bit, has_symlinks;' line is
discarded because it's not necessary when the function lives in
"read-cache.c".

At present, this change has no visible impact, but it is crucial
for our future plans to pass in the repo context. Comment
has been added whilst we are at it.

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>
---
 read-cache.c | 20 ++++++++++++++++++++
 read-cache.h | 16 ++--------------
 2 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/read-cache.c b/read-cache.c
index c44e4d128f..cb4f4878c8 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -202,6 +202,26 @@ void fill_stat_cache_info(struct index_state *istate, struct cache_entry *ce, st
 	}
 }
 
+/*
+ * Determine the appropriate index mode for a file based on its stat()
+ * information and the existing cache entry (if any).
+ *
+ * This function handles degradation for filesystems that lack
+ * symlink support or reliable executable bits.
+ */
+unsigned int ce_mode_from_stat(const struct cache_entry *ce, unsigned int mode)
+{
+	if (!has_symlinks && S_ISREG(mode) &&
+	    ce && S_ISLNK(ce->ce_mode))
+		return ce->ce_mode;
+	if (!trust_executable_bit && S_ISREG(mode)) {
+		if (ce && S_ISREG(ce->ce_mode))
+			return ce->ce_mode;
+		return create_ce_mode(0666);
+	}
+	return create_ce_mode(mode);
+}
+
 static unsigned int st_mode_from_ce(const struct cache_entry *ce)
 {
 	switch (ce->ce_mode & S_IFMT) {
diff --git a/read-cache.h b/read-cache.h
index 043da1f1aa..3c4af2faeb 100644
--- a/read-cache.h
+++ b/read-cache.h
@@ -5,20 +5,8 @@
 #include "object.h"
 #include "pathspec.h"
 
-static inline unsigned int ce_mode_from_stat(const struct cache_entry *ce,
-					     unsigned int mode)
-{
-	extern int trust_executable_bit, has_symlinks;
-	if (!has_symlinks && S_ISREG(mode) &&
-	    ce && S_ISLNK(ce->ce_mode))
-		return ce->ce_mode;
-	if (!trust_executable_bit && S_ISREG(mode)) {
-		if (ce && S_ISREG(ce->ce_mode))
-			return ce->ce_mode;
-		return create_ce_mode(0666);
-	}
-	return create_ce_mode(mode);
-}
+unsigned int ce_mode_from_stat(const struct cache_entry *ce,
+				unsigned int mode);
 
 static inline int ce_to_dtype(const struct cache_entry *ce)
 {
-- 
2.43.0


^ permalink raw reply related

* [PATCH v5 3/4] environment: move trust_executable_bit into repo_config_values
From: Tian Yuchen @ 2026-07-15  3:55 UTC (permalink / raw)
  To: git
  Cc: ps, cirnovskyv, Tian Yuchen, Christian Couder, Ayush Chandekar,
	Olamide Caleb Bello
In-Reply-To: <20260715035501.48271-1-cat@malon.dev>

Move the global 'trust_executable_bit' configuration
into the repository-specific 'repo_config_values'
struct.

To ensure code readability, the getter function
'repo_trust_executable_bit()' has been introduced.
Callers access this configuration by passing in 'repo'
when possible, and explicitly fall back to 'the_repository'
the rest of time.

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 +-
 environment.c | 11 +++++++++--
 environment.h |  4 +++-
 read-cache.c  |  8 ++++----
 4 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/apply.c b/apply.c
index 249248d4f2..47b6ae5904 100644
--- a/apply.c
+++ b/apply.c
@@ -3893,7 +3893,7 @@ static int check_preimage(struct apply_state *state,
 		if (*ce && !(*ce)->ce_mode)
 			BUG("ce_mode == 0 for path '%s'", old_name);
 
-		if (trust_executable_bit || !S_ISREG(st->st_mode))
+		if (repo_trust_executable_bit(state->repo) || !S_ISREG(st->st_mode))
 			st_mode = ce_mode_from_stat(*ce, st->st_mode);
 		else if (*ce)
 			st_mode = (*ce)->ce_mode;
diff --git a/environment.c b/environment.c
index fc3ed8bb1c..75069a884d 100644
--- a/environment.c
+++ b/environment.c
@@ -41,7 +41,6 @@
 static int pack_compression_seen;
 static int zlib_compression_seen;
 
-int trust_executable_bit = 1;
 int trust_ctime = 1;
 int check_stat = 1;
 int has_symlinks = 1;
@@ -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;
+}
+
 int have_git_dir(void)
 {
 	return startup_info->have_repository
@@ -305,7 +311,7 @@ int git_default_core_config(const char *var, const char *value,
 
 	/* This needs a better name */
 	if (!strcmp(var, "core.filemode")) {
-		trust_executable_bit = git_config_bool(var, value);
+		cfg->trust_executable_bit = git_config_bool(var, value);
 		return 0;
 	}
 	if (!strcmp(var, "core.trustctime")) {
@@ -720,5 +726,6 @@ void repo_config_values_init(struct repo_config_values *cfg)
 {
 	cfg->attributes_file = NULL;
 	cfg->apply_sparse_checkout = 0;
+	cfg->trust_executable_bit = 1;
 	cfg->branch_track = BRANCH_TRACK_REMOTE;
 }
diff --git a/environment.h b/environment.h
index 123a71cdc8..72b59fd89c 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 trust_executable_bit;
 
 	/* section "branch" config values */
 	enum branch_track branch_track;
@@ -123,6 +124,8 @@ 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);
 
+int repo_trust_executable_bit(struct repository *repo);
+
 void repo_config_values_init(struct repo_config_values *cfg);
 
 /*
@@ -160,7 +163,6 @@ int is_bare_repository(void);
 extern char *git_work_tree_cfg;
 
 /* Environment bits from configuration mechanism */
-extern int trust_executable_bit;
 extern int trust_ctime;
 extern int check_stat;
 extern int has_symlinks;
diff --git a/read-cache.c b/read-cache.c
index cb4f4878c8..a9c11a3346 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -214,7 +214,7 @@ unsigned int ce_mode_from_stat(const struct cache_entry *ce, unsigned int mode)
 	if (!has_symlinks && S_ISREG(mode) &&
 	    ce && S_ISLNK(ce->ce_mode))
 		return ce->ce_mode;
-	if (!trust_executable_bit && S_ISREG(mode)) {
+	if (!repo_trust_executable_bit(the_repository) && S_ISREG(mode)) {
 		if (ce && S_ISREG(ce->ce_mode))
 			return ce->ce_mode;
 		return create_ce_mode(0666);
@@ -228,7 +228,7 @@ static unsigned int st_mode_from_ce(const struct cache_entry *ce)
 	case S_IFLNK:
 		return has_symlinks ? S_IFLNK : (S_IFREG | 0644);
 	case S_IFREG:
-		return (ce->ce_mode & (trust_executable_bit ? 0755 : 0644)) | S_IFREG;
+		return (ce->ce_mode & (repo_trust_executable_bit(the_repository) ? 0755 : 0644)) | S_IFREG;
 	case S_IFGITLINK:
 		return S_IFDIR | 0755;
 	case S_IFDIR:
@@ -338,7 +338,7 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
 		/* We consider only the owner x bit to be relevant for
 		 * "mode changes"
 		 */
-		if (trust_executable_bit &&
+		if (repo_trust_executable_bit(the_repository) &&
 		    (0100 & (ce->ce_mode ^ st->st_mode)))
 			changed |= MODE_CHANGED;
 		break;
@@ -759,7 +759,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
 		ce->ce_flags |= CE_INTENT_TO_ADD;
 
 
-	if (trust_executable_bit && has_symlinks) {
+	if (repo_trust_executable_bit(istate->repo) && has_symlinks) {
 		ce->ce_mode = create_ce_mode(st_mode);
 	} else {
 		/* If there is an existing entry, pick the mode bits and type
-- 
2.43.0


^ permalink raw reply related


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