* Re: [PATCH 1/8] t0001: plug test gaps for git-init(1) with GIT_OBJECT_DIRECTORY
From: Kristoffer Haugsbakk @ 2026-05-21 17:51 UTC (permalink / raw)
To: Patrick Steinhardt, git
In-Reply-To: <20260521-b4-pks-setup-centralize-odb-creation-v1-1-f130d2a7e8ae@pks.im>
On Thu, May 21, 2026, at 09:42, Patrick Steinhardt wrote:
> In subsequent commits we'll rework how we set up the repository. This is
> a somewhat intricate and thus fragile sequence, there's many things that
Should this be s/, there/; there/ ? Depends on if this is a list of
three items or if “This is” is a subclause that is supposed to point at
“there's many”.
> can go subtly wrong, and there are lots of interesting interactions that
> one can discover.
>
> One such discovered edge case was the interaction between git-init(1)
> and the "GIT_OBJECT_DIRECTORY" enviroment variable. When set, the
> behaviour is that the object directory should be created at the path
> that the variable points to. This behaviour is documented as such in
> its man page:
>
> If the object storage directory is specified via the
> GIT_OBJECT_DIRECTORY environment variable then the sha1 directories
> are created underneath; otherwise, the default $GIT_DIR/objects
> directory is used.
>
> Curiously enough though we don't seem to have any tests that exercise
> this directly, and thus a subsequent commit inadvertently broke this
> expectation.
Isn’t it more that “the upcoming changes *would have* broken” them if
not for this change? This seems to refer to a an alternative commit
history where this change does not exist?
>
> Plug this test gap.
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>[snip]
^ permalink raw reply
* Re: [PATCH 16/18] odb/source-loose: wire up `write_object_stream()` callback
From: Junio C Hamano @ 2026-05-21 17:49 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: git
In-Reply-To: <20260521-b4-pks-odb-source-loose-v1-16-6553b399be2d@pks.im>
Patrick Steinhardt <ps@pks.im> writes:
> -int odb_source_loose_write_stream(struct odb_source_loose *loose,
> +/*
> + * Write the given stream into the loose object source. The only difference to
> + * the generic implementation of this function is that we don't perform an
"difference to" -> "difference from"???
^ permalink raw reply
* Re: [PATCH v2 07/11] git-gui: try harder to find worktree from gitdir
From: Mark Levedahl @ 2026-05-21 17:45 UTC (permalink / raw)
To: Shroom Moo; +Cc: git, Johannes Sixt, Aina Boot
In-Reply-To: <tencent_E13EB585242AD7C263B8B3B732A428465D09@qq.com>
On 5/21/26 12:55 AM, Shroom Moo wrote:
> On 5/21/26 4:24 AM, Mark Levedahl wrote:
>> + } elseif [file exists {gitdir}] {
>> + if {[catch {
>> + set fd_gitdir [open {gitdir} {r}]
>> + set gitlink_parent [file dirname [read $fd_gitdir]]
>> + catch {close $fd_gitdir}
>> + set worktree [git -C $gitlink_parent rev-parse --show-toplevel]
>> + set parent_gitdir [git -C $worktree rev-parse --absolute-git-dir]
>> + if {$::_gitdir ne $parent_gitdir} {
>> + set worktree {}
>> + }
>> + }]} {
>> + catch {close $fd_gitdir}
>> + set worktree {}
>> + }
>> + }
> There is also an unaddressed issue:
> In [file exists {gitdir}] and [open {gitdir} r], {gitdir} is a
> literal string referring to a file named gitdir in the current
> working directory. However, in the context of a linked worktree
> (created via git worktree add), the actual file path is
> $_gitdir/gitdir (e.g., .git/worktrees/<name>/gitdir). While the
> current working directory could be anywhere (even inside the .git
> directory), $_gitdir is an absolute path pointing to that worktree's
> gitdir (e.g., /path/to/main/.git/worktrees/branch). The gitdir file
> resides within the $_gitdir directory and contains a relative path
> like ../../.git/worktrees/branch. The current code logic will never
> locate this file.
You have to be in the particular worktree's gitdir for this to work. I there exists
worktrees/foo
worktrees/frotz
worktrees/bar
Which would we expore? The code above must be in foo, frotz, bar
The main worktree is found not from worktrees/*, but from the root of the gitdir.
>
> Additionally, [file exists {gitdir}] checks for the gitdir file in
> the current working directory. Since the function has not yet
> switched to $_gitdir when this check runs, it is almost impossible
> to find the file. Consequently, this logic never triggers, preventing
> linked worktrees from being recognized.
>
> Maybe the identification of linked worktree should not directly look
> for the gitdir file, but should check whether there is a.git file and
> its content points to... /.git/worktrees/... ? Anyways, using the
> literal {gitdir} to search in the current directory lead to risks.
>
> Shroom
>
We cannot get to this code if not inside the gitdir, and if the user set GIT_DIR and/or
GIT_WORK_TREE to do something clever, that either worked or the code already threw an
error. git, without GIT_WORK_TREE set, uses the current directory as the worktree, or the
parent directory containing .git. So, we must be inside the gitdir if this code path gets hit.
Mark
Mark
^ permalink raw reply
* Re: [PATCH v2 10/11] git-gui: adapt blame/browser parsing for bare operation
From: Mark Levedahl @ 2026-05-21 17:35 UTC (permalink / raw)
To: Shroom Moo; +Cc: git, Johannes Sixt, Aina Boot
In-Reply-To: <tencent_407FE60B6954528497709B6CAD49018D120A@qq.com>
On 5/21/26 1:02 AM, Shroom Moo wrote:
> On 5/21/26 4:24 AM, Mark Levedahl wrote:
>> +proc find_path_type {head path} {
>> + if {$path eq {./}} {
>> + # the root-tree exists in every rev, ls-tree gives data on the contents,
>> + # not the type of tree itself. So, if the rev exists, return {tree}
>> + if {[catch {set objtype [git ls-tree $head]}]} {
>> + set objtype {}
>> + } else {
>> + set objtype {tree}
>> + }
>> + } else {
>> + # test that the path exists in head, ls-tree gives info on the path only
>> + if {[catch {set objtype [git ls-tree {--format=%(objecttype)} $head $path]}]} {
>> + set objtype {}
>> + }
>> + }
>> + return $objtype
>> +}
> In v1, argument parsing relied on file exists within the worktree to
> determine if a path existed, without using ls-tree. In v2, the use of
> git ls-tree seems to actually be intended to list directory contents,
> rather than querying the type of the path itself.
>
> If $path is a directory (a tree object), git ls-tree outputs the
> object type for every entry within that directory, one per line.
>
> The variable objtype is assigned a multi-line string. When compared
> against "tree", the match fails, causing the function to return an
> empty string, which subsequently leads to an error. We can change to
> "git cat-file -t" or similiar approaches.
>
> Shroom
>
git ls-tree $rev $path --format='%(objecttype)' gives the type of the object at $path in
$rev, or an error. The types returned are "tree" for a directory, "blob" for a file. So
this gives definitive information if the object desired exists in the given rev, and is of
the right type. (We don't care about commits and tags, those cannot be blamed or browsed).
git-lstree $rev $dirname/ lists all of the objects in the directory, while git-lstree
$rev $dirname (no trailing /) gives info on the directory itself. There is no name for the
root directory itself, all of its contents are listed. That is why the root './' is
special case.
Asking the worktree that is on version 33 about whether frotz is a directory in version 2
is just asking for trouble, at best the worktree is authoritative for the checked out
version, but even then there can be uncommitted changed. In the root of git-gui, I get
/git-gui.sh browser gitgui-0.9.0 Makefile
'Makefile' is not a directory in rev 'gitgui-0.9.0'
so the types of objects are being checked.
Mark
^ permalink raw reply
* Re: [PATCH 1/8] t0001: plug test gaps for git-init(1) with GIT_OBJECT_DIRECTORY
From: Junio C Hamano @ 2026-05-21 16:49 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: git
In-Reply-To: <20260521-b4-pks-setup-centralize-odb-creation-v1-1-f130d2a7e8ae@pks.im>
Patrick Steinhardt <ps@pks.im> writes:
> In subsequent commits we'll rework how we set up the repository. This is
> a somewhat intricate and thus fragile sequence, there's many things that
> can go subtly wrong, and there are lots of interesting interactions that
> one can discover.
>
> One such discovered edge case was the interaction between git-init(1)
> and the "GIT_OBJECT_DIRECTORY" enviroment variable. When set, the
"environment"???
> behaviour is that the object directory should be created at the path
> that the variable points to. This behaviour is documented as such in
> its man page:
>
> If the object storage directory is specified via the
> GIT_OBJECT_DIRECTORY environment variable then the sha1 directories
> are created underneath; otherwise, the default $GIT_DIR/objects
> directory is used.
>
> Curiously enough though we don't seem to have any tests that exercise
> this directly, and thus a subsequent commit inadvertently broke this
> expectation.
>
> Plug this test gap.
Nice.
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
> t/t0001-init.sh | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/t/t0001-init.sh b/t/t0001-init.sh
> index e4d32bb4d2..e89feca544 100755
> --- a/t/t0001-init.sh
> +++ b/t/t0001-init.sh
> @@ -980,4 +980,14 @@ test_expect_success 're-init reads matching includeIf.onbranch' '
> test_cmp expect err
> '
>
> +test_expect_success 'init honors GIT_OBJECT_DIRECTORY' '
> + test_when_finished "rm -rf init-objdir custom-odb" &&
> + mkdir custom-odb &&
> + env GIT_OBJECT_DIRECTORY="$(pwd)/custom-odb" \
> + git init init-objdir &&
> + test_path_is_missing init-objdir/.git/objects/pack &&
> + test_path_is_dir custom-odb/pack &&
> + test_path_is_dir custom-odb/info
> +'
> +
> test_done
^ permalink raw reply
* Re: [PATCH v3 1/8] environment: move "trust_ctime" into `struct repo_config_values`
From: Tian Yuchen @ 2026-05-21 16:37 UTC (permalink / raw)
To: Olamide Caleb Bello, git
Cc: phillip.wood123, gitster, christian.couder, usmanakinyemi202,
kaartic.sivaraam, me
In-Reply-To: <20260423165432.143598-2-belkid98@gmail.com>
Hi Bello!
On 4/24/26 00:54, Olamide Caleb Bello wrote:
The code itself looks great to me, but I have some reservations about
the description here (in terms of why trust_ctime is eagerly parsed):
> `core.trustctime` is parsed eagerly
> because it is used in low‑level stat‑matching functions
> (`match_stat_data()`), where a lazy parse could cause unexpected
> fatal errors and complicate libification efforts.
It's true that if we use repo_config_get_bool() to parse trust_ctime,
following the call stack downwards, there is a die() call. The terminate
condition is that the configuration does not exist or contains invalid
characters.
But I think there is another factor: match_stat_data() is called on a
hot path. The following code is implemented in read-cache.c,
refresh_index() function:
for (i = 0; i < istate->cache_nr; i++) {
...
new_entry = refresh_cache_ent(istate, ce, options,
&cache_errno, &changed,
&t2_did_lstat, &t2_did_scan);
t2_sum_lstat += t2_did_lstat;
t2_sum_scan += t2_did_scan;
if (new_entry == ce)
...
The call chain: refresh_index() -> refresh_cache_ent() ->
ie_match_stat() -> ce_match_stat_basic() -> *match_stat_data()*
Therefore, if the variable is lazily parsed, this means there will be a
performance regression whenever the index status needs to be checked,
e.g. 'git status'.
So, I guess it would be better to extend a bit:
'...where a lazy parse could cause unexpected fatal, and result in a
performance regression...'
Thanks, yuchen
^ permalink raw reply
* [PATCH 4/4] doc: hook: don’t self-link via config include
From: kristofferhaugsbakk @ 2026-05-21 16:25 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, jn.avila, adrian.ratiu
In-Reply-To: <CV_doc_hook.6f0@msgid.xyz>
From: Kristoffer Haugsbakk <code@khaugsbakk.name>
Do not link to git-hook(1) from the config options when we already are
in that doc.
This implementation is similar to the updates to git-init(1) and
git-commit(1), implemented in [1] and [2], respectively.
† 1: e7b3a768 (doc: git-init: rework config item init.templateDir,
2024-03-10)
† 2: 819fdd6e (doc: convert git commit config to new format, 2025-01-15)
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
---
Documentation/config/hook.adoc | 19 +++++++++++++------
Documentation/git-hook.adoc | 1 +
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/Documentation/config/hook.adoc b/Documentation/config/hook.adoc
index a9dc0063c12..083dc60a132 100644
--- a/Documentation/config/hook.adoc
+++ b/Documentation/config/hook.adoc
@@ -1,10 +1,17 @@
+ifdef::git-hook[]
+:see-git-hook:
+endif::git-hook[]
+ifndef::git-hook[]
+:see-git-hook: See linkgit:git-hook[1].
+endif::git-hook[]
+
hook.<friendly-name>.command::
The command to execute for `hook.<friendly-name>`. `<friendly-name>`
is a unique name that identifies this hook. The hook events that
trigger the command are configured with `hook.<friendly-name>.event`.
The value can be an executable path or a shell oneliner. If more than
one value is specified for the same `<friendly-name>`, only the last
- value parsed is used. See linkgit:git-hook[1].
+ value parsed is used. {see-git-hook}
hook.<friendly-name>.event::
The hook events that trigger `hook.<friendly-name>`. The value is the
@@ -14,7 +21,7 @@ hook.<friendly-name>.event::
This is a multi-valued key. To run `hook.<friendly-name>` on multiple
events, specify the key more than once. An empty value resets
the list of events, clearing any previously defined events for
- `hook.<friendly-name>`. See linkgit:git-hook[1].
+ `hook.<friendly-name>`. {see-git-hook}
+
The `<friendly-name>` must not be the same as a known hook event name
(e.g. do not use `hook.pre-commit.event`). Using a known event name as
@@ -27,7 +34,7 @@ hook.<friendly-name>.enabled::
Set to `false` to disable the hook without removing its
configuration. This is particularly useful when a hook is defined
in a system or global config file and needs to be disabled for a
- specific repository. See linkgit:git-hook[1].
+ specific repository. {see-git-hook}
hook.<friendly-name>.parallel::
Whether the hook `hook.<friendly-name>` may run in parallel with other hooks
@@ -37,13 +44,13 @@ hook.<friendly-name>.parallel::
all hooks for that event run sequentially regardless of `hook.jobs`.
Only configured (named) hooks need to declare this. Traditional hooks
found in the hooks directory do not need to, and run in parallel when
- the effective job count is greater than 1. See linkgit:git-hook[1].
+ the effective job count is greater than 1. {see-git-hook}
hook.<event>.enabled::
Switch to enable or disable all hooks for the `<event>` hook event.
When set to `false`, no hooks fire for that event, regardless of any
per-hook `hook.<friendly-name>.enabled` settings. Defaults to `true`.
- See linkgit:git-hook[1].
+ {see-git-hook}
+
Note on naming: `<event>` must be the event name (e.g. `pre-commit`),
not a hook friendly-name. Since using a known event name as a
@@ -60,7 +67,7 @@ hook.<event>.jobs::
setting has no effect unless all configured hooks for the event have
`hook.<friendly-name>.parallel` set to `true`. Set to `-1` to use the
number of available CPU cores. Must be a positive integer or `-1`;
- zero is rejected with a warning. See linkgit:git-hook[1].
+ zero is rejected with a warning. {see-git-hook}
+
Note on naming: although this key resembles `hook.<friendly-name>.*`
(a per-hook setting), `<event>` must be the event name, not a hook
diff --git a/Documentation/git-hook.adoc b/Documentation/git-hook.adoc
index 750df58e58e..4868852aa0b 100644
--- a/Documentation/git-hook.adoc
+++ b/Documentation/git-hook.adoc
@@ -204,6 +204,7 @@ unintended and unsupported ways.
CONFIGURATION
-------------
+:git-hook: 1
include::config/hook.adoc[]
SEE ALSO
--
2.54.0.13.g9c7419e39f8
^ permalink raw reply related
* [PATCH 3/4] doc: config: include existing git-hook(1) section
From: kristofferhaugsbakk @ 2026-05-21 16:25 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, jn.avila, adrian.ratiu
In-Reply-To: <CV_doc_hook.6f0@msgid.xyz>
From: Kristoffer Haugsbakk <code@khaugsbakk.name>
It is already included in git-hook(1) but missing from git-config(1).
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
---
Documentation/config.adoc | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/config.adoc b/Documentation/config.adoc
index dcea3c0c15e..a80e7db46d9 100644
--- a/Documentation/config.adoc
+++ b/Documentation/config.adoc
@@ -451,6 +451,8 @@ include::config/guitool.adoc[]
include::config/help.adoc[]
+include::config/hook.adoc[]
+
include::config/http.adoc[]
include::config/i18n.adoc[]
--
2.54.0.13.g9c7419e39f8
^ permalink raw reply related
* [PATCH 2/4] doc: hook: consistently capitalize Git
From: kristofferhaugsbakk @ 2026-05-21 16:25 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, jn.avila, adrian.ratiu
In-Reply-To: <CV_doc_hook.6f0@msgid.xyz>
From: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
---
Documentation/git-hook.adoc | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Documentation/git-hook.adoc b/Documentation/git-hook.adoc
index 96c5c9c3c23..750df58e58e 100644
--- a/Documentation/git-hook.adoc
+++ b/Documentation/git-hook.adoc
@@ -3,7 +3,7 @@ git-hook(1)
NAME
----
-git-hook - Run git hooks
+git-hook - Run Git hooks
SYNOPSIS
--------
@@ -15,8 +15,8 @@ SYNOPSIS
DESCRIPTION
-----------
-A command interface for running git hooks (see linkgit:githooks[5]),
-for use by other scripted git commands.
+A command interface for running Git hooks (see linkgit:githooks[5]),
+for use by other scripted Git commands.
This command parses the default configuration files for sets of configs like
so:
@@ -161,7 +161,7 @@ setting, allowing all hooks for the event to run concurrently, even if they
are not individually marked as parallel.
+
Some hooks always run sequentially regardless of this flag or the
-`hook.jobs` config, because git knows they cannot safely run in parallel:
+`hook.jobs` config, because Git knows they cannot safely run in parallel:
`applypatch-msg`, `pre-commit`, `prepare-commit-msg`, `commit-msg`,
`post-commit`, `post-checkout`, and `push-to-checkout`.
--
2.54.0.13.g9c7419e39f8
^ permalink raw reply related
* [PATCH 1/4] doc: hook: remove stray backtick
From: kristofferhaugsbakk @ 2026-05-21 16:25 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, jn.avila, adrian.ratiu
In-Reply-To: <CV_doc_hook.6f0@msgid.xyz>
From: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
---
Documentation/git-hook.adoc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Documentation/git-hook.adoc b/Documentation/git-hook.adoc
index 46ea52db55f..96c5c9c3c23 100644
--- a/Documentation/git-hook.adoc
+++ b/Documentation/git-hook.adoc
@@ -41,7 +41,7 @@ spell-checker for your commit messages, you would write a configuration like so:
With this config, when you run 'git commit', first `~/bin/linter --cpp20` will
have a chance to check your files to be committed (during the `pre-commit` hook
-event`), and then `~/bin/spellchecker` will have a chance to check your commit
+event), and then `~/bin/spellchecker` will have a chance to check your commit
message (during the `commit-msg` hook event).
Commands are run in the order Git encounters their associated
--
2.54.0.13.g9c7419e39f8
^ permalink raw reply related
* [PATCH 0/4] doc: hook: small improvements
From: kristofferhaugsbakk @ 2026-05-21 16:25 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, jn.avila, adrian.ratiu
From: Kristoffer Haugsbakk <code@khaugsbakk.name>
Topic name: kh/doc-hook
Topic summary: Small improvements to git-hook(1) and the associated config.
[1/4] doc: hook: remove stray backtick
[2/4] doc: hook: consistently capitalize Git
[3/4] doc: config: include existing git-hook(1) section
[4/4] doc: hook: don’t self-link via config include
Documentation/config.adoc | 2 ++
Documentation/config/hook.adoc | 19 +++++++++++++------
Documentation/git-hook.adoc | 11 ++++++-----
3 files changed, 21 insertions(+), 11 deletions(-)
base-commit: aec3f587505a472db67e9462d0702e7d463a449d
--
2.54.0.13.g9c7419e39f8
^ permalink raw reply
* Re: [PATCH 03/18] odb/source-loose: start converting to a proper `struct odb_source`
From: Junio C Hamano @ 2026-05-21 15:49 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: git
In-Reply-To: <20260521-b4-pks-odb-source-loose-v1-3-6553b399be2d@pks.im>
Patrick Steinhardt <ps@pks.im> writes:
> Start converting `struct odb_source_loose` into a proper pluggable
> `struct odb_source` by embedding the base struct and assigning it the
> new `ODB_SOURCE_LOOSE` type. Furthermore, wire up lifecycle management
> of this source by implementing the `free` callback and taking ownership
> of the chdir notifications.
>
> Note that the loose source is not yet functional as a standalone `struct
> odb_source`, as it's missing all of the callback implementations. These
> will be wired up in subsequent commits.
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
> object-file.c | 17 -----------------
> object-file.h | 2 --
> odb/source-files.c | 2 +-
> odb/source-loose.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
> odb/source-loose.h | 14 ++++++++++++++
> odb/source.h | 3 +++
> 6 files changed, 63 insertions(+), 20 deletions(-)
>
> diff --git a/object-file.c b/object-file.c
> index 7a1908bfc0..977d959d33 100644
> --- a/object-file.c
> +++ b/object-file.c
> @@ -2041,14 +2041,6 @@ static struct oidtree *odb_source_loose_cache(struct odb_source *source,
> return files->loose->cache;
> }
>
> -static void odb_source_loose_clear_cache(struct odb_source_loose *loose)
> -{
> - oidtree_clear(loose->cache);
> - FREE_AND_NULL(loose->cache);
> - memset(&loose->subdir_seen, 0,
> - sizeof(loose->subdir_seen));
> -}
> -
> void odb_source_loose_reprepare(struct odb_source *source)
> {
> struct odb_source_files *files = odb_source_files_downcast(source);
> @@ -2205,15 +2197,6 @@ struct odb_transaction *odb_transaction_files_begin(struct odb_source *source)
> return &transaction->base;
> }
>
> -void odb_source_loose_free(struct odb_source_loose *loose)
> -{
> - if (!loose)
> - return;
> - odb_source_loose_clear_cache(loose);
> - loose_object_map_clear(&loose->map);
> - free(loose);
> -}
> -
> struct odb_loose_read_stream {
> struct odb_read_stream base;
> git_zstream z;
> diff --git a/object-file.h b/object-file.h
> index 1d8312cf7f..02c9680980 100644
> --- a/object-file.h
> +++ b/object-file.h
> @@ -21,8 +21,6 @@ struct object_info;
> struct odb_read_stream;
> struct odb_source;
>
> -void odb_source_loose_free(struct odb_source_loose *loose);
> -
> /* Reprepare the loose source by emptying the loose object cache. */
> void odb_source_loose_reprepare(struct odb_source *source);
>
> diff --git a/odb/source-files.c b/odb/source-files.c
> index 185cc6903e..ccc637311b 100644
> --- a/odb/source-files.c
> +++ b/odb/source-files.c
> @@ -27,7 +27,7 @@ static void odb_source_files_free(struct odb_source *source)
> {
> struct odb_source_files *files = odb_source_files_downcast(source);
> chdir_notify_unregister(NULL, odb_source_files_reparent, files);
> - odb_source_loose_free(files->loose);
> + odb_source_free(&files->loose->base);
> packfile_store_free(files->packed);
> odb_source_release(&files->base);
> free(files);
> diff --git a/odb/source-loose.c b/odb/source-loose.c
> index c9e7414814..92e18f5adb 100644
> --- a/odb/source-loose.c
> +++ b/odb/source-loose.c
> @@ -1,10 +1,55 @@
> #include "git-compat-util.h"
> +#include "abspath.h"
> +#include "chdir-notify.h"
> +#include "loose.h"
> +#include "odb.h"
> +#include "odb/source-files.h"
> #include "odb/source-loose.h"
> +#include "oidtree.h"
> +
> +void odb_source_loose_clear_cache(struct odb_source_loose *loose)
> +{
> + oidtree_clear(loose->cache);
> + FREE_AND_NULL(loose->cache);
> + memset(&loose->subdir_seen, 0,
> + sizeof(loose->subdir_seen));
> +}
> +
> +static void odb_source_loose_reparent(const char *name UNUSED,
> + const char *old_cwd,
> + const char *new_cwd,
> + void *cb_data)
> +{
> + struct odb_source_loose *loose = cb_data;
> + char *path = reparent_relative_path(old_cwd, new_cwd,
> + loose->base.path);
> + free(loose->base.path);
> + loose->base.path = path;
> +}
> +
> +static void odb_source_loose_free(struct odb_source *source)
> +{
> + struct odb_source_loose *loose = odb_source_loose_downcast(source);
> + odb_source_loose_clear_cache(loose);
> + loose_object_map_clear(&loose->map);
> + chdir_notify_unregister(NULL, odb_source_loose_reparent, loose);
> + odb_source_release(&loose->base);
> + free(loose);
> +}
>
> struct odb_source_loose *odb_source_loose_new(struct odb_source_files *files)
> {
> struct odb_source_loose *loose;
> +
> CALLOC_ARRAY(loose, 1);
> + odb_source_init(&loose->base, files->base.odb, ODB_SOURCE_LOOSE,
> + files->base.path, files->base.local);
> loose->files = files;
> +
> + loose->base.free = odb_source_loose_free;
> +
> + if (!is_absolute_path(loose->base.path))
> + chdir_notify_register(NULL, odb_source_loose_reparent, loose);
> +
> return loose;
> }
> diff --git a/odb/source-loose.h b/odb/source-loose.h
> index bf61e767c8..441da9e418 100644
> --- a/odb/source-loose.h
> +++ b/odb/source-loose.h
> @@ -12,6 +12,7 @@ struct oidtree;
> * file per object. This source is part of the files source.
> */
> struct odb_source_loose {
> + struct odb_source base;
> struct odb_source_files *files;
>
> /*
> @@ -32,4 +33,17 @@ struct odb_source_loose {
>
> struct odb_source_loose *odb_source_loose_new(struct odb_source_files *files);
>
> +/*
> + * Cast the given object database source to the loose backend. This will cause
> + * a BUG in case the source uses doesn't use this backend.
"uses doesn't use"???
> + */
> +static inline struct odb_source_loose *odb_source_loose_downcast(struct odb_source *source)
> +{
> + if (source->type != ODB_SOURCE_LOOSE)
> + BUG("trying to downcast source of type '%d' to loose", source->type);
> + return container_of(source, struct odb_source_loose, base);
> +}
> +
> +void odb_source_loose_clear_cache(struct odb_source_loose *loose);
> +
> #endif
> diff --git a/odb/source.h b/odb/source.h
> index 0a440884e4..8bcb67787e 100644
> --- a/odb/source.h
> +++ b/odb/source.h
> @@ -14,6 +14,9 @@ enum odb_source_type {
> /* The "files" backend that uses loose objects and packfiles. */
> ODB_SOURCE_FILES,
>
> + /* The "loose" backend that uses loose objects, only. */
> + ODB_SOURCE_LOOSE,
> +
> /* The "in-memory" backend that stores objects in memory. */
> ODB_SOURCE_INMEMORY,
> };
^ permalink raw reply
* Re: [PATCH 4/9] run-command: add support for timeout in command finisher
From: Johannes Sixt @ 2026-05-21 14:36 UTC (permalink / raw)
To: Siddh Raman Pant
Cc: git@vger.kernel.org, gitster@pobox.com, newren@gmail.com,
ps@pks.im, oswald.buddenhagen@gmx.de, code@khaugsbakk.name
In-Reply-To: <2f7eea03273ffaacc50a9ae186673da88fc3345f.camel@oracle.com>
Am 21.05.26 um 11:59 schrieb Siddh Raman Pant:
> The timeout is for the failure path, where the external helper has
> already stopped following that protocol or is blocked on something
> outside git's control. Since git starts the helper and puts it on the
> log/grep path, git also needs a bounded way to recover when that helper
> does not make progress. Otherwise an optional note source can prevent
> the main git command from completing.
That Git communicates with a process that looks like it stopped is the
normal case, for example:
- Output is sent to the pager. The user can take their time to study the
output. All the while, git waits patiently for the user to advance the
pager.
- Git fetch transfers large amounts of data across the network. Most of
the time it waits for data to arrive and does nothing. The peer process
looks like it hangs. Git does not decide to kill the connection at any
time. It is the user's decision to do so.
If the notes provider hangs, then it is not on Git to decide when it has
waited long enough.
-- Hannes
^ permalink raw reply
* Re: [PATCH v5 0/4] approxidate: tweak special date formats
From: Tuomas Ahola @ 2026-05-21 14:14 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Jeff King
In-Reply-To: <xmqqik8g28gw.fsf@gitster.g>
Junio C Hamano <gitster@pobox.com> wrote:
> Tuomas Ahola <taahol@utu.fi> writes:
>
> > -static void date_today(struct tm *tm, struct tm *now, int *num UNUSED)
> > +static void date_today(struct tm *tm, struct tm *now, int *num)
> > {
> > if (tm->tm_hour == now->tm_hour &&
> > tm->tm_min == now->tm_min &&
> > tm->tm_sec == now->tm_sec)
> > date_time(tm, 0);
> > + *num = 0;
> > tm->tm_mday = -1;
> > update_tm(tm, now, 0);
> > }
>
> Hmph, what is this change about? Does the lack of this clearing
> break some test?
>
As you can see, many other date_*() functions have that same assignment, too.
It looked a bit off, so I first left it out, but this revision does add a
corner case test[*] that would fail without it.
> In any case, will queue. It seems that we are getting to the point
> of diminishing returns and better off declaring victory soonish?
>
Yes, I agree. The patch series is effectively finished as I don't have any
further itches or ideas. And I think the series gets its work done quite well
actually.
> > +check_approxidate 'January 5th today pm' '2009-01-30 12:00:00'
[*] Namely, this one.
^ permalink raw reply
* Re: [PATCH v11] checkout: extend --track with a "fetch" mode to refresh start-point
From: Phillip Wood @ 2026-05-21 14:06 UTC (permalink / raw)
To: Junio C Hamano
Cc: Harald Nordgren via GitGitGadget, git, Ramsay Jones,
D. Ben Knoble, Kristoffer Haugsbakk, Marc Branchaud,
Harald Nordgren
In-Reply-To: <xmqqtss02a2o.fsf@gitster.g>
On 21/05/2026 13:58, Junio C Hamano wrote:
> Phillip Wood <phillip.wood123@gmail.com> writes:
>
>>> One. Have you considered the case where the remote-tracking refs
>>> are overlapping, e.g., where "origin" and "upstream" point at
>>> different URLs but they both store in "refs/remotes/upstream/*"?
>>> Perhaps their URLs may textually be different but are pointing
>>> logically at the same place (e.g., one ssh:// the other https:// for
>>> example).
>>>
>>> What should happen? What does happen after you apply this patch?
>>
>> It would be worth looking at what "git checkout --track" does in that
>> case and seeing if we can share the code.
>
> It always is a good idea to think how we can share code for
> different purposes to solve a new problem, but in this particular
> one, I am not sure if "git checkout -t -b topic upstream/main"
> codepath has much to offer to solve what the new "before the
> checkout, update from the remote" feature wants to do. To the
> former, it does not matter how refs/remotes/upstream/* are updated
> and by fetching which remote at all.
Don't we want to avoid creating a branch with an ambiguous upstream so
that a subsequent "git pull" works though? Looking at
branch.c:setup_tracking() it seems to reject upstream branches that
match more than one remote.
Thanks
Phillip
> The only thing it cares about
> is to leave the record that this new "topic" branch works with
> refs/remotes/upstrea/main. But the latter needs to be able to
> compute which remote it should fetch from. It is a problem that
> existing code had no need to solve.
>
^ permalink raw reply
* [PATCH v4] remote: qualify "git pull" advice for non-upstream compareBranches
From: Harald Nordgren via GitGitGadget @ 2026-05-21 14:06 UTC (permalink / raw)
To: git; +Cc: Harald Nordgren, Harald Nordgren
In-Reply-To: <pull.2301.v3.git.git.1779282625696.gitgitgadget@gmail.com>
From: Harald Nordgren <haraldnordgren@gmail.com>
Enable ENABLE_ADVICE_PULL for push-branch comparisons too, not just
the upstream entry, so the "use git pull" hint prints when the local
branch is behind its push branch.
Spell out "git pull <remote> <branch>" so running the suggested
command actually pulls the ref the user was told about; plain
"git pull" would fetch the upstream instead.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>
---
remote: qualify "git pull" advice for non-upstream branches
* Don't suggest git pull when we have no good command to suggest.
* New test for this. Asserts the behind line shows with no follow-up
advice.
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2301%2FHaraldNordgren%2Fstatus-pull-advice-qualified-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2301/HaraldNordgren/status-pull-advice-qualified-v4
Pull-Request: https://github.com/git/git/pull/2301
Range-diff vs v3:
1: 3703be9aac ! 1: ef54dacb07 remote: qualify "git pull" advice for non-upstream compareBranches
@@ remote.c: int format_tracking_info(struct branch *branch, struct strbuf *sb,
full_ref = resolve_compare_branch(branch,
branches.items[i].string);
@@ remote.c: int format_tracking_info(struct branch *branch, struct strbuf *sb,
- if (reported)
- strbuf_addstr(sb, "\n");
-- if (is_upstream)
-+ if (is_upstream || is_push)
+ if (is_upstream)
flags |= ENABLE_ADVICE_PULL;
- if (is_push)
- flags |= ENABLE_ADVICE_PUSH;
@@ remote.c: int format_tracking_info(struct branch *branch, struct strbuf *sb,
+ if (push_remote_name &&
+ skip_prefix(full_ref, "refs/remotes/", &push_branch_name) &&
+ skip_prefix(push_branch_name, push_remote_name, &push_branch_name) &&
-+ *push_branch_name == '/')
++ *push_branch_name == '/') {
+ push_branch_name++;
-+ else
++ flags |= ENABLE_ADVICE_PULL;
++ } else {
+ push_remote_name = NULL;
++ }
++ } else {
++ flags |= ENABLE_ADVICE_PULL;
+ }
+ }
format_branch_comparison(sb, !cmp, ours, theirs, short_ref,
@@ t/t6040-tracking-info.sh: test_expect_success 'status.compareBranches with remap
+ EOF
+ test_cmp expect actual
+'
++
++test_expect_success 'status.compareBranches suppresses advice when push tracking ref is unconventional' '
++ test_config -C test push.default current &&
++ test_config -C test remote.imported.url ../. &&
++ test_config -C test remote.imported.fetch "+refs/heads/*:refs/imported/imported/*" &&
++ test_config -C test branch.feature17.pushRemote imported &&
++ test_config -C test status.compareBranches "@{push}" &&
++ git -C test fetch imported &&
++ git -C test checkout --no-track -b feature17 refs/imported/imported/main &&
++ (cd test && advance work17) &&
++ git -C test push imported HEAD:feature17 &&
++ git -C test fetch imported &&
++ git -C test reset --hard HEAD^ &&
++ git -C test status >actual &&
++ cat >expect <<-EOF &&
++ On branch feature17
++ Your branch is behind ${SQ}imported/imported/feature17${SQ} by 1 commit, and can be fast-forwarded.
++
++ nothing to commit, working tree clean
++ EOF
++ test_cmp expect actual
++'
+
test_done
remote.c | 48 +++++++++++++++----
t/t6040-tracking-info.sh | 100 +++++++++++++++++++++++++++++++++++++++
2 files changed, 140 insertions(+), 8 deletions(-)
diff --git a/remote.c b/remote.c
index 24a8118d25..193e1dd1f1 100644
--- a/remote.c
+++ b/remote.c
@@ -2268,6 +2268,8 @@ static void format_branch_comparison(struct strbuf *sb,
bool up_to_date,
int ours, int theirs,
const char *branch_name,
+ const char *push_remote_name,
+ const char *push_branch_name,
enum ahead_behind_flags abf,
unsigned flags)
{
@@ -2303,9 +2305,15 @@ static void format_branch_comparison(struct strbuf *sb,
"and can be fast-forwarded.\n",
theirs),
branch_name, theirs);
- if (use_pull_advice && advice_enabled(ADVICE_STATUS_HINTS))
- strbuf_addstr(sb,
- _(" (use \"git pull\" to update your local branch)\n"));
+ if (use_pull_advice && advice_enabled(ADVICE_STATUS_HINTS)) {
+ if (push_remote_name && push_branch_name)
+ strbuf_addf(sb,
+ _(" (use \"git pull %s %s\" to update your local branch)\n"),
+ push_remote_name, push_branch_name);
+ else
+ strbuf_addstr(sb,
+ _(" (use \"git pull\" to update your local branch)\n"));
+ }
} else {
strbuf_addf(sb,
Q_("Your branch and '%s' have diverged,\n"
@@ -2316,9 +2324,15 @@ static void format_branch_comparison(struct strbuf *sb,
"respectively.\n",
ours + theirs),
branch_name, ours, theirs);
- if (use_divergence_advice && advice_enabled(ADVICE_STATUS_HINTS))
- strbuf_addstr(sb,
- _(" (use \"git pull\" if you want to integrate the remote branch with yours)\n"));
+ if (use_divergence_advice && advice_enabled(ADVICE_STATUS_HINTS)) {
+ if (push_remote_name && push_branch_name)
+ strbuf_addf(sb,
+ _(" (use \"git pull %s %s\" if you want to integrate the remote branch with yours)\n"),
+ push_remote_name, push_branch_name);
+ else
+ strbuf_addstr(sb,
+ _(" (use \"git pull\" if you want to integrate the remote branch with yours)\n"));
+ }
}
}
@@ -2356,6 +2370,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
int ours, theirs, cmp;
int is_upstream, is_push;
unsigned flags = 0;
+ const char *push_remote_name = NULL;
+ const char *push_branch_name = NULL;
full_ref = resolve_compare_branch(branch,
branches.items[i].string);
@@ -2399,11 +2415,27 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
if (is_upstream)
flags |= ENABLE_ADVICE_PULL;
- if (is_push)
- flags |= ENABLE_ADVICE_PUSH;
if (show_divergence_advice && is_upstream)
flags |= ENABLE_ADVICE_DIVERGENCE;
+ if (is_push) {
+ flags |= ENABLE_ADVICE_PUSH;
+ if (!upstream_ref || strcmp(upstream_ref, full_ref)) {
+ push_remote_name = pushremote_for_branch(branch, NULL);
+ if (push_remote_name &&
+ skip_prefix(full_ref, "refs/remotes/", &push_branch_name) &&
+ skip_prefix(push_branch_name, push_remote_name, &push_branch_name) &&
+ *push_branch_name == '/') {
+ push_branch_name++;
+ flags |= ENABLE_ADVICE_PULL;
+ } else {
+ push_remote_name = NULL;
+ }
+ } else {
+ flags |= ENABLE_ADVICE_PULL;
+ }
+ }
format_branch_comparison(sb, !cmp, ours, theirs, short_ref,
+ push_remote_name, push_branch_name,
abf, flags);
reported = 1;
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index 0242b5bf7a..91cbb8775d 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -646,4 +646,104 @@ test_expect_success 'status.compareBranches with remapped push and upstream remo
test_cmp expect actual
'
+test_expect_success 'status.compareBranches behind both upstream and push' '
+ test_config -C test push.default current &&
+ test_config -C test remote.pushDefault origin &&
+ test_config -C test status.compareBranches "@{upstream} @{push}" &&
+ git -C test checkout -b feature13 upstream/main &&
+ (cd test && advance work13) &&
+ git -C test push origin &&
+ git -C test branch --set-upstream-to upstream/ahead &&
+ git -C test reset --hard HEAD^ &&
+ git -C test status >actual &&
+ cat >expect <<-EOF &&
+ On branch feature13
+ Your branch is behind ${SQ}upstream/ahead${SQ} by 1 commit, and can be fast-forwarded.
+ (use "git pull" to update your local branch)
+
+ Your branch is behind ${SQ}origin/feature13${SQ} by 1 commit, and can be fast-forwarded.
+ (use "git pull origin feature13" to update your local branch)
+
+ nothing to commit, working tree clean
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'status.compareBranches with remapped push and behind push branch' '
+ test_config -C test remote.pushDefault origin &&
+ test_config -C test remote.origin.push refs/heads/feature14:refs/heads/remapped14 &&
+ test_config -C test status.compareBranches "@{push}" &&
+ git -C test checkout -b feature14 upstream/main &&
+ (cd test && advance work14) &&
+ git -C test push &&
+ git -C test reset --hard HEAD^ &&
+ git -C test status >actual &&
+ cat >expect <<-EOF &&
+ On branch feature14
+ Your branch is behind ${SQ}origin/remapped14${SQ} by 1 commit, and can be fast-forwarded.
+ (use "git pull origin remapped14" to update your local branch)
+
+ nothing to commit, working tree clean
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'status.compareBranches with behind push branch and no upstream' '
+ test_config -C test push.default current &&
+ test_config -C test remote.pushDefault origin &&
+ test_config -C test status.compareBranches "@{push}" &&
+ git -C test checkout --no-track -b feature15 upstream/main &&
+ (cd test && advance work15) &&
+ git -C test push origin &&
+ git -C test reset --hard HEAD^ &&
+ git -C test status >actual &&
+ cat >expect <<-EOF &&
+ On branch feature15
+ Your branch is behind ${SQ}origin/feature15${SQ} by 1 commit, and can be fast-forwarded.
+ (use "git pull origin feature15" to update your local branch)
+
+ nothing to commit, working tree clean
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'status.compareBranches behind upstream-equals-push suggests plain pull' '
+ test_config -C test status.compareBranches "@{upstream} @{push}" &&
+ git -C test checkout -b feature16 origin/main &&
+ (cd test && advance work16) &&
+ git -C test push origin HEAD:main &&
+ git -C test reset --hard HEAD^ &&
+ git -C test status >actual &&
+ cat >expect <<-EOF &&
+ On branch feature16
+ Your branch is behind ${SQ}origin/main${SQ} by 1 commit, and can be fast-forwarded.
+ (use "git pull" to update your local branch)
+
+ nothing to commit, working tree clean
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'status.compareBranches suppresses advice when push tracking ref is unconventional' '
+ test_config -C test push.default current &&
+ test_config -C test remote.imported.url ../. &&
+ test_config -C test remote.imported.fetch "+refs/heads/*:refs/imported/imported/*" &&
+ test_config -C test branch.feature17.pushRemote imported &&
+ test_config -C test status.compareBranches "@{push}" &&
+ git -C test fetch imported &&
+ git -C test checkout --no-track -b feature17 refs/imported/imported/main &&
+ (cd test && advance work17) &&
+ git -C test push imported HEAD:feature17 &&
+ git -C test fetch imported &&
+ git -C test reset --hard HEAD^ &&
+ git -C test status >actual &&
+ cat >expect <<-EOF &&
+ On branch feature17
+ Your branch is behind ${SQ}imported/imported/feature17${SQ} by 1 commit, and can be fast-forwarded.
+
+ nothing to commit, working tree clean
+ EOF
+ test_cmp expect actual
+'
+
test_done
base-commit: aec3f587505a472db67e9462d0702e7d463a449d
--
gitgitgadget
^ permalink raw reply related
* Re: [PATCH v3] git-jump: pick a mode automatically when invoked without arguments
From: Junio C Hamano @ 2026-05-21 14:00 UTC (permalink / raw)
To: Greg Hurrell via GitGitGadget
Cc: git, Jeff King, Greg Hurrell, Erik Cervin Edin, Greg Hurrell
In-Reply-To: <pull.2108.v3.git.1779371110195.gitgitgadget@gmail.com>
"Greg Hurrell via GitGitGadget" <gitgitgadget@gmail.com> writes:
> * Removed stray # from README.
> * Don't both teaching "auto" to select "ws" mode, because it is always
> subsumed by "diff".
> * Update usage string to make clear that git jump --stdout foo is not a
> synonym for git jump --stdout auto foo, because distinguishing
> between foo as <mode> and foo as <arg> is fraught with ambiguity.
>
> In answer to Junio's question:
>
> > If more than one interesting cases apply, what happens, and what
> > should happen?
>
> it's an ordered choice (merge > diff).
After 'diff --quiet "$@"' says "nothing interesting between the
index and the working tree", I actually think it may be worth using
either 'git diff --check HEAD "$@"' or 'git diff --cached --check "$@"'
to see if ws fix is needed.
But I am not a target audience of this feature, so I'll let others
figure out what to do here.
^ permalink raw reply
* [PATCH v3] git-jump: pick a mode automatically when invoked without arguments
From: Greg Hurrell via GitGitGadget @ 2026-05-21 13:45 UTC (permalink / raw)
To: git
Cc: Jeff King, Greg Hurrell, Erik Cervin Edin, Junio C Hamano,
Greg Hurrell, Greg Hurrell
In-Reply-To: <pull.2108.v2.git.1779280307112.gitgitgadget@gmail.com>
From: Greg Hurrell <greg.hurrell@datadoghq.com>
When `git jump` is invoked with no positional arguments (and no
arguments after `--stdout`) it currently prints usage and exits with
status 1.
But there are two situations where we can usefully infer the most
valuable and likely mode that a user would want to use, and select it
automatically:
1. When there are unmerged paths in the index, the user likely
wants `git jump merge`.
2. When the working tree has unstaged changes, the user likely
wants `git jump diff`.
In this commit we teach `git jump` a new "auto" mode which detects these
cases and dispatches to the corresponding mode automatically. The user
can either explicitly spell out `git jump auto`, or just leave it at
`git jump` (because "auto" is the default).
If none of the interesting cases listed above applies, then auto mode
falls back to the existing usage-and-exit behavior.
Signed-off-by: Greg Hurrell <greg.hurrell@datadoghq.com>
---
git-jump: pick a mode automatically when invoked without arguments
Changes since v2; all of these in response to feedback from Junio:
* Removed stray # from README.
* Don't both teaching "auto" to select "ws" mode, because it is always
subsumed by "diff".
* Update usage string to make clear that git jump --stdout foo is not a
synonym for git jump --stdout auto foo, because distinguishing
between foo as <mode> and foo as <arg> is fraught with ambiguity.
In answer to Junio's question:
> If more than one interesting cases apply, what happens, and what
> should happen?
it's an ordered choice (merge > diff).
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2108%2Fwincent%2Fauto-jump-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2108/wincent/auto-jump-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/2108
Range-diff vs v2:
1: 5fbc8480ef ! 1: af758dcfd2 git-jump: pick a mode automatically when invoked without arguments
@@ Commit message
arguments after `--stdout`) it currently prints usage and exits with
status 1.
- But there are several situations where we can usefully infer the most
+ But there are two situations where we can usefully infer the most
valuable and likely mode that a user would want to use, and select it
automatically:
@@ Commit message
2. When the working tree has unstaged changes, the user likely
wants `git jump diff`.
- 3. In the presence of conflict markers or whitespace errors (as reported
- by `git diff --check`), the user likely wants `git jump ws`.
-
In this commit we teach `git jump` a new "auto" mode which detects these
cases and dispatches to the corresponding mode automatically. The user
can either explicitly spell out `git jump auto`, or just leave it at
@@ contrib/git-jump/README: git jump grep foo_bar
git jump grep -i foo_bar
+# jump to places with conflict markers or whitespace errors
-+# (as reported by # `git diff --check`)
++# (as reported by `git diff --check`)
+git jump ws
+
# use the silver searcher for git jump grep
@@ contrib/git-jump/README: git jump grep foo_bar
+# whitespace problems; otherwise show usage
+git jump auto
+
-+# with no explicit mode, same as "auto"
++# with no explicit mode and no args, same as "auto"
+git jump
--------------------------------------------------
@@ contrib/git-jump/README: git jump grep foo_bar
## contrib/git-jump/git-jump ##
@@
-
usage() {
cat <<\EOF
--usage: git jump [--stdout] <mode> [<args>]
-+usage: git jump [--stdout] [<mode>] [<args>]
+ usage: git jump [--stdout] <mode> [<args>]
++ or: git jump [--stdout]
Jump to interesting elements in an editor.
-The <mode> parameter is one of:
-+The <mode> parameter is one of the following,
-+defaulting to "auto" if omitted:
++The <mode> parameter is one of the following.
++With no <mode> and no <args>, it defaults to "auto".
diff: elements are diff hunks. Arguments are given to diff.
@@ contrib/git-jump/git-jump: mode_ws() {
+ mode_merge "$@"
+ elif ! git diff --quiet "$@"; then
+ mode_diff "$@"
-+ elif ! git diff --check >/dev/null 2>&1; then
-+ mode_ws "$@"
+ else
+ usage >&2
+ exit 1
contrib/git-jump/README | 12 ++++++++++++
contrib/git-jump/git-jump | 26 +++++++++++++++++++++++---
2 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/contrib/git-jump/README b/contrib/git-jump/README
index 3211841305..aabec4a756 100644
--- a/contrib/git-jump/README
+++ b/contrib/git-jump/README
@@ -75,8 +75,20 @@ git jump grep foo_bar
# arbitrary grep options
git jump grep -i foo_bar
+# jump to places with conflict markers or whitespace errors
+# (as reported by `git diff --check`)
+git jump ws
+
# use the silver searcher for git jump grep
git config jump.grepCmd "ag --column"
+
+# pick a mode automatically: "merge" if there are unmerged paths,
+# "diff" if the worktree has unstaged changes, "ws" if there are
+# whitespace problems; otherwise show usage
+git jump auto
+
+# with no explicit mode and no args, same as "auto"
+git jump
--------------------------------------------------
You can use the optional argument '--stdout' to print the listing to
diff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump
index 8d1d5d79a6..79286d8112 100755
--- a/contrib/git-jump/git-jump
+++ b/contrib/git-jump/git-jump
@@ -3,9 +3,11 @@
usage() {
cat <<\EOF
usage: git jump [--stdout] <mode> [<args>]
+ or: git jump [--stdout]
Jump to interesting elements in an editor.
-The <mode> parameter is one of:
+The <mode> parameter is one of the following.
+With no <mode> and no <args>, it defaults to "auto".
diff: elements are diff hunks. Arguments are given to diff.
@@ -16,6 +18,10 @@ grep: elements are grep hits. Arguments are given to git grep or, if
ws: elements are whitespace errors. Arguments are given to diff --check.
+auto: select one of the other modes based on worktree state;
+ "merge" if there are unmerged paths, "diff" if there are
+ unstaged changes, "ws" if there are whitespace errors.
+
If the optional argument `--stdout` is given, print the quickfix
lines to standard output instead of feeding it to the editor.
EOF
@@ -82,6 +88,21 @@ mode_ws() {
git diff --check "$@"
}
+mode_auto() {
+ if test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" != "true"; then
+ usage >&2
+ exit 1
+ fi
+ if test -n "$(git ls-files -u "$@")"; then
+ mode_merge "$@"
+ elif ! git diff --quiet "$@"; then
+ mode_diff "$@"
+ else
+ usage >&2
+ exit 1
+ fi
+}
+
use_stdout=
while test $# -gt 0; do
case "$1" in
@@ -99,8 +120,7 @@ while test $# -gt 0; do
shift
done
if test $# -lt 1; then
- usage >&2
- exit 1
+ set -- auto
fi
mode=$1; shift
type "mode_$mode" >/dev/null 2>&1 || { usage >&2; exit 1; }
base-commit: aec3f587505a472db67e9462d0702e7d463a449d
--
gitgitgadget
^ permalink raw reply related
* Re: [PATCH v5 0/4] approxidate: tweak special date formats
From: Junio C Hamano @ 2026-05-21 13:33 UTC (permalink / raw)
To: Tuomas Ahola; +Cc: git, Jeff King
In-Reply-To: <20260521105408.8222-1-taahol@utu.fi>
Tuomas Ahola <taahol@utu.fi> writes:
> -static void date_today(struct tm *tm, struct tm *now, int *num UNUSED)
> +static void date_today(struct tm *tm, struct tm *now, int *num)
> {
> if (tm->tm_hour == now->tm_hour &&
> tm->tm_min == now->tm_min &&
> tm->tm_sec == now->tm_sec)
> date_time(tm, 0);
> + *num = 0;
> tm->tm_mday = -1;
> update_tm(tm, now, 0);
> }
Hmph, what is this change about? Does the lack of this clearing
break some test?
In any case, will queue. It seems that we are getting to the point
of diminishing returns and better off declaring victory soonish?
> diff --git a/t/t0006-date.sh b/t/t0006-date.sh
> index b187b1bfc4..9a76b84ed9 100755
> --- a/t/t0006-date.sh
> +++ b/t/t0006-date.sh
> @@ -212,13 +212,14 @@ check_approxidate 'noon today' '2009-08-30 12:00:00'
> check_approxidate 'today at noon' '2009-08-30 12:00:00' '-12 hours'
> check_approxidate 'noon today' '2009-09-01 12:00:00' '+36 hours'
> check_approxidate 'noon yesterday' '2009-08-29 12:00:00'
> +check_approxidate 'noon yesterday' '2009-08-29 12:00:00' '-12 hours'
> check_approxidate 'last Friday at noon' '2009-08-28 12:00:00'
> check_approxidate 'last Friday at noon' '2009-08-28 12:00:00' '-12 hours'
> -check_approxidate 'noon yesterday' '2009-08-29 12:00:00' '-12 hours'
> check_approxidate 'tea last saturday' '2009-08-29 17:00:00'
> check_approxidate 'tea last saturday' '2009-08-29 17:00:00' '-12 hours'
> check_approxidate 'January 5th noon pm' '2009-01-05 12:00:00'
> check_approxidate 'January 5th noon pm' '2009-01-05 12:00:00' '-12 hours'
> +check_approxidate 'January 5th today pm' '2009-01-30 12:00:00'
> check_approxidate '10am noon' '2009-08-29 12:00:00'
> check_approxidate 'January 5th yesterday' '2009-01-29 19:20:00'
> check_approxidate 'January 5th yesterday' '2008-12-31 19:20:00' '+2 days'
>
> base-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0
^ permalink raw reply
* Re: [PATCH v9 3/5] branch: add --prune-merged <remote>
From: Junio C Hamano @ 2026-05-21 13:29 UTC (permalink / raw)
To: Phillip Wood
Cc: Harald Nordgren via GitGitGadget, git, Kristoffer Haugsbakk,
Johannes Sixt, Harald Nordgren
In-Reply-To: <6501a3d5-a5ec-421b-8526-ee7d4ae5ea98@gmail.com>
Phillip Wood <phillip.wood123@gmail.com> writes:
> I think being able to prune branches that have been merged into their
> upstream is a good idea. However, I find the focus on remotes rather
> than upstream branches in the UI a bit confusing. While the upstream of
> a branch is often a remote tracking branch it doesn't have to be. For my
> personal projects I often do
>
> git checkout -b topic master
>
> and it would be nice to be able to run
>
> git branch --prune-merged master
>
> to clean up those topics that have been merged.
Excellent suggestion.
The task at hand is to make a list of things that "track" (in the
"checkout -t" sense) something, see which one in that list are
descendant of that something, and removing those that have already
been merged into that something. There is nothing that requires
that something to be a remote-tracking branch at all.
If
git branch --forked master
(i.e., "who tracks 'master' in the 'checkout -t' sense") were
available, then
git branch --merged master | sort >1
git branch --forked master | sort >2
comm -12 1 2
would give us the list of branches that forked from 'master' and
have already been merged, i.e., candidate to be removed via the
"prune-merged" mechanism. With the built-in "git branch -d"
protection to require capital "-D" to force removal of a new work
that is not merged to tracked, we actually need only
git branch --forked master |
xargs git branch -d
to do so. We may want to give --dry-run to "git branch -d" so that
you can say
git branch --forked master |
xargs git branch -d --dry-run
to see what would be removed.
And again, there is no strong reason why "--forked" has to work only
with remote-tracking branches.
> Similarly I think it is
> confusing that
>
> git checkout -b topic origin
>
> starts a branch from the default branch on origin, but if I run
>
> git branch --prune-merged origin
Sorry, this was my bad. I agree that it is not a useful thing for
"origin" to mean "origin/*" here when it is established that
"origin" to mean "origin/HEAD".
^ permalink raw reply
* Re: [PATCH v11] checkout: extend --track with a "fetch" mode to refresh start-point
From: Junio C Hamano @ 2026-05-21 12:58 UTC (permalink / raw)
To: Phillip Wood
Cc: Harald Nordgren via GitGitGadget, git, Ramsay Jones,
D. Ben Knoble, Kristoffer Haugsbakk, Marc Branchaud,
Harald Nordgren
In-Reply-To: <b8932b27-8006-4b43-b7e5-1fac0fbf42c7@gmail.com>
Phillip Wood <phillip.wood123@gmail.com> writes:
>> One. Have you considered the case where the remote-tracking refs
>> are overlapping, e.g., where "origin" and "upstream" point at
>> different URLs but they both store in "refs/remotes/upstream/*"?
>> Perhaps their URLs may textually be different but are pointing
>> logically at the same place (e.g., one ssh:// the other https:// for
>> example).
>>
>> What should happen? What does happen after you apply this patch?
>
> It would be worth looking at what "git checkout --track" does in that
> case and seeing if we can share the code.
It always is a good idea to think how we can share code for
different purposes to solve a new problem, but in this particular
one, I am not sure if "git checkout -t -b topic upstream/main"
codepath has much to offer to solve what the new "before the
checkout, update from the remote" feature wants to do. To the
former, it does not matter how refs/remotes/upstream/* are updated
and by fetching which remote at all. The only thing it cares about
is to leave the record that this new "topic" branch works with
refs/remotes/upstrea/main. But the latter needs to be able to
compute which remote it should fetch from. It is a problem that
existing code had no need to solve.
^ permalink raw reply
* Re: [PATCH v9 3/5] branch: add --prune-merged <remote>
From: Harald Nordgren @ 2026-05-21 12:37 UTC (permalink / raw)
To: phillip.wood
Cc: Harald Nordgren via GitGitGadget, git, Kristoffer Haugsbakk,
Johannes Sixt
In-Reply-To: <6501a3d5-a5ec-421b-8526-ee7d4ae5ea98@gmail.com>
> I think being able to prune branches that have been merged into their
> upstream is a good idea. However, I find the focus on remotes rather
> than upstream branches in the UI a bit confusing. While the upstream of
> a branch is often a remote tracking branch it doesn't have to be. For my
> personal projects I often do
>
> git checkout -b topic master
>
> and it would be nice to be able to run
>
> git branch --prune-merged master
>
> to clean up those topics that have been merged. Similarly I think it is
> confusing that
>
> git checkout -b topic origin
>
> starts a branch from the default branch on origin, but if I run
>
> git branch --prune-merged origin
>
> to clean it up, it will clean up all the branches with an upstream on
> origin, not just those whose upstream matches origin/HEAD.
>
> So I like the idea, but would prefer the arguments to --prune-merged to
> be upstream branches, not remotes. We could support globs so that
>
> git branch --prune-merges 'origin/*'
>
> would clean up all the branches whose upstream is on origin if that is
> useful.
>
> Thanks
>
> Phillip
Hi Phillip!
This seems like a big change. It almost becomes a different feature.
Would be interesting to hear what others have to say as well.
Harald
^ permalink raw reply
* Re: [PATCH v4 2/2] config: add "worktree" and "worktree/i" includeIf conditions
From: Patrick Steinhardt @ 2026-05-21 12:09 UTC (permalink / raw)
To: me; +Cc: git, Kristoffer Haugsbakk, Junio C Hamano, Phillip Wood
In-Reply-To: <20260513-includeif-worktree-v4-2-f8e6212d1fba@black-desk.cn>
On Wed, May 13, 2026 at 04:08:18PM +0800, Chen Linxuan via B4 Relay wrote:
> diff --git a/Documentation/config.adoc b/Documentation/config.adoc
> index 62eebe7c5450..6299b1e3a019 100644
> --- a/Documentation/config.adoc
> +++ b/Documentation/config.adoc
> @@ -146,6 +146,46 @@ refer to linkgit:gitignore[5] for details. For convenience:
> This is the same as `gitdir` except that matching is done
> case-insensitively (e.g. on case-insensitive file systems)
>
> +`worktree`::
> + The data that follows the keyword `worktree` and a colon is used as a
> + glob pattern. If the working directory of the current worktree matches
> + the pattern, the include condition is met.
> ++
> +The worktree location is the path where files are checked out (as returned
> +by `git rev-parse --show-toplevel`). This is different from `gitdir`, which
> +matches the `.git` directory path. In a linked worktree, the worktree path
> +is the directory where that worktree's files are located, not the main
> +repository's `.git` directory.
Nit: I feel like the first sentence already says it all, and the
remainder is not adding much value. But I'm probably also quite biased
given that I'm familiar with interals, so I don't insist on any change
here.
[snip]
> +While `extensions.worktreeConfig` (see linkgit:git-worktree[1]) also supports
> +per-worktree configuration, it stores the config inside each repository's
> +`.git/config.worktree` file and requires running `git config --worktree`
> +inside each worktree individually. In contrast, `includeIf "worktree:..."`
> +can be set once in a global or system-level configuration file (e.g.
> +`~/.config/git/config`) and applies to all repositories at once based on
> +their worktree location.
Nit: I tihnk saying "global or system-level" is totally sufficient,
there really is no need to explain where those files live.
But again, I'm not sure whether we need a new version for this change.
> diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh
> index 6e51f892f320..07b6fb649cd2 100755
> --- a/t/t1305-config-include.sh
> +++ b/t/t1305-config-include.sh
> @@ -396,4 +396,117 @@ test_expect_success 'onbranch without repository but explicit nonexistent Git di
[snip]
> +test_expect_success 'conditional include, worktree, icase' '
> + git init wt-icase &&
> + (
> + cd wt-icase &&
> + test_commit initial &&
> + wt_path="$(pwd)" &&
> + wt_upper=$(echo "$wt_path" | tr a-z A-Z) &&
> + echo "[includeIf \"worktree/i:$wt_upper\"]path=icase-inc" >>.git/config &&
> + echo "[test]wticase=1" >.git/icase-inc &&
> + echo 1 >expect &&
> + git config test.wticase >actual &&
> + test_cmp expect actual
> + )
> +'
Ah, one more thing I didn't notice for the last version: it's good that
we have a check for the case-insensitive behaviour, but we're missing a
test that verifies that we're in fact case-sensitive by default. That
test would of course not work with a case-insensitive filesystem, but we
can depend on the `!CASE_INSENSITIVE_FS` prerequisite for that.
Other than that this series looks good to me, thanks!
Patrick
^ permalink raw reply
* Re: [PATCH] http: handle absolute-path alternates from server root
From: Patrick Steinhardt @ 2026-05-21 11:50 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, git, slonkazoid
In-Reply-To: <20260515170134.GC88375@coredump.intra.peff.net>
On Fri, May 15, 2026 at 01:01:34PM -0400, Jeff King wrote:
> On Fri, May 15, 2026 at 09:41:06AM +0200, Patrick Steinhardt wrote:
>
> > > We talked about dropping it a few years ago, but Eric countered that
> > > dumb clones are easier on the server in some cases (like gigantic
> > > public-inbox repos that are packed to keep most of the old history in
> > > one big pack that is never updated). The verbatim pack-reuse feature
> > > tries to get smart clones closer to that, but it's hard to beat serving
> > > a static file from the server's perspective. I haven't measured anything
> > > in that area in a while, though.
> >
> > In theory we can get much closer with packfile URIs, too, can't we? If
> > the packfiles are directly accessible anyway the server could just
> > announce these directly and have the client fetch them. That should
> > significantly reduce the load on the server even further.
>
> Packfile URIs help with the actual pack generation (even if we're
> blitting out bits from the disk with verbatim packfile reuse, we still
> have to handle gaps and compute the checksum over the output pack).
>
> But it doesn't help with the server computing the set of objects the
> client needs in the first place. IIRC, packfile URIs work by the server
> saying "oh, I was going to send you object XYZ, but you can get it from
> this stable pack instead". So the server still has to compute the set of
> objects (and send any that are not mentioned in URI packs). Bitmaps
> help, but there's still non-trivial computation and storage on the
> server.
I guess it depends on the actual server-side implementation, but in the
general case this is of course true. A server could decide to for
example overserve objects in case the client does a full clone, or it
could arrange packfiles in a special way that allows it to serve at
least some kinds of requests efficiently.
> Contrast that with a client that instead pulls a packfile over dumb
> storage on its own, and then comes to the server for a top-off fetch.
> The server still has to do some computation, but it's usually quite
> small, because both sides agree quickly that there's no need to dig down
> further than the tips in that dumb packfile.
So this here is in theory possible with packfile URIs, as well, by
computing the top-off fetch depending on the packfile layout.
But this requires quite a bunch of server-side logic and very specific
layouts, I guess.
> > Of course, the big downside is that "fetch.uriProtocols" is empty by
> > default, so Git will not use them. Makes me wonder whether this is
> > something we want to eventually change, but I guess the current default
> > behaviour is somewhat insecure as it would allow the server to redirect
> > clients to arbitrary locations. It would be great if we had a mechanism
> > that only allowed packfile URIs that use the same host, which would make
> > this a lot more reasonable to enable by default.
>
> It's been a while since I've looked at it, but I seem to recall that the
> server-side tools for specifying which packfile URIs to use were not
> that mature. Maybe that has changed, though (I'm probably 5 years out of
> date since the last time I really thought about these things).
Packfile URIs definitely need some love to become feasible, yes, and I
don't think they have evolved much since their introduction. I still
feel like they are the better mechanism for offloading traffic compared
to bundle URIs though, as we already have packfiles around anyway.
Patrick
^ permalink raw reply
* Re: [PATCH 0/3] small quote.[ch] cleanup
From: Patrick Steinhardt @ 2026-05-21 11:39 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, git
In-Reply-To: <xmqqjyt084sn.fsf@gitster.g>
On Tue, May 19, 2026 at 12:19:20PM +0900, Junio C Hamano wrote:
> Jeff King <peff@peff.net> writes:
>
> > I noticed some unused code while looking at an unrelated topic. So
> > here's a small cleanup.
> >
> > [1/3]: quote.h: bump strvec forward declaration to the top
> > [2/3]: quote: drop sq_dequote_to_argv()
> > [3/3]: quote: simplify internals of dequoting
> >
> > quote.c | 21 ++-------------------
> > quote.h | 14 ++++----------
> > 2 files changed, 6 insertions(+), 29 deletions(-)
> >
> > -Peff
>
> These were very straight-forward and pleasant to read. Queued.
> Thanks.
Indeed, all of these steps make sense to me. Thanks!
Patrick
^ permalink raw reply
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