* Re: git-history drops signatures
From: Patrick Steinhardt @ 2026-06-01 8:03 UTC (permalink / raw)
To: Alix Brunet; +Cc: git
In-Reply-To: <CAPCeX5a6HxD8pAcE9th8+0zhsa-nabRrJQpjKXJrg02zc6EAOw@mail.gmail.com>
Hi Alix,
On Sat, May 30, 2026 at 12:44:25PM +0200, Alix Brunet wrote:
> Hey team ;
>
> I noticed `git history` drops signatures,
> Even though `git rebase` can keep / re-sign commits (`-S`)
>
> Will this ever be implemented?
right now it does drop signatures indeed, but I agree that this is
something we should eventually implement. I didn't have the intent to
work on this soon though as I still have a couple of other features for
git-history(1) that I'd like to prioritize.
All to say: if anyone cares for this feature and has the capacity, then
please feel free to have a go at it :) Otherwise it'll probably take a
while.
Thanks!
Patrick
^ permalink raw reply
* [PATCH 2/2] builtin/init-db: deprecate alias for git-init(1)
From: Patrick Steinhardt @ 2026-06-01 7:56 UTC (permalink / raw)
To: git
In-Reply-To: <20260601-pks-deprecate-git-init-db-v1-0-ea3e6eebe674@pks.im>
The git-init-db(1) command was initially only initializing the object
database of a Git repository. This has changed over time so that the
command also initializes all the other data structures, which is why we
have eventually introduced git-init(1) as a more aptly named replacement
for it.
This has all happened in 2007 already, and with 5c94f87e6b (use 'init'
instead of 'init-db' for shipped docs and tools, 2007-01-12) we have
also adapted all user-facing documentation to mention the replacement.
It is thus safe to assume that (almost) nobody uses git-init-db(1)
nowadays anymore.
Deprecate the command in favor of git-init(1) and wire up the removal
when compiling Git with breaking changes enabled.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
Documentation/BreakingChanges.adoc | 3 +++
Documentation/Makefile | 1 +
Documentation/git-init-db.adoc | 5 +++++
Documentation/meson.build | 2 +-
Makefile | 2 +-
git.c | 2 ++
t/t5502-quickfetch.sh | 4 ++--
t/t5503-tagfollow.sh | 2 +-
8 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/Documentation/BreakingChanges.adoc b/Documentation/BreakingChanges.adoc
index 73bb939359..89b7482f54 100644
--- a/Documentation/BreakingChanges.adoc
+++ b/Documentation/BreakingChanges.adoc
@@ -300,6 +300,9 @@ references.
+
These features will be removed.
+* The git-init-db(1) command is an alias for its modern drop-in replacement
+ git-init(1). The alias will be removed.
+
* Support for "--stdin" option in the "name-rev" command was
deprecated (and hidden from the documentation) in the Git 2.40
timeframe, in preference to its synonym "--annotate-stdin". Git 3.0
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 2699f0b24a..3769856b58 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -541,6 +541,7 @@ lint-docs-meson:
sort >tmp-meson-diff/meson.adoc && \
ls git*.adoc scalar.adoc | \
grep -v -e git-bisect-lk2009.adoc \
+ -e git-init-db.adoc \
-e git-pack-redundant.adoc \
-e git-tools.adoc \
-e git-whatchanged.adoc \
diff --git a/Documentation/git-init-db.adoc b/Documentation/git-init-db.adoc
index 18bf1a3c8c..9802fc9f3d 100644
--- a/Documentation/git-init-db.adoc
+++ b/Documentation/git-init-db.adoc
@@ -11,6 +11,11 @@ SYNOPSIS
[verse]
'git init-db' [-q | --quiet] [--bare] [--template=<template-directory>] [--separate-git-dir <git-dir>] [--shared[=<permissions>]]
+WARNING
+-------
+
+`git init-db` has been deprecated in favor of `git init`, which is a drop-in
+replacement for `git init-db`.
DESCRIPTION
-----------
diff --git a/Documentation/meson.build b/Documentation/meson.build
index f4854f802d..0f127d752d 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -72,7 +72,6 @@ manpages = {
'git-http-push.adoc' : 1,
'git-imap-send.adoc' : 1,
'git-index-pack.adoc' : 1,
- 'git-init-db.adoc' : 1,
'git-init.adoc' : 1,
'git-instaweb.adoc' : 1,
'git-interpret-trailers.adoc' : 1,
@@ -212,6 +211,7 @@ manpages = {
}
manpages_breaking_changes = {
+ 'git-init-db.adoc' : 1,
'git-pack-redundant.adoc' : 1,
'git-whatchanged.adoc' : 1,
}
diff --git a/Makefile b/Makefile
index b03f74ee8c..4420231753 100644
--- a/Makefile
+++ b/Makefile
@@ -894,7 +894,6 @@ BUILT_INS += git-cherry-pick$X
BUILT_INS += git-format-patch$X
BUILT_INS += git-format-rev$X
BUILT_INS += git-fsck-objects$X
-BUILT_INS += git-init-db$X
BUILT_INS += git-maintenance$X
BUILT_INS += git-merge-subtree$X
BUILT_INS += git-restore$X
@@ -904,6 +903,7 @@ BUILT_INS += git-status$X
BUILT_INS += git-switch$X
BUILT_INS += git-version$X
ifndef WITH_BREAKING_CHANGES
+BUILT_INS += git-init-db$X
BUILT_INS += git-whatchanged$X
endif
diff --git a/git.c b/git.c
index a72394b599..6bf6a60360 100644
--- a/git.c
+++ b/git.c
@@ -591,7 +591,9 @@ static struct cmd_struct commands[] = {
{ "hook", cmd_hook, RUN_SETUP_GENTLY },
{ "index-pack", cmd_index_pack, RUN_SETUP_GENTLY | NO_PARSEOPT },
{ "init", cmd_init },
+#ifndef WITH_BREAKING_CHANGES
{ "init-db", cmd_init },
+#endif
{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY },
{ "last-modified", cmd_last_modified, RUN_SETUP },
{ "log", cmd_log, RUN_SETUP },
diff --git a/t/t5502-quickfetch.sh b/t/t5502-quickfetch.sh
index b160f8b7fb..a2b62f551a 100755
--- a/t/t5502-quickfetch.sh
+++ b/t/t5502-quickfetch.sh
@@ -25,7 +25,7 @@ test_expect_success 'clone without alternate' '
(
mkdir cloned &&
cd cloned &&
- git init-db &&
+ git init &&
git remote add -f origin ..
) &&
cnt=$( (
@@ -94,7 +94,7 @@ test_expect_success 'quickfetch should not copy from alternate' '
(
mkdir quickclone &&
cd quickclone &&
- git init-db &&
+ git init &&
(cd ../.git/objects && pwd) >.git/objects/info/alternates &&
git remote add origin .. &&
git fetch -k -k
diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh
index febe441041..31ec352c5c 100755
--- a/t/t5503-tagfollow.sh
+++ b/t/t5503-tagfollow.sh
@@ -32,7 +32,7 @@ test_expect_success setup '
(
mkdir cloned &&
cd cloned &&
- git init-db &&
+ git init &&
git remote add -f origin ..
) &&
--
2.54.0.926.g75ba10bac6.dirty
^ permalink raw reply related
* [PATCH 1/2] builtin/init-db: rename to "builtin/init.c"
From: Patrick Steinhardt @ 2026-06-01 7:55 UTC (permalink / raw)
To: git
In-Reply-To: <20260601-pks-deprecate-git-init-db-v1-0-ea3e6eebe674@pks.im>
Rename "builtin/init-db.c" to "builtin/init.c" to match the modern
git-init(1) command name instead of its ancient alias git-init-db(1).
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
Makefile | 4 ++--
builtin.h | 2 +-
builtin/{init-db.c => init.c} | 8 ++++----
git.c | 4 ++--
meson.build | 2 +-
5 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/Makefile b/Makefile
index b31ecb0756..b03f74ee8c 100644
--- a/Makefile
+++ b/Makefile
@@ -894,7 +894,7 @@ BUILT_INS += git-cherry-pick$X
BUILT_INS += git-format-patch$X
BUILT_INS += git-format-rev$X
BUILT_INS += git-fsck-objects$X
-BUILT_INS += git-init$X
+BUILT_INS += git-init-db$X
BUILT_INS += git-maintenance$X
BUILT_INS += git-merge-subtree$X
BUILT_INS += git-restore$X
@@ -1428,7 +1428,7 @@ BUILTIN_OBJS += builtin/help.o
BUILTIN_OBJS += builtin/history.o
BUILTIN_OBJS += builtin/hook.o
BUILTIN_OBJS += builtin/index-pack.o
-BUILTIN_OBJS += builtin/init-db.o
+BUILTIN_OBJS += builtin/init.o
BUILTIN_OBJS += builtin/interpret-trailers.o
BUILTIN_OBJS += builtin/last-modified.o
BUILTIN_OBJS += builtin/log.o
diff --git a/builtin.h b/builtin.h
index 4e47a4ebd3..bd072aa0e4 100644
--- a/builtin.h
+++ b/builtin.h
@@ -200,7 +200,7 @@ int cmd_help(int argc, const char **argv, const char *prefix, struct repository
int cmd_history(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_hook(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_index_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
-int cmd_init_db(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_init(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_interpret_trailers(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_last_modified(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_log_reflog(int argc, const char **argv, const char *prefix, struct repository *repo);
diff --git a/builtin/init-db.c b/builtin/init.c
similarity index 98%
rename from builtin/init-db.c
rename to builtin/init.c
index c55517ad94..9184f2fc2c 100644
--- a/builtin/init-db.c
+++ b/builtin/init.c
@@ -69,10 +69,10 @@ static const char *const init_db_usage[] = {
* On the other hand, it might just make lookup slower and messier. You
* be the judge. The default case is to have one DB per managed directory.
*/
-int cmd_init_db(int argc,
- const char **argv,
- const char *prefix,
- struct repository *repo UNUSED)
+int cmd_init(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
char *git_dir;
const char *real_git_dir = NULL;
diff --git a/git.c b/git.c
index 36f08891ef..a72394b599 100644
--- a/git.c
+++ b/git.c
@@ -590,8 +590,8 @@ static struct cmd_struct commands[] = {
{ "history", cmd_history, RUN_SETUP },
{ "hook", cmd_hook, RUN_SETUP_GENTLY },
{ "index-pack", cmd_index_pack, RUN_SETUP_GENTLY | NO_PARSEOPT },
- { "init", cmd_init_db },
- { "init-db", cmd_init_db },
+ { "init", cmd_init },
+ { "init-db", cmd_init },
{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY },
{ "last-modified", cmd_last_modified, RUN_SETUP },
{ "log", cmd_log, RUN_SETUP },
diff --git a/meson.build b/meson.build
index 064fe2e2f1..682e46e7eb 100644
--- a/meson.build
+++ b/meson.build
@@ -634,7 +634,7 @@ builtin_sources = [
'builtin/history.c',
'builtin/hook.c',
'builtin/index-pack.c',
- 'builtin/init-db.c',
+ 'builtin/init.c',
'builtin/interpret-trailers.c',
'builtin/last-modified.c',
'builtin/log.c',
--
2.54.0.926.g75ba10bac6.dirty
^ permalink raw reply related
* [PATCH 0/2] Deprecate git-init-db(1) alias
From: Patrick Steinhardt @ 2026-06-01 7:55 UTC (permalink / raw)
To: git
Hi,
this small patch series deprecates the git-init-db(1) alias in favor of
git-init(1).
Patrick
---
Patrick Steinhardt (2):
builtin/init-db: rename to "builtin/init.c"
builtin/init-db: deprecate alias for git-init(1)
Documentation/BreakingChanges.adoc | 3 +++
Documentation/Makefile | 1 +
Documentation/git-init-db.adoc | 5 +++++
Documentation/meson.build | 2 +-
Makefile | 4 ++--
builtin.h | 2 +-
builtin/{init-db.c => init.c} | 8 ++++----
git.c | 6 ++++--
meson.build | 2 +-
t/t5502-quickfetch.sh | 4 ++--
t/t5503-tagfollow.sh | 2 +-
11 files changed, 25 insertions(+), 14 deletions(-)
---
base-commit: 1666c1265231b0bc5f613fbbf3f0a9896cdef76e
change-id: 20260601-pks-deprecate-git-init-db-c0e8d7f8b94e
^ permalink raw reply
* Re: [PATCH v2 0/2] commit: remove deprecated functions
From: Junio C Hamano @ 2026-06-01 7:14 UTC (permalink / raw)
To: Jeff King
Cc: kristofferhaugsbakk, Kristoffer Haugsbakk, Patrick Steinhardt,
git
In-Reply-To: <20260529083716.GE1106035@coredump.intra.peff.net>
Jeff King <peff@peff.net> writes:
> On Thu, May 28, 2026 at 09:00:09AM +0200, kristofferhaugsbakk@fastmail.com wrote:
>
>> Topic summary: Remove deprecated comments that were slated for removal
>> after Git 2.53.0.
>
> This looks obviously correct to me, but the whole topic made me wonder:
> was it worth retaining the old names and deprecating them, versus just
> removing them back then?
>
> Topics in flight would have needed an update then, but they did
> eventually anyway. So it feels like the total amount of work done is
> larger, compared to just fixing them as the topics were merged. Either
> way the compiler tells us, and the adjustments themselves are small.
Your alternative approach will depend on the integrator doing all
the fixups at the merge time.
The amount of effort required by the entire community as a whole may
have been larger, but the way the rename was carried out did spread
them thinner.
Admittedly, with help from rerere and merge-fix mechanism, such a
"fixup at the merge time" typically needs to be done only once per
the other conflicting topic in flight, but still, when constructing
a workflow, I try to avoid having to depend on the single bottleneck
for a task that does not need to be performed by the single
bottleneck, especially when the single bottleneck has other tasks
that can only be done by the single bottleneck.
> Not a huge deal either way, but just pondering for future such
> situations.
>
> -Peff
^ permalink raw reply
* Re: [PATCH] sub-process: use gentle handshake to avoid die() on startup failure
From: Junio C Hamano @ 2026-06-01 6:43 UTC (permalink / raw)
To: Michael Montalbo via GitGitGadget; +Cc: git, Michael Montalbo
In-Reply-To: <pull.2133.git.1780287309846.gitgitgadget@gmail.com>
"Michael Montalbo via GitGitGadget" <gitgitgadget@gmail.com> writes:
> diff --git a/sub-process.c b/sub-process.c
> index 83bf0a0e82..22c68bd10d 100644
> --- a/sub-process.c
> +++ b/sub-process.c
> @@ -132,18 +132,19 @@ static int handshake_version(struct child_process *process,
> if (packet_flush_gently(process->in))
> return error("Could not write flush packet");
>
> - if (!(line = packet_read_line(process->out, NULL)) ||
> + if (packet_read_line_gently(process->out, NULL, &line) <= 0 ||
> !skip_prefix(line, welcome_prefix, &p) ||
> strcmp(p, "-server"))
> return error("Unexpected line '%s', expected %s-server",
> line ? line : "<flush packet>", welcome_prefix);
If `packet_read_line_gently()` returns `< 0` (due to an EOF or read
error), `line` will be `NULL`. The error message printed will be:
`Unexpected line '<flush packet>', expected filter-server`
This is misleading when the remote process didn't send a flush
packet; it hung up or crashed.
> - if (!(line = packet_read_line(process->out, NULL)) ||
> + if (packet_read_line_gently(process->out, NULL, &line) <= 0 ||
> !skip_prefix(line, "version=", &p) ||
> strtol_i(p, 10, chosen_version))
> return error("Unexpected line '%s', expected version",
> line ? line : "<flush packet>");
Ditto.
> - if ((line = packet_read_line(process->out, NULL)))
> - return error("Unexpected line '%s', expected flush", line);
> + if (packet_read_line_gently(process->out, NULL, &line) < 0 || line)
> + return error("Unexpected line '%s', expected flush",
> + line ? line : "<read error>");
We catch error return (< 0) or a line with payload (!!line) and
report an error here, because we want to see <flush> here. OK.
> @@ -171,7 +172,7 @@ static int handshake_capabilities(struct child_process *process,
> if (packet_flush_gently(process->in))
> return error("Could not write flush packet");
>
> - while ((line = packet_read_line(process->out, NULL))) {
> + while (packet_read_line_gently(process->out, NULL, &line) > 0) {
> const char *p;
> if (!skip_prefix(line, "capability=", &p))
> continue;
While this correctly stops the loop if packet_read_line_gently()
returns a non-positive value, doesn't it introduce a subtle bug?
`packet_read_line_gently()` returns:
- `> 0` for a normal line (which keeps the loop running).
- `0` for a flush packet (which we expect as the normal terminator
of the capabilities list, stopping the loop).
- `< 0` for an EOF or read error (which also stops the loop).
In the original code, an EOF or read error would have caused
`packet_read_line()` to call `die()`, aborting the process.
With the new code, if the child process dies or closes its pipe
during the capabilities handshake, the loop will terminate, and the
function will return `0` (success). The parent process will proceed
as if the capabilities were successfully negotiated. Any further
communication with the child process would fail so the damage may
not be huge, but somebody must check if the loop terminated because
of a flush packet, or an error.
while (1) {
const char *p;
int len = packet_read_line_gently(process->out, NULL, &line);
if (len < 0)
return error(_("subprocess `%s` failed to give capabilities"),
process->args.v[0]);
if (!skip_prefix(line, "capability=", &p))
continue;
...
or something, perhaps?
^ permalink raw reply
* Re: [PATCH] prio-queue: use cascade-down sift for faster extract-min
From: Kristofer Karlsson @ 2026-06-01 6:21 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Kristofer Karlsson via GitGitGadget, git
In-Reply-To: <xmqq5x42aipu.fsf@gitster.g>
Thanks for the quick and very valid feedback! I already started
investigating - I think I was too quick (and wrong) when I reasoned
about the replace operation.I will rework it a bit and come back with
a patch version 2 soon that ensures that neither get and replace have
regressed in any way.
- Kristofer
On Mon, 1 Jun 2026 at 08:16, Junio C Hamano <gitster@pobox.com> wrote:
>
> "Kristofer Karlsson via GitGitGadget" <gitgitgadget@gmail.com>
> writes:
>
> > diff --git a/prio-queue.c b/prio-queue.c
> > index 9748528ce6..18005c43c4 100644
> > --- a/prio-queue.c
> > +++ b/prio-queue.c
> > @@ -62,17 +62,21 @@ static void sift_down_root(struct prio_queue *queue)
> > {
> > size_t ix, child;
> >
> > - /* Push down the one at the root */
> > - for (ix = 0; ix * 2 + 1 < queue->nr; ix = child) {
> > - child = ix * 2 + 1; /* left */
> > + for (ix = 0; (child = ix * 2 + 1) < queue->nr; ix = child) {
> > if (child + 1 < queue->nr &&
> > compare(queue, child, child + 1) >= 0)
> > child++; /* use right child */
> > + queue->array[ix] = queue->array[child];
> > + }
> >
> > - if (compare(queue, ix, child) <= 0)
> > + /* Place queue->array[queue->nr] (left by caller) and sift up. */
> > + queue->array[ix] = queue->array[queue->nr];
>
> Here we always sift/bubble up the last element.
>
> I am wondering if it makes sense to teach sift_down_root to take an
> extra argument, "struct prio_queue_entry entry" (passed by value)
> and sift/bubble it up, not always queue->array[queue->nr], and ...
>
> > + while (ix) {
> > + size_t parent = (ix - 1) / 2;
> > + if (compare(queue, parent, ix) <= 0)
> > break;
> > -
> > - swap(queue, child, ix);
> > + swap(queue, parent, ix);
> > + ix = parent;
> > }
> > }
> >
> > @@ -89,7 +93,6 @@ void *prio_queue_get(struct prio_queue *queue)
> > if (!--queue->nr)
> > return result;
> >
> > - queue->array[0] = queue->array[queue->nr];
> > sift_down_root(queue);
> > return result;
> > }
> > @@ -111,8 +114,7 @@ void prio_queue_replace(struct prio_queue *queue, void *thing)
> > queue->array[queue->nr - 1].ctr = queue->insertion_ctr++;
> > queue->array[queue->nr - 1].data = thing;
> > } else {
> > - queue->array[0].ctr = queue->insertion_ctr++;
> > - queue->array[0].data = thing;
> > - sift_down_root(queue);
> > + prio_queue_get(queue);
> > + prio_queue_put(queue, thing);
>
> ... update this part in the else clause to do something like
>
> struct prio_queue_entry entry;
> entry.ctr = queue->insertion_ctr++;
> entry.data = thing;
> sift_down_root(queue, entry);
>
> to retain the optimization? It would perform a single cascade-down
> sift, followed by a single sift-up, so it would save a comparison, a
> copy, and a swap in the worset case compared to the get+put sequence?
>
> Of course, the original sift_down_root() caller (i.e. prio_queue_get())
> needs to pass queue->array[queue->nr] as the second parameter to match.
>
> > }
> > }
> >
> > base-commit: c69baaf57ba26cf117c2b6793802877f19738b0d
^ permalink raw reply
* Re: [PATCH] prio-queue: use cascade-down sift for faster extract-min
From: Junio C Hamano @ 2026-06-01 6:16 UTC (permalink / raw)
To: Kristofer Karlsson via GitGitGadget; +Cc: git, Kristofer Karlsson
In-Reply-To: <pull.2132.git.1780250236304.gitgitgadget@gmail.com>
"Kristofer Karlsson via GitGitGadget" <gitgitgadget@gmail.com>
writes:
> diff --git a/prio-queue.c b/prio-queue.c
> index 9748528ce6..18005c43c4 100644
> --- a/prio-queue.c
> +++ b/prio-queue.c
> @@ -62,17 +62,21 @@ static void sift_down_root(struct prio_queue *queue)
> {
> size_t ix, child;
>
> - /* Push down the one at the root */
> - for (ix = 0; ix * 2 + 1 < queue->nr; ix = child) {
> - child = ix * 2 + 1; /* left */
> + for (ix = 0; (child = ix * 2 + 1) < queue->nr; ix = child) {
> if (child + 1 < queue->nr &&
> compare(queue, child, child + 1) >= 0)
> child++; /* use right child */
> + queue->array[ix] = queue->array[child];
> + }
>
> - if (compare(queue, ix, child) <= 0)
> + /* Place queue->array[queue->nr] (left by caller) and sift up. */
> + queue->array[ix] = queue->array[queue->nr];
Here we always sift/bubble up the last element.
I am wondering if it makes sense to teach sift_down_root to take an
extra argument, "struct prio_queue_entry entry" (passed by value)
and sift/bubble it up, not always queue->array[queue->nr], and ...
> + while (ix) {
> + size_t parent = (ix - 1) / 2;
> + if (compare(queue, parent, ix) <= 0)
> break;
> -
> - swap(queue, child, ix);
> + swap(queue, parent, ix);
> + ix = parent;
> }
> }
>
> @@ -89,7 +93,6 @@ void *prio_queue_get(struct prio_queue *queue)
> if (!--queue->nr)
> return result;
>
> - queue->array[0] = queue->array[queue->nr];
> sift_down_root(queue);
> return result;
> }
> @@ -111,8 +114,7 @@ void prio_queue_replace(struct prio_queue *queue, void *thing)
> queue->array[queue->nr - 1].ctr = queue->insertion_ctr++;
> queue->array[queue->nr - 1].data = thing;
> } else {
> - queue->array[0].ctr = queue->insertion_ctr++;
> - queue->array[0].data = thing;
> - sift_down_root(queue);
> + prio_queue_get(queue);
> + prio_queue_put(queue, thing);
... update this part in the else clause to do something like
struct prio_queue_entry entry;
entry.ctr = queue->insertion_ctr++;
entry.data = thing;
sift_down_root(queue, entry);
to retain the optimization? It would perform a single cascade-down
sift, followed by a single sift-up, so it would save a comparison, a
copy, and a swap in the worset case compared to the get+put sequence?
Of course, the original sift_down_root() caller (i.e. prio_queue_get())
needs to pass queue->array[queue->nr] as the second parameter to match.
> }
> }
>
> base-commit: c69baaf57ba26cf117c2b6793802877f19738b0d
^ permalink raw reply
* Mirror repositories for submodules
From: Benson Muite @ 2026-06-01 6:11 UTC (permalink / raw)
To: git
Hi,
Would a contribution to add mirror repositories as alternate submodule
sources be considered for inclusion? Some projects have mirror
repositories on other hosting services, and may have bandwidth limits on
their primary hosting service. Being able to indicate mirror
repositories for where to check for updates and sources for submodules
when doing `git clone --recurse-submodules https://my.repo ` or `git
submodule update --init --recursive` would be helpful when there is a
timeout.
Regards,
Benson
^ permalink raw reply
* Re: [PATCH v2 0/2] commit: remove deprecated functions
From: Patrick Steinhardt @ 2026-06-01 5:58 UTC (permalink / raw)
To: Jeff King; +Cc: kristofferhaugsbakk, Junio C Hamano, Kristoffer Haugsbakk, git
In-Reply-To: <20260529083716.GE1106035@coredump.intra.peff.net>
On Fri, May 29, 2026 at 04:37:16AM -0400, Jeff King wrote:
> On Thu, May 28, 2026 at 09:00:09AM +0200, kristofferhaugsbakk@fastmail.com wrote:
>
> > Topic summary: Remove deprecated comments that were slated for removal
> > after Git 2.53.0.
>
> This looks obviously correct to me, but the whole topic made me wonder:
> was it worth retaining the old names and deprecating them, versus just
> removing them back then?
>
> Topics in flight would have needed an update then, but they did
> eventually anyway. So it feels like the total amount of work done is
> larger, compared to just fixing them as the topics were merged. Either
> way the compiler tells us, and the adjustments themselves are small.
>
> Not a huge deal either way, but just pondering for future such
> situations.
Yeah, I'm always very torn on these myself. I guess ultimately it's
always going to be dependent on the actual refactoring: the bigger the
blast radius, the more it makes sense to have a transition period so
that we don't break in-flight patch series.
Where exactly that line is is a different question of course.
Patrick
^ permalink raw reply
* Re: git hook question
From: Jeff King @ 2026-06-01 5:55 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Wesley Schwengle, Git maillinglist
In-Reply-To: <xmqqcxyaakpy.fsf@gitster.g>
On Mon, Jun 01, 2026 at 02:33:13PM +0900, Junio C Hamano wrote:
> Jeff King <peff@peff.net> writes:
>
> > I don't think so; the command is expected to handle (or ignore) the
> > arguments as appropriate.
>
> We should also caution that the command is expected to handle not
> just the arguments but its standard input. Not reading any and
> exiting may be a no-no for some hooks.
Perhaps. I think we've tried to make Git resilient to hooks which do not
read all of their input (by ignoring SIGPIPE). It may be a bug for a
hook to ignore stdin, but depending on what the hook is trying to do,
that information might or might not be relevant.
I do think there is a gotcha for hooks that expect the stdin of their
commands to be hooked up to a terminal to interact with the user.
I certainly don't have any objection to calling more of this out in the
docs, though.
-Peff
^ permalink raw reply
* Re: git hook question
From: Junio C Hamano @ 2026-06-01 5:33 UTC (permalink / raw)
To: Jeff King; +Cc: Wesley Schwengle, Git maillinglist
In-Reply-To: <20260529052141.GA1099450@coredump.intra.peff.net>
Jeff King <peff@peff.net> writes:
> I don't think so; the command is expected to handle (or ignore) the
> arguments as appropriate.
We should also caution that the command is expected to handle not
just the arguments but its standard input. Not reading any and
exiting may be a no-no for some hooks.
And unlike command line arguments, there is no handy way to say "I
do not care what the input is" (other than putting "cat >/dev/null;"
in front of what you really want to do, that is).
^ permalink raw reply
* Re: [PATCH 0/5] git son: add command to create independent child repositories
From: Junio C Hamano @ 2026-06-01 5:33 UTC (permalink / raw)
To: Evan Haque via GitGitGadget; +Cc: git, Evan Haque
In-Reply-To: <pull.2122.git.1779814052.gitgitgadget@gmail.com>
"Evan Haque via GitGitGadget" <gitgitgadget@gmail.com> writes:
> Motivation
> ==========
>
> When spinning off a new project that is related to an existing repository,
> there is no built-in way to create a child repository that maintains a link
> back to its parent without the tight coupling of submodules. Submodules pin
> the child to a specific commit and require the parent to track the child in
> its index, which is too heavyweight when the child is meant to be fully
> independent.
>
> The typical workflow today is manual: git init, git remote add, update
> .gitignore — three steps that are easy to forget or get wrong. git son
> automates this and establishes a lightweight convention for the parent-child
> relationship: a remote named parent in the child, and nothing in the parent
> except an ignore rule.
Although I am personally not interested in this topic even for local
repository use, I should point out that using this tool to create
this combination of repositories would not be useful for other
people who want to clone your arrangement. Other than leaving
comments in the parent project, there seems to be no way to specify
how or where the child projects should be cloned within the working
tree of the parent project.
Since Git is primarily a tool for collaboration among people with
their own repositories, I fail see how this feature is something we
should ship to all Git users as part of the core distribution.
Thanks.
^ permalink raw reply
* Re: [PATCH v3 0/6] [RFC] diff: add diff.<driver>.process for external hunk providers
From: Michael Montalbo @ 2026-06-01 4:28 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Michael Montalbo via GitGitGadget, git
In-Reply-To: <xmqq5x43dfk4.fsf@gitster.g>
On Sun, May 31, 2026 at 3:44 AM Junio C Hamano <gitster@pobox.com> wrote:
>
> "Michael Montalbo via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
> > Language-aware diff tools (e.g., Difftastic) and format-specific analyzers
> > can produce better line matching than Git's builtin diff algorithm, but
> > diff.<driver>.command replaces Git's output entirely, losing downstream
> > features like word diff, function context, color, and blame.
>
> This seems to break CI on Windows; take a look at
>
> https://github.com/git/git/actions/runs/26709491830/job/78717295153
>
> for an example.
>
> Thanks.
Thanks for the heads up. Interestingly, I think Windows exposed a latent issue
with sub-process startup dying instead of erroring out when there is a space in
the path.
I've submitted https://lore.kernel.org/git/pull.2133.git.1780287309846.gitgitgadget@gmail.com/T/#u
which I believe addresses the issue, however it seems like there are
some potentially
unrelated CI failures going on right now which is making verification
a bit harder.
^ permalink raw reply
* [PATCH] sub-process: use gentle handshake to avoid die() on startup failure
From: Michael Montalbo via GitGitGadget @ 2026-06-01 4:15 UTC (permalink / raw)
To: git; +Cc: Michael Montalbo, Michael Montalbo
From: Michael Montalbo <mmontalbo@gmail.com>
When the configured subprocess command contains shell metacharacters
(such as a space), prepare_shell_cmd() wraps it in "sh -c <cmd>".
The shell itself always starts successfully, so start_command()
returns zero even if the tool inside does not exist. The subsequent
handshake then reads from a dead pipe and calls die() via the
non-gentle packet_read_line(), killing the parent process instead of
letting it handle the error.
Before this change, a missing filter process at a path containing
spaces produces a confusing error:
$ git -c filter.lfs.process="/path with space/tool" \
-c filter.lfs.required=true add file.txt
fatal: the remote end hung up unexpectedly
After this change, the proper error is reported:
$ git ... add file.txt
error: initialization for subprocess '/path with space/tool' failed
fatal: file.txt: clean filter 'lfs' failed
Switch the subprocess handshake from the dying packet_read_line()
to packet_read_line_gently() so that a process that exits during
startup produces an error return instead of killing the caller.
This affects any subprocess consumer whose command path contains
spaces. On Windows this routinely happens because programs live
under "C:/Program Files/...", and MSYS2 path conversion can rewrite
absolute paths to include that prefix. On POSIX it triggers
whenever the configured path naturally contains a space or other
metacharacter. convert.c (filter.<driver>.process, used by git-lfs
and custom clean/smudge filters) is the primary affected consumer.
Signed-off-by: Michael Montalbo <mmontalbo@gmail.com>
---
sub-process: use gentle handshake to avoid die() on startup failure
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2133%2Fmmontalbo%2Fmm%2Fsubprocess-handshake-fix-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2133/mmontalbo/mm/subprocess-handshake-fix-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/2133
sub-process.c | 11 ++++++-----
t/t0021-conversion.sh | 17 +++++++++++++++++
2 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/sub-process.c b/sub-process.c
index 83bf0a0e82..22c68bd10d 100644
--- a/sub-process.c
+++ b/sub-process.c
@@ -132,18 +132,19 @@ static int handshake_version(struct child_process *process,
if (packet_flush_gently(process->in))
return error("Could not write flush packet");
- if (!(line = packet_read_line(process->out, NULL)) ||
+ if (packet_read_line_gently(process->out, NULL, &line) <= 0 ||
!skip_prefix(line, welcome_prefix, &p) ||
strcmp(p, "-server"))
return error("Unexpected line '%s', expected %s-server",
line ? line : "<flush packet>", welcome_prefix);
- if (!(line = packet_read_line(process->out, NULL)) ||
+ if (packet_read_line_gently(process->out, NULL, &line) <= 0 ||
!skip_prefix(line, "version=", &p) ||
strtol_i(p, 10, chosen_version))
return error("Unexpected line '%s', expected version",
line ? line : "<flush packet>");
- if ((line = packet_read_line(process->out, NULL)))
- return error("Unexpected line '%s', expected flush", line);
+ if (packet_read_line_gently(process->out, NULL, &line) < 0 || line)
+ return error("Unexpected line '%s', expected flush",
+ line ? line : "<read error>");
/* Check to make sure that the version received is supported */
for (i = 0; versions[i]; i++) {
@@ -171,7 +172,7 @@ static int handshake_capabilities(struct child_process *process,
if (packet_flush_gently(process->in))
return error("Could not write flush packet");
- while ((line = packet_read_line(process->out, NULL))) {
+ while (packet_read_line_gently(process->out, NULL, &line) > 0) {
const char *p;
if (!skip_prefix(line, "capability=", &p))
continue;
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index f0d50d769e..033b00a364 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -857,6 +857,23 @@ test_expect_success 'invalid process filter must fail (and not hang!)' '
)
'
+test_expect_success 'missing process filter with space in path does not die' '
+ test_config_global filter.protocol.process "/non existent/tool" &&
+ test_config_global filter.protocol.required true &&
+ rm -rf repo &&
+ mkdir repo &&
+ (
+ cd repo &&
+ git init &&
+
+ echo "*.r filter=protocol" >.gitattributes &&
+
+ cp "$TEST_ROOT/test.o" test.r &&
+ test_must_fail git add . 2>git-stderr.log &&
+ test_grep "clean filter.*protocol.*failed" git-stderr.log
+ )
+'
+
test_expect_success 'delayed checkout in process filter' '
test_config_global filter.a.process "test-tool rot13-filter --log=a.log clean smudge delay" &&
test_config_global filter.a.required true &&
base-commit: 29bd7ed5127255713c1ac2f43b7c6f257d7b4594
--
gitgitgadget
^ permalink raw reply related
* Re: [PATCH v2] doc: fix typos via codespell
From: Junio C Hamano @ 2026-06-01 1:16 UTC (permalink / raw)
To: Andrew Kreimer; +Cc: git
In-Reply-To: <20260531184428.55905-1-algonell@gmail.com>
Andrew Kreimer <algonell@gmail.com> writes:
> diff --git a/midx-write.c b/midx-write.c
> index 561e9eedc0..19e1cd10b7 100644
> --- a/midx-write.c
> +++ b/midx-write.c
> @@ -1461,7 +1461,7 @@ static int write_midx_internal(struct write_midx_opts *opts)
>
> /*
> * Attempt opening the pack index to populate num_objects.
> - * Ignore failiures as they can be expected and are not
> + * Ignore failures as they can be expected and are not
> * fatal during this selection time.
> */
> open_pack_index(oldest);
You seem to have lost the following hunk from the previous round
diff --git a/midx-write.c b/midx-write.c
index a25cab75ab..6d6d29c6cd 100644
--- a/midx-write.c
+++ b/midx-write.c
@@ -1152,7 +1152,7 @@ static bool midx_needs_update(struct multi_pack_index *midx, struct write_midx_c
/*
* Ensure that we have a valid checksum before consulting the
- * exisiting MIDX in order to determine if we can avoid an
+ * existing MIDX in order to determine if we can avoid an
* update.
*
* This is necessary because the given MIDX is loaded directly
but it is OK as the same fix appears in 'master' thanks to 22235136
(midx-write: handle noop writes when converting incremental chains,
2026-05-19).
Other than that, I made sure that there is no other changes since
the initial patch other than that the changes to po/ and git-gui/ no
longer exist in the topic, which matches what the proposed commit
log says.
However, there are things that BREAK tests.
> diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh
> index ac4a5b2734..869fb4a14e 100755
> --- a/t/t1700-split-index.sh
> +++ b/t/t1700-split-index.sh
> @@ -502,7 +502,7 @@ test_expect_success 'do not refresh null base index' '
> git checkout main &&
> git update-index --split-index &&
> test_commit more &&
> - # must not write a new shareindex, or we wont catch the problem
> + # must not write a new shareindex, or we won't catch the problem
> git -c splitIndex.maxPercentChange=100 merge --no-edit side-branch 2>err &&
> # i.e. do not expect warnings like
> # could not freshen shared index .../shareindex.00000...
The edit above is made to a STRING that is enclosed inside a pair of
single quote. If we want to use "won't", we would need to write "We
won'\''t", but while it may be syntactically correct as a part of
shell script, it is a pointless change, as the target audience wants
to see this line as if it is just a plain text.
"We will not" would be acceptable,
> diff --git a/t/t3909-stash-pathspec-file.sh b/t/t3909-stash-pathspec-file.sh
> index 73f2dbdeb0..3afa6bff3d 100755
> --- a/t/t3909-stash-pathspec-file.sh
> +++ b/t/t3909-stash-pathspec-file.sh
> @@ -29,7 +29,7 @@ verify_expect () {
> test_expect_success 'simplest' '
> restore_checkpoint &&
>
> - # More files are written to make sure that git didnt ignore
> + # More files are written to make sure that git didn't ignore
Ditto. "did not ignore".
> # --pathspec-from-file, stashing everything
> echo A >fileA.t &&
> echo B >fileB.t &&
> @@ -47,7 +47,7 @@ test_expect_success 'simplest' '
> test_expect_success '--pathspec-file-nul' '
> restore_checkpoint &&
>
> - # More files are written to make sure that git didnt ignore
> + # More files are written to make sure that git didn't ignore
Ditto.
> # --pathspec-from-file, stashing everything
> echo A >fileA.t &&
> echo B >fileB.t &&
> @@ -66,7 +66,7 @@ test_expect_success '--pathspec-file-nul' '
> test_expect_success 'only touches what was listed' '
> restore_checkpoint &&
>
> - # More files are written to make sure that git didnt ignore
> + # More files are written to make sure that git didn't ignore
Ditto.
It is a bit disappointing that the changes were guided by a tool
called Codespell, yet apparently the tool does not seem to
understand the syntax rules of the language the files it is
modifying is written in X-<.
Thanks.
^ permalink raw reply related
* Re: [PATCH] describe: fix --exclude, --match with --contains and --all
From: Junio C Hamano @ 2026-06-01 0:40 UTC (permalink / raw)
To: Tuomas Ahola; +Cc: Jacob Keller, git, Jacob Keller
In-Reply-To: <20260531234644.97LRl%taahol@utu.fi>
Tuomas Ahola <taahol@utu.fi> writes:
> Junio C Hamano <gitster@pobox.com> wrote:
>
>> It is curious that this fails in some but not all CI jobs, and even
>> more curious that these failures look the same.
>>
>> e.g., https://github.com/git/git/actions/runs/26671595367/job/78615760984#step:4:1984
>>
>> +++ diff -u expect actual
>> --- expect 2026-05-30 02:21:23
>> +++ actual 2026-05-30 02:21:23
>> @@ -1 +1 @@
>> -branch_A
>> +remotes/origin/remote_branch_A
>> error: last command exited with $?=1
>> not ok 70 - describe --contains --all --exclude
>> #
>> # echo "branch_A" >expect &&
>> # tagged_commit=$(git rev-parse "refs/tags/A^0") &&
>> # git describe --contains --all --exclude="A" --exclude="c" --exclude="test*" $tagged_commit >actual &&
>> # test_cmp expect actual
>>
>> Rings any bell?
>
> That's way out of my wheelhouse but this seems to fix the failure
> for Alpine at least:
>
> -----8<-----
>
> diff --git a/builtin/name-rev.c b/builtin/name-rev.c
> index d6594ada53..1776ffab46 100644
> --- a/builtin/name-rev.c
> +++ b/builtin/name-rev.c
> @@ -416,7 +416,7 @@ static void name_tips(struct mem_pool *string_pool)
> * Try to set better names first, so that worse ones spread
> * less.
> */
> - QSORT(tip_table.table, tip_table.nr, cmp_by_tag_and_age);
> + STABLE_QSORT(tip_table.table, tip_table.nr, cmp_by_tag_and_age);
> for (i = 0; i < tip_table.nr; i++) {
> struct tip_table_entry *e = &tip_table.table[i];
> if (e->commit) {
Ah, OK, when the test has multiple candidates with the same score,
of course emitting any one of them as the answer is a valid and
correctly working program.
So switching to stable-qsort here may "fix" the test breakage, but
it makes the real-world use cases worse, doesn't it? When any one
of the solutions with the same "goodness" is acceptable, the change
makes the code behave as if the elements in the table before they
are sorted have an "if same score, earlier the better" kind of
relationship between them.
I would have preferred to see a tweak on the test side to avoid
having more than one answer of the same goodness, or perhaps list
all the possible acceptable answers and instead of using test_cmp to
check for the exact answer, take any of the acceptable ones, or
something like that.
Thanks.
^ permalink raw reply
* Re: [PATCH] prio-queue: use cascade-down sift for faster extract-min
From: Junio C Hamano @ 2026-06-01 0:09 UTC (permalink / raw)
To: René Scharfe, Kristofer Karlsson via GitGitGadget
Cc: git, Kristofer Karlsson
In-Reply-To: <pull.2132.git.1780250236304.gitgitgadget@gmail.com>
"Kristofer Karlsson via GitGitGadget" <gitgitgadget@gmail.com>
writes:
I'll add René the recipients, as _replace() was added by him as
optimization, so "this new one is functionally equivalent to the
original" somewhat misses the point, even though we may all agree
that the change is a very good one overall in the end when we look
at the entire picture.
> From: Kristofer Karlsson <krka@spotify.com>
>
> Replace the standard sift-down in prio_queue_get() with a
> cascade-down approach.
>
> The standard approach places the last array element at the root,
> then sifts it down. At each level this requires two comparisons
> (left vs right child, then element vs winner) and, when the
> element is larger, a swap (three 16-byte copies).
>
> The cascade approach instead promotes the smaller child into the
> vacant root slot at each level — one comparison and one copy.
> The vacancy sinks to a leaf, where the last array element is
> placed and sifted up if needed — typically zero levels since the
> last array element tends to be large.
>
> In the common case, work per extract drops from 2d comparisons
> + 3d copies to d comparisons + d copies: roughly half the
> comparisons and a third of the data movement. The sift-up phase
> can add work when the last element is smaller than ancestors of
> the leaf vacancy, but this is rare in practice.
>
> Simplify prio_queue_replace() to a plain get+put sequence. This
> is semantically equivalent: the old implementation wrote to slot 0
> and sifted down, which has the same observable effect as removing
> the root and inserting a new element. No caller observes queue
> state between the two operations. The previous implementation
> shared sift_down_root() with get, but the cascade approach no
> longer accommodates that cleanly since sift_down_root() now
> expects the element to reinsert at queue->array[queue->nr], left
> there by prio_queue_get() after decrementing nr. This is fine in
> practice: replace is only called from pop_most_recent_commit()
> (fetch-pack, object-name, walker) and show-branch — none of
> which appear in any hot path.
>
> A synthetic benchmark (10 rounds of 10M put+get cycles, ascending
> integer keys, CPU-pinned, median of 3 runs, same compiler and
> Makefile flags) shows consistent improvement across all queue
> sizes, with no regressions:
>
> queue width baseline cascade speedup
> ------------------------------------------------
> 10 4.32s 3.97s 1.09x
> 100 7.95s 6.49s 1.23x
> 1,000 11.30s 9.66s 1.17x
> 10,000 16.34s 14.15s 1.16x
> 100,000 21.43s 18.66s 1.15x
>
> With descending keys (worst case — the last element always sinks
> to a leaf in both approaches) the cascade still wins slightly
> (1-4%) by replacing swaps with copies, and never regresses.
>
> In end-to-end git commands the improvement is modest because
> sift_down_root is only ~8% of total runtime. Profiling
> rev-list --count on a 2.5M-commit monorepo shows sift_down_root
> dropping from 8.2% to 0.4% of total runtime. The improvement
> scales with DAG width: wider DAGs produce larger priority queues,
> amplifying the per-level savings. In small or narrow repos the
> queues stay shallow and the effect is negligible.
>
> Signed-off-by: Kristofer Karlsson <krka@spotify.com>
> ---
> prio-queue: use cascade-down sift for faster extract-min
>
> Hi, I am not sure this is just noise or not but I thought it at least
> was interesting.
>
> I looked into the internals of prio_queue and found it was technically
> doing too much work and could be simplified/optimized. I found I could
> optimize it by ~20% for the common case (adding commits that would
> typically end up far back in the queue) but only ~1% for the reverse
> case (adding things to the front of the prio queue). The average speedup
> is somewhere in between I suppose. That said, this is not really the
> bottleneck so the overall boost seems to be around ~3-4% improvement for
> repos with wide DAGs.
>
> I would normally classify this as not urgent or important, but I think
> the advantage is that the change is very small and simple and it already
> has good unit tests (t/unit-tests/u-prio-queue.c).
>
> With that said, here are the details:
>
> The prio_queue_get impl is based on removing the root entry, then moving
> the very last element into the root slot, then sifting it down into the
> right place. This uses both comparisons between sibling elements in the
> heap as well as comparisons between the element to add and one of the
> siblings. Then it uses swap operations to move things correctly.
>
> This patch instead promotes the smaller child upward at each level,
> leaving a vacancy that sinks to a leaf, then places the removed element
> there with a short sift-up to keep the heap balanced.
>
> We can analytically compare this - for a sift-distance of d we can
> reason about the number of operations to execute.
>
> Before: 2d comparisons + 3d copies
> After: d comparisons + d copies
>
>
> After changing sift_down in this way, the replace operation can't simply
> depend on it anymore, so I reimplemented it as a sequence of get + put.
> This is technically correct but maybe not as efficient. However, I am
> not sure that it matters, since I couldn't see any usage of the replace
> operation in any hot path.
>
> Performance: Profiling git rev-list --count on a 2.5M-commit monorepo
> shows sift_down_root dropping from 8.2% to 0.4% of total runtime,
> effectively eliminated as significant overhead.
>
> Synthetic benchmark 10 rounds of 10M put+get cycles, CPU-pinned, median
> of 3 runs, same compiler and Makefile flags.
>
> Ascending keys (git's typical pattern -- parents have lower priority
> than children):
>
> queue width baseline patched speedup
> 10 4.32s 3.97s 1.09x
> 100 7.95s 6.49s 1.23x
> 1,000 11.30s 9.66s 1.17x
> 10,000 16.34s 14.15s 1.16x
> 100,000 21.43s 18.66s 1.15x
>
>
> Descending keys (worst case — last element always sinks to leaf in both
> approaches):
>
> queue width baseline patched speedup
> 10 4.84s 4.78s 1.01x
> 100 9.43s 9.20s 1.03x
> 1,000 15.28s 14.71s 1.04x
> 10,000 23.61s 23.49s 1.01x
> 100,000 29.16s 28.22s 1.03x
>
>
> No regressions in any scenario.
>
> End-to-end benchmarks
>
> All benchmarks use a benchmark setup of 1 warmup run followed by 10
> timed runs. Each configuration is built from the same source tree and
> tested on the same repo in alternating order.
>
> linux kernel (1.4M commits) — range v5.0..v6.0 (311K commits):
>
> Command baseline patched speedup
> rev-list --count v5.0..v6.0 455ms 440ms 1.04x
>
>
> I also ran it on git.git but did not see any performance diff at all,
> due to the size and narrow DAG.
>
> The improvement scales with DAG width: wider DAGs produce larger
> priority queues, amplifying the per-level savings. In small or narrow
> repositories the priority queues stay shallow and the sift-down cost is
> already negligible, so the change is not noticeable.
>
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2132%2Fspkrka%2Fcascade-sift-down-v1
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2132/spkrka/cascade-sift-down-v1
> Pull-Request: https://github.com/gitgitgadget/git/pull/2132
>
> prio-queue.c | 22 ++++++++++++----------
> 1 file changed, 12 insertions(+), 10 deletions(-)
>
> diff --git a/prio-queue.c b/prio-queue.c
> index 9748528ce6..18005c43c4 100644
> --- a/prio-queue.c
> +++ b/prio-queue.c
> @@ -62,17 +62,21 @@ static void sift_down_root(struct prio_queue *queue)
> {
> size_t ix, child;
>
> - /* Push down the one at the root */
> - for (ix = 0; ix * 2 + 1 < queue->nr; ix = child) {
> - child = ix * 2 + 1; /* left */
> + for (ix = 0; (child = ix * 2 + 1) < queue->nr; ix = child) {
> if (child + 1 < queue->nr &&
> compare(queue, child, child + 1) >= 0)
> child++; /* use right child */
> + queue->array[ix] = queue->array[child];
> + }
>
> - if (compare(queue, ix, child) <= 0)
> + /* Place queue->array[queue->nr] (left by caller) and sift up. */
> + queue->array[ix] = queue->array[queue->nr];
> + while (ix) {
> + size_t parent = (ix - 1) / 2;
> + if (compare(queue, parent, ix) <= 0)
> break;
> -
> - swap(queue, child, ix);
> + swap(queue, parent, ix);
> + ix = parent;
> }
> }
>
> @@ -89,7 +93,6 @@ void *prio_queue_get(struct prio_queue *queue)
> if (!--queue->nr)
> return result;
>
> - queue->array[0] = queue->array[queue->nr];
> sift_down_root(queue);
> return result;
> }
> @@ -111,8 +114,7 @@ void prio_queue_replace(struct prio_queue *queue, void *thing)
> queue->array[queue->nr - 1].ctr = queue->insertion_ctr++;
> queue->array[queue->nr - 1].data = thing;
> } else {
> - queue->array[0].ctr = queue->insertion_ctr++;
> - queue->array[0].data = thing;
> - sift_down_root(queue);
> + prio_queue_get(queue);
> + prio_queue_put(queue, thing);
> }
> }
>
> base-commit: c69baaf57ba26cf117c2b6793802877f19738b0d
^ permalink raw reply
* Re: [PATCH] describe: fix --exclude, --match with --contains and --all
From: Tuomas Ahola @ 2026-05-31 23:46 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jacob Keller, git, Jacob Keller
In-Reply-To: <xmqqo6hwcves.fsf@gitster.g>
Junio C Hamano <gitster@pobox.com> wrote:
> It is curious that this fails in some but not all CI jobs, and even
> more curious that these failures look the same.
>
> e.g., https://github.com/git/git/actions/runs/26671595367/job/78615760984#step:4:1984
>
> +++ diff -u expect actual
> --- expect 2026-05-30 02:21:23
> +++ actual 2026-05-30 02:21:23
> @@ -1 +1 @@
> -branch_A
> +remotes/origin/remote_branch_A
> error: last command exited with $?=1
> not ok 70 - describe --contains --all --exclude
> #
> # echo "branch_A" >expect &&
> # tagged_commit=$(git rev-parse "refs/tags/A^0") &&
> # git describe --contains --all --exclude="A" --exclude="c" --exclude="test*" $tagged_commit >actual &&
> # test_cmp expect actual
>
> Rings any bell?
That's way out of my wheelhouse but this seems to fix the failure
for Alpine at least:
-----8<-----
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index d6594ada53..1776ffab46 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -416,7 +416,7 @@ static void name_tips(struct mem_pool *string_pool)
* Try to set better names first, so that worse ones spread
* less.
*/
- QSORT(tip_table.table, tip_table.nr, cmp_by_tag_and_age);
+ STABLE_QSORT(tip_table.table, tip_table.nr, cmp_by_tag_and_age);
for (i = 0; i < tip_table.nr; i++) {
struct tip_table_entry *e = &tip_table.table[i];
if (e->commit) {
^ permalink raw reply related
* [PATCH] Makefile: drop duplicate %.a from link recipes
From: Harald Nordgren via GitGitGadget @ 2026-05-31 23:16 UTC (permalink / raw)
To: git; +Cc: Harald Nordgren, Harald Nordgren
From: Harald Nordgren <haraldnordgren@gmail.com>
Three link recipes list archive files twice on the link line: once
via $(filter %.a,$^) and again through $(LIBS), which expands to
$(filter-out %.o,$(GITLIBS)) $(EXTLIBS). On macOS the linker warns
about the duplicates:
ld: warning: ignoring duplicate libraries: 'libgit.a', 'target/release/libgitcore.a'
Drop the redundant filter from the test-helper, fuzz-program, and
unit-test recipes so they match the pattern used by other link
recipes in the file.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>
---
Makefile: drop duplicate %.a from test-helper link rule
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2314%2FHaraldNordgren%2Fmakefile-test-helper-dedup-libs-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2314/HaraldNordgren/makefile-test-helper-dedup-libs-v1
Pull-Request: https://github.com/git/git/pull/2314
Makefile | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile
index b31ecb0756..309d1d1e74 100644
--- a/Makefile
+++ b/Makefile
@@ -3392,7 +3392,7 @@ perf: all
t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS)) $(UNIT_TEST_DIR)/test-lib.o
t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS)
- $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
+ $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
check-sha1:: t/helper/test-tool$X
t/helper/test-sha1.sh
@@ -4015,13 +4015,13 @@ fuzz-all: $(FUZZ_PROGRAMS)
$(FUZZ_PROGRAMS): %: %.o oss-fuzz/dummy-cmd-main.o $(GITLIBS) GIT-LDFLAGS
$(QUIET_LINK)$(FUZZ_CXX) $(FUZZ_CXXFLAGS) -o $@ $(ALL_LDFLAGS) \
-Wl,--allow-multiple-definition \
- $(filter %.o,$^) $(filter %.a,$^) $(LIBS) $(LIB_FUZZING_ENGINE)
+ $(filter %.o,$^) $(LIBS) $(LIB_FUZZING_ENGINE)
$(UNIT_TEST_PROGS): $(UNIT_TEST_BIN)/%$X: $(UNIT_TEST_DIR)/%.o $(UNIT_TEST_OBJS) \
$(GITLIBS) GIT-LDFLAGS
$(call mkdir_p_parent_template)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
- $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
+ $(filter %.o,$^) $(LIBS)
GIT-TEST-SUITES: FORCE
@FLAGS='$(CLAR_TEST_SUITES)'; \
base-commit: 1666c1265231b0bc5f613fbbf3f0a9896cdef76e
--
gitgitgadget
^ permalink raw reply related
* [PATCH v3 12/12] git-gui: add gui and pick as explicit subcommands
From: Mark Levedahl @ 2026-05-31 23:02 UTC (permalink / raw)
To: git; +Cc: j6t, egg_mushroomcow, bootaina702, Mark Levedahl
In-Reply-To: <20260531230225.126817-1-mlevedahl@gmail.com>
git-gui accepts subcommands blame | browser | citool, and assumes the
subcommand is 'gui' if none is actually given, But, git-gui also has a
repository picker (choose_repository::pick) that can create a new
repository + worktree, or choose an existing one, switch to that, and
the run the gui. The user has no direct control over invoking the
picker, instead the picker is triggered by failure in the repository /
worktree discovery process: this includes being started in a directory
not controlled by git, which is probably the intended use case.
The picker can appear when the user has no intention of creating a new
worktree, and the user cannot use the picker to create a new worktree
inside another.
So, add two explicit subcommands:
gui - Run the gui if repository/worktree discovery succeeds, or die
with an error message, but never run the picker.
pick - First run the picker, regardless, then start the gui in
the chosen worktree.
Nothing in this changes the prior behavior, the alternates above must be
explicitly selected to see any change.
Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
---
git-gui.sh | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/git-gui.sh b/git-gui.sh
index 22939215a6..933e72c9b2 100755
--- a/git-gui.sh
+++ b/git-gui.sh
@@ -1024,6 +1024,8 @@ proc load_config {include_global} {
##
## feature option selection
+enable_option picker
+enable_option gitdir_discovery
if {[regexp {^git-(.+)$} [file tail $argv0] _junk subcommand]} {
unset _junk
} else {
@@ -1035,6 +1037,9 @@ if {$subcommand eq {gui.sh}} {
if {$subcommand eq {gui} && [llength $argv] > 0} {
set subcommand [lindex $argv 0]
set argv [lrange $argv 1 end]
+ if {$subcommand eq {gui}} {
+ disable_option picker
+ }
}
enable_option multicommit
@@ -1050,6 +1055,7 @@ blame {
disable_option multicommit
disable_option branch
disable_option transport
+ disable_option picker
}
citool {
enable_option singlecommit
@@ -1058,6 +1064,7 @@ citool {
disable_option multicommit
disable_option branch
disable_option transport
+ disable_option picker
while {[llength $argv] > 0} {
set a [lindex $argv 0]
@@ -1080,6 +1087,9 @@ citool {
set argv [lrange $argv 1 end]
}
}
+pick {
+ disable_option gitdir_discovery
+}
}
######################################################################
@@ -1168,7 +1178,7 @@ proc unset_gitdir_vars {} {
# find repository
set _gitdir {}
-if {$_gitdir eq {}} {
+if {[is_enabled gitdir_discovery]} {
if {[catch {
set _gitdir [git rev-parse --absolute-git-dir]
} err]} {
@@ -1180,7 +1190,7 @@ if {$_gitdir eq {}} {
}
set picked 0
-if {$_gitdir eq {}} {
+if {$_gitdir eq {} && [is_enabled picker]} {
unset_gitdir_vars
load_config 1
apply_config
@@ -1195,6 +1205,12 @@ if {$_gitdir eq {}} {
set picked 1
}
+if {$_gitdir eq {}} {
+ catch {wm withdraw .}
+ error_popup [strcat [mc "Git directory not found:"] "\n\n$err"]
+ exit 1
+}
+
# find worktree, continue without if not required
if {[catch {
set _gitworktree [git rev-parse --show-toplevel]
@@ -3104,14 +3120,15 @@ blame {
return
}
citool -
-gui {
+gui -
+pick {
if {[llength $argv] != 0} {
usage
}
# fall through to setup UI for commits
}
default {
- set err "[mc usage:] $argv0 \[{blame|browser|citool}\]"
+ set err "[mc usage:] $argv0 \[{blame|browser|citool|gui|pick}\]"
if {[tk windowingsystem] eq "win32"} {
wm withdraw .
tk_messageBox -icon error -message $err \
--
2.54.0.99.14
^ permalink raw reply related
* [PATCH v3 11/12] git-gui: check browser/blame arguments carefully
From: Mark Levedahl @ 2026-05-31 23:02 UTC (permalink / raw)
To: git; +Cc: j6t, egg_mushroomcow, bootaina702, Mark Levedahl
In-Reply-To: <20260531230225.126817-1-mlevedahl@gmail.com>
git gui offers two related commands, browser and blame, that provide
graphical interfaces driven by git ls-tree and git blame. As such, the
arguments to git-gui need to satisfy those two git commands. But,
git-gui does not assure this leading to confusing or incorrect results.
For instance 'git browser <non-existent path>' shows a blank browser
window rather than error message.
Also, commit 3e45ee1ef2 ("git-gui: Smarter command line parsing for
browser, blame", 2007-05-08) implemented code to allow giving path
before rev on the command line, and unconditionally uses the worktree to
disambiguate. As a result, the following command run in a current
git-gui checkout of the master branch shows the master branch version of
blame.tcl, when none should be shown as that file does not exist in
gitgui-0.6.0.
git gui blame lib/blame.tcl gitgui-0.6.0
This 'file before rev' feature in git-gui mirrors ideas considered when
git's user interface was very young, but no such feature is documented
for any git command. Rather than try to fix an idea git itself
rejected, let's just remove this broken and hopefully unused feature.
git-gui browser|blame both accept 'rev' and 'path' as command line
arguments. rev defaults to 'HEAD' if not given, while path must be
given. path names a directory tree to ls-tree or a file to blame. path
must exist in rev for ls-tree and for blame. In addition git blame will
include uncommitted changes from the worktree file at 'path' if rev is
not given (thus defaulting to HEAD), but still requires that the file
exists in HEAD.
So, let's clean up the parser to check that the arguments are usable.
- give a full synopsis, including '--' that may be used to separate rev and
path. (as path is the required final arg, -- gives no extra info)
- explicitly check the number of arguments
- use rev-parse to assure a user supplied rev is valid
- use ls-tree to assure that path exists in rev
- for blame only, with no rev given and a worktree existing, also assure
that path points to a file in the worktree
With these changes, error messages are thrown by the parser if the path
or rev are not known: no blank or erroneous displays are created. Also,
this avoids accessing the worktree except in the specific use case
supported by blame / git-blame, meaning browser|blame now also work
without a worktree.
Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
---
git-gui.sh | 122 +++++++++++++++++++++++++++--------------------------
1 file changed, 63 insertions(+), 59 deletions(-)
diff --git a/git-gui.sh b/git-gui.sh
index 16d6b3051a..22939215a6 100755
--- a/git-gui.sh
+++ b/git-gui.sh
@@ -3000,101 +3000,105 @@ proc normalize_relpath {path} {
}
}
+proc show_parse_err {err} {
+ if {[tk windowingsystem] eq "win32"} {
+ catch {wm withdraw .}
+ error_popup $err
+ } else {
+ puts stderr $err
+ }
+ exit 1
+}
+
# -- Not a normal commit type invocation? Do that instead!
#
switch -- $subcommand {
browser -
blame {
if {$subcommand eq "blame"} {
- set subcommand_args {[--line=<num>] rev? path}
+ set subcommand_args {[--line=<num>] [rev] [--] <filename>}
+ set required_pathtype blob
} else {
- set subcommand_args {rev? path}
+ set subcommand_args {[rev] [--] <dirname>}
+ set required_pathtype tree
}
- if {$argv eq {}} usage
+ set maxargs [llength $subcommand_args]
+ set nargs [llength $argv]
+ if {$nargs < 1 || $nargs > $maxargs} usage
set head {}
set path {}
set jump_spec {}
- set is_path 0
- foreach a $argv {
- set p [file join $_prefix $a]
- if {$is_path || [file exists $p]} {
- if {$path ne {}} usage
- set path [normalize_relpath $p]
- break
+ set iarg 0
+ foreach a $argv {
+ incr iarg
+ if {$iarg == $nargs} {
+ # final argument is path
+ set path [normalize_relpath [file join $_prefix $a]]
} elseif {$a eq {--}} {
- if {$path ne {}} {
- if {$head ne {}} usage
- set head $path
- set path {}
+ # allow before required final arg that must be path
+ if {$iarg != $nargs - 1} {
+ usage
}
- set is_path 1
} elseif {[regexp {^--line=(\d+)$} $a a lnum]} {
- if {$jump_spec ne {} || $head ne {}} usage
+ # --line can only be the first arg
+ if {$iarg != 1 || $subcommand ne {blame}} usage
set jump_spec [list $lnum]
} elseif {$head eq {}} {
- if {$head ne {}} usage
set head $a
- set is_path 1
} else {
usage
}
}
- unset is_path
- if {$head ne {} && $path eq {}} {
- if {[string index $head 0] eq {/}} {
- set path [normalize_relpath $head]
- set head {}
+ # If head not given, use current branch (HEAD),
+ # and blame will use worktree if there is one.
+ set use_worktree 0
+ if {$head eq {}} {
+ load_current_branch
+ set head $current_branch
+ if {$subcommand eq {blame} && ![is_bare]} {
+ if {![file isfile $path]} {
+ show_parse_err [mc "fatal: no such file '%s' in worktree" $path]
+ }
+ set use_worktree 1
+ }
+ } else {
+ if {[catch {
+ set commitid \
+ [git rev-parse --verify --end-of-options \
+ [strcat $head "^{commit}"]]
+ }]} {
+ show_parse_err [mc "fatal: '%s' is not a valid rev'" $head]
} else {
- set path [normalize_relpath $_prefix$head]
- set head {}
+ set current_branch $head
}
}
- if {$head eq {}} {
- load_current_branch
- } else {
- if {[regexp [string map "@@ [expr $hashlength - 1]" {^[0-9a-f]{1,@@}$}] $head]} {
- if {[catch {
- set head [git rev-parse --verify $head]
- } err]} {
- if {[tk windowingsystem] eq "win32"} {
- tk_messageBox -icon error -title [mc Error] -message $err
- } else {
- puts stderr $err
- }
- exit 1
- }
+ # check path is known in head, and is file / directory as required
+ set pathtype {}
+ catch {set pathtype [git ls-tree {--format=%(objecttype)} $head $path]}
+ if {$pathtype ne {} && $path eq {.}} {
+ # ls-tree gives contents of root-dir, we need root-dir itself
+ set pathtype {tree}
+ }
+
+ if {$pathtype ne $required_pathtype} {
+ switch -- $required_pathtype {
+ tree {show_parse_err \
+ [mc "'%s' is not a directory in rev '%s'" $path $head]}
+ blob {show_parse_err \
+ [mc "'%s' is not a filename in rev '%s'" $path $head]}
}
- set current_branch $head
}
wm deiconify .
switch -- $subcommand {
browser {
- if {$jump_spec ne {}} usage
- if {$head eq {}} {
- if {$path ne {} && [file isdirectory $path]} {
- set head $current_branch
- } else {
- set head $path
- set path {}
- }
- }
browser::new $head $path
}
blame {
- if {$head eq {} && ![file exists $path]} {
- catch {wm withdraw .}
- tk_messageBox \
- -icon error \
- -type ok \
- -title [mc "git-gui: fatal error"] \
- -message [mc "fatal: cannot stat path %s: No such file or directory" $path]
- exit 1
- }
- blame::new $head $path $jump_spec
+ blame::new [expr {$use_worktree ? {} : $head}] $path $jump_spec
}
}
return
--
2.54.0.99.14
^ permalink raw reply related
* [PATCH v3 10/12] git-gui: allow specifying path '.' to the browser
From: Mark Levedahl @ 2026-05-31 23:02 UTC (permalink / raw)
To: git; +Cc: j6t, egg_mushroomcow, bootaina702, Mark Levedahl
In-Reply-To: <20260531230225.126817-1-mlevedahl@gmail.com>
Invoking "git-gui browser rev ." should show the file browser for the
commitish rev, starting at the current directory. When the current
directory is the working tree root, this errors out in normalize_relpath
because the '.' is removed, yielding an empty list as argument to [file
join ...]. git ls-tree (underlying the browser) accepts '.', so use that
as the value when in the root.
Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
---
git-gui.sh | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/git-gui.sh b/git-gui.sh
index f48d929da8..16d6b3051a 100755
--- a/git-gui.sh
+++ b/git-gui.sh
@@ -2993,7 +2993,11 @@ proc normalize_relpath {path} {
}
lappend elements $item
}
- return [eval file join $elements]
+ if {$elements ne {}} {
+ return [eval file join $elements]
+ } else {
+ return {.}
+ }
}
# -- Not a normal commit type invocation? Do that instead!
--
2.54.0.99.14
^ permalink raw reply related
* [PATCH v3 09/12] git-gui: try harder to find worktree from gitdir
From: Mark Levedahl @ 2026-05-31 23:02 UTC (permalink / raw)
To: git; +Cc: j6t, egg_mushroomcow, bootaina702, Mark Levedahl
In-Reply-To: <20260531230225.126817-1-mlevedahl@gmail.com>
git-gui, since 87cd09f43e ("git-gui: work from the .git dir",
2010-01-23), has had the intent to allow starting from inside a
repository, then switching to the parent directory if that is a valid
worktree.
This certainly hasn't worked since 2d92ab32fd ("rev-parse: make
--show-toplevel without a worktree an error", 2019-11-19) in git, but
breaking this git-gui feature was unintentional.
There are (at least) 3 cases where the gitdir can tell us where the
worktree is, and we would like all to work:
- core.worktree is set, and points to a valid worktree. This is already
handled by git rev-parse --show-toplevel, even when not in the worktree.
There is nothing more to do in this case.
- the gitdir is embedded in a worktree as subdirectory .git. The parent
is (or at least should be) a valid worktree. This worked long ago.
- the gitdir is a worktree specific directory (under
<mainrepo>/worktrees/worktree_name), within which there is a file
"gitdir" pointing to .git in the worktree. git gui never learned to
handle this case.
Let's handle the latter two cases. Always check that the discovered
worktree is valid and points to the already discovered gitdir according
to git rev-parse. This avoids issues that may arise because we are
discovering from the gitdir up, rather than the worktree down, and file
system non-posix behavior or misconfiguration of git might cause
confusion. For instance, a manually moved worktree might not be where
the gitdir points, or the gitdir might be configured with
core.bare=true.
Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
---
git-gui.sh | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/git-gui.sh b/git-gui.sh
index abee222903..f48d929da8 100755
--- a/git-gui.sh
+++ b/git-gui.sh
@@ -1103,6 +1103,37 @@ unset argv0dir
##
## repository setup
+proc find_worktree_from_gitdir {} {
+ # this is invoked only if the current directory is inside the repository
+ set worktree {}
+ if {[file tail $::_gitdir] eq {.git}} {
+ # the dir containing .git is a worktree if repo allows it
+ # Check that git reports parent as a worktree (gitdir might not allow a worktree)
+ if {[catch {
+ set parent [file dirname $::_gitdir]
+ set worktree [git -C $parent rev-parse --show-toplevel]
+ }]} {
+ set worktree {}
+ }
+ } elseif [file exists {gitdir}] {
+ # a worktree gitdir has .gitdir naming worktree/.git
+ # assure git run there reports this dir as the gitdir (links might be broken)
+ if {[catch {
+ set fd_gitdir [open {gitdir} {r}]
+ set worktree [file dirname [read $fd_gitdir]]
+ catch {close $fd_gitdir}
+ set worktree_gitdir [git -C $worktree rev-parse --absolute-git-dir]
+ if {$::_gitdir ne $worktree_gitdir} {
+ set worktree {}
+ }
+ }]} {
+ catch {close $fd_gitdir}
+ set worktree {}
+ }
+ }
+ return $worktree
+}
+
proc is_gitvars_error {err} {
set havevars 0
set GIT_DIR {}
@@ -1176,6 +1207,13 @@ if {[catch {
set _prefix {}
}
+if {[is_bare]} {
+ # Maybe we are in an embedded or worktree specific gitdir
+ if {[set _gitworktree [find_worktree_from_gitdir]] ne {}} {
+ set _prefix {}
+ }
+}
+
if {![is_bare]} {
if {[catch {cd $_gitworktree} err]} {
catch {wm withdraw .}
--
2.54.0.99.14
^ permalink raw reply related
* [PATCH v3 08/12] git-gui: simplify [is_bare] to report if a worktree is known
From: Mark Levedahl @ 2026-05-31 23:02 UTC (permalink / raw)
To: git; +Cc: j6t, egg_mushroomcow, bootaina702, Mark Levedahl
In-Reply-To: <20260531230225.126817-1-mlevedahl@gmail.com>
git-gui includes proc is_bare, used in several places to make decisions
on whether a worktree exists, but also in discovery to tell if a
worktree can be supported.
But, is_bare is out of date with regard to multiple worktrees, safe
repository guards, and possibly other relevant features known to git
rev-parse. Also, is_bare caches its result on the first call, so is not
useful if a later step in the discovery process finds a worktree.
So, simplify is_bare to report whether git-gui has a worktree or is
working only from a repository.
Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
---
git-gui.sh | 25 +------------------------
1 file changed, 1 insertion(+), 24 deletions(-)
diff --git a/git-gui.sh b/git-gui.sh
index 53b6859345..abee222903 100755
--- a/git-gui.sh
+++ b/git-gui.sh
@@ -372,7 +372,6 @@ if {[tk windowingsystem] eq "aqua"} {
set _appname {Git Gui}
set _gitdir {}
set _gitworktree {}
-set _isbare {}
set _githtmldir {}
set _prefix {}
set _reponame {}
@@ -524,29 +523,7 @@ proc get_config {name} {
}
proc is_bare {} {
- global _isbare
- global _gitdir
- global _gitworktree
-
- if {$_isbare eq {}} {
- if {[catch {
- set _bare [git rev-parse --is-bare-repository]
- switch -- $_bare {
- true { set _isbare 1 }
- false { set _isbare 0}
- default { throw }
- }
- }]} {
- if {[is_config_true core.bare]
- || ($_gitworktree eq {}
- && [lindex [file split $_gitdir] end] ne {.git})} {
- set _isbare 1
- } else {
- set _isbare 0
- }
- }
- }
- return $_isbare
+ return [expr {$::_gitworktree eq {}}]
}
######################################################################
--
2.54.0.99.14
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox