From: "Kristofer Karlsson via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Patrick Steinhardt <ps@pks.im>, Jeff King <peff@peff.net>,
Justin Tobler <jltobler@gmail.com>,
Kristofer Karlsson <krka@spotify.com>,
Kristofer Karlsson <krka@spotify.com>
Subject: [PATCH v3] odb: do not list our own refs as alternate refs
Date: Thu, 05 Nov 2026 07:43:22 +0000 [thread overview]
Message-ID: <pull.2285.v3.git.1793864602482.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.2285.git.1793200705017.gitgitgadget@gmail.com>
From: Kristofer Karlsson <krka@spotify.com>
Since 722ff7f876 (receive-pack: quarantine objects until pre-receive
accepts, 2016-10-03), receive-pack writes incoming objects to a
temporary object directory. Child processes see it as their primary
object directory, and tmp-objdir passes the repository's own object
directory to them via GIT_ALTERNATE_OBJECT_DIRECTORIES.
The connectivity check passes --alternate-refs to rev-list since
39b44ba771 (check_everything_connected: assume alternate ref tips are
valid, 2019-07-01). Inside the quarantine, the repository's own object
directory is one of the alternates, so --alternate-refs runs
for-each-ref on the repository itself and lists all of its refs.
That includes hidden refs. bcec6780b2 (receive-pack: only use visible
refs for connectivity check, 2022-11-17) added --exclude-hidden=receive
to the check so that repositories with many hidden refs do not have to
load all of them on each push. The hidden refs are excluded from --all,
but they all come back through --alternate-refs.
Our own repository is not a source of alternate refs: its refs are our
own refs, which the caller already lists as it sees fit. So skip an
alternate whose repository is our own when listing alternate refs.
This does not depend on how the alternate came about, so it also covers
an environment that makes our own object directory an alternate by
hand.
Since --alternate-refs is a rev-list option, callers other than the
connectivity check may use it too, so this tightens what it means
rather than only fixing the connectivity check. It is in line with
what we already do when loading alternates, where listing the object
directory itself is ignored as a common mistake; inside the quarantine
that check compares against the quarantine instead of our own object
directory, so our own object directory slips through. Document the
tightened meaning, too.
Add tests that our own refs are no longer listed, by the connectivity
check, by rev-list run from a pre-receive hook, and by rev-list with
our own object directory passed in as an alternate by hand, and that
the refs of a real alternate still are. Add a perf test pushing a
single commit into a repository with a visible branch and about
200,000 refs hidden by receive.hideRefs, and into a copy of it that
hides nothing:
Test HEAD~1 HEAD
-----------------------------------------------------------------------
5552.2: push, hidden refs 0.29(0.31+0.06) 0.10(0.07+0.03) -65.5%
5552.3: push, no hidden refs 1.20(1.02+0.68) 1.00(0.83+0.59) -16.7%
With hidden refs, most of the time went to the for-each-ref child that
listed the alternate refs. Without hidden refs, every ref was listed
twice, once for --all and once for --alternate-refs.
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Kristofer Karlsson <krka@spotify.com>
---
odb: do not list our own refs as alternate refs
When a repository hides refs with receive.hideRefs, every push still
loads all of the hidden refs in the connectivity check, even though
bcec6780b2 (receive-pack: only use visible refs for connectivity check,
2022-11-17) excludes them from it. With many hidden refs, that is most
of the time spent on a small push.
I stumbled across this while working on the boundary walk of the
connectivity check (the follow-up to kk/connectivity-check-incremental),
when the walk loaded every ref during a push even though it should only
have looked at a few of them.
Changes since v2:
* Went back to the approach of v1, as Peff suggested: skip our own
repository in the alternate refs code itself, with no special
handling of the quarantine. The "borrowed" flag and the check for the
parent of GIT_QUARANTINE_PATH are gone.
* The commit message now describes this as a tightening of what
--alternate-refs means, in line with how loading alternates already
ignores the object directory itself.
* Kept the documentation note and the tests from v2, except the one for
a quarantine outside of the commondir.
Changes since v1:
* Changed the rule to "an alternate that is ourselves is not a source
of alternate refs", as Peff described it.
* Added a "borrowed" flag to alternates, set when they are loaded,
which says whether they come from another repository, and used it for
--alternate-refs. Our own object directory is recognized either as
commondir/objects or as the parent of GIT_QUARANTINE_PATH.
* Documented this for --alternate-refs.
* Added tests for rev-list --alternate-refs in a pre-receive hook, for
our own object directory set up as an alternate by hand, and for a
quarantine outside of the commondir.
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2285%2Fspkrka%2Fquarantine-altrefs-bugreport-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2285/spkrka/quarantine-altrefs-bugreport-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/2285
Range-diff vs v2:
1: bac15042c0 ! 1: 35ab373cd4 odb: do not list our own refs as alternate refs in the quarantine
@@ Metadata
Author: Kristofer Karlsson <krka@spotify.com>
## Commit message ##
- odb: do not list our own refs as alternate refs in the quarantine
+ odb: do not list our own refs as alternate refs
Since 722ff7f876 (receive-pack: quarantine objects until pre-receive
accepts, 2016-10-03), receive-pack writes incoming objects to a
- temporary object directory. Child processes see it as their primary
+ temporary object directory. Child processes see it as their primary
object directory, and tmp-objdir passes the repository's own object
directory to them via GIT_ALTERNATE_OBJECT_DIRECTORIES.
The connectivity check passes --alternate-refs to rev-list since
39b44ba771 (check_everything_connected: assume alternate ref tips are
- valid, 2019-07-01). Inside the quarantine, the repository's own object
+ valid, 2019-07-01). Inside the quarantine, the repository's own object
directory is one of the alternates, so --alternate-refs runs
for-each-ref on the repository itself and lists all of its refs.
- That includes hidden refs. bcec6780b2 (receive-pack: only use visible
+ That includes hidden refs. bcec6780b2 (receive-pack: only use visible
refs for connectivity check, 2022-11-17) added --exclude-hidden=receive
to the check so that repositories with many hidden refs do not have to
- load all of them on each push. The hidden refs are excluded from --all,
+ load all of them on each push. The hidden refs are excluded from --all,
but they all come back through --alternate-refs.
- An alternate that is ourselves is not a source of alternate refs: its
- refs are our own refs, which the caller already lists as it sees fit.
- Mark each object directory added via alternates with whether it is
- borrowed from another repository, and list alternate refs only from
- those. Within one process this needs no guessing, as tmp-objdir
- links our own object directory in itself. But a child process rebuilds
- its object store from the environment, so when an alternate is added,
- recognize ourselves in two ways:
-
- - as our <commondir>/objects, which also covers an environment that
- makes our own object directory an alternate by hand;
-
- - as the parent of GIT_QUARANTINE_PATH, as the quarantine is created
- directly inside our object directory (see "QUARANTINE ENVIRONMENT"
- in git-receive-pack(1)); this also works when the object directory
- is not under the commondir.
-
- Document in --alternate-refs that our own object directory does not
- count as an alternate repository.
-
- This is safe: alternate refs only serve as negative tips that are
- assumed to be complete, so dropping some can only make the traversal
- walk further, never make it accept a missing object.
+ Our own repository is not a source of alternate refs: its refs are our
+ own refs, which the caller already lists as it sees fit. So skip an
+ alternate whose repository is our own when listing alternate refs.
+ This does not depend on how the alternate came about, so it also covers
+ an environment that makes our own object directory an alternate by
+ hand.
+
+ Since --alternate-refs is a rev-list option, callers other than the
+ connectivity check may use it too, so this tightens what it means
+ rather than only fixing the connectivity check. It is in line with
+ what we already do when loading alternates, where listing the object
+ directory itself is ignored as a common mistake; inside the quarantine
+ that check compares against the quarantine instead of our own object
+ directory, so our own object directory slips through. Document the
+ tightened meaning, too.
Add tests that our own refs are no longer listed, by the connectivity
- check, by rev-list run from a pre-receive hook, by rev-list with our
- own object directory passed in as an alternate by hand, and by rev-list
- in a quarantine whose parent is not under the commondir, and that the
- refs of a real alternate still are. Add a perf test pushing a
+ check, by rev-list run from a pre-receive hook, and by rev-list with
+ our own object directory passed in as an alternate by hand, and that
+ the refs of a real alternate still are. Add a perf test pushing a
single commit into a repository with a visible branch and about
200,000 refs hidden by receive.hideRefs, and into a copy of it that
hides nothing:
Test HEAD~1 HEAD
-----------------------------------------------------------------------
- 5552.2: push, hidden refs 0.31(0.33+0.08) 0.09(0.06+0.03) -71.0%
- 5552.3: push, no hidden refs 1.23(1.06+0.68) 1.01(0.83+0.61) -17.9%
+ 5552.2: push, hidden refs 0.29(0.31+0.06) 0.10(0.07+0.03) -65.5%
+ 5552.3: push, no hidden refs 1.20(1.02+0.68) 1.00(0.83+0.59) -16.7%
With hidden refs, most of the time went to the for-each-ref child that
- listed the alternate refs. Without hidden refs, every ref was listed
+ listed the alternate refs. Without hidden refs, every ref was listed
twice, once for --all and once for --alternate-refs.
Helped-by: Jeff King <peff@peff.net>
@@ Documentation/rev-list-options.adoc: explicitly.
## odb.c ##
-@@ odb.c: static int refs_from_alternate_cb(struct odb_files_dir *alternate,
- size_t base_len;
- struct alternate_refs_data *cb = payload;
-
-+ if (!alternate->borrowed)
-+ goto out;
-+
- if (!strbuf_realpath(&path, alternate->abspath, 0))
- goto out;
- if (!strbuf_strip_suffix(&path, "/objects"))
-
- ## odb/source-files.c ##
@@
- #include "blob.h"
- #include "chdir-notify.h"
+ #include "abspath.h"
+ #include "commit-graph.h"
#include "config.h"
+#include "dir.h"
-+#include "environment.h"
+ #include "environment.h"
#include "gettext.h"
- #include "hex.h"
- #include "lockfile.h"
-@@ odb/source-files.c: static void odb_source_files_free(struct odb_source *source)
- files->dirs = next;
- }
- hashmap_clear(&files->dirs_by_path);
-+ free(files->quarantine_path);
-
- odb_source_release(&files->base);
- free(files);
-@@ odb/source-files.c: static int read_alternates(const char *object_dir, struct strvec *out)
- return 0;
- }
+ #include "hashmap.h"
+@@ odb.c: static int refs_from_alternate_cb(struct odb_files_dir *alternate,
+ void *payload)
+ {
+ struct strbuf path = STRBUF_INIT;
++ struct strbuf repo = STRBUF_INIT;
+ size_t base_len;
+ struct alternate_refs_data *cb = payload;
-+/*
-+ * Our own object directory is <commondir>/objects, or the parent of
-+ * GIT_QUARANTINE_PATH, as an object quarantine is created directly
-+ * inside it (see tmp_objdir_create()). Anything else, including a path
-+ * that cannot be resolved, is borrowed.
-+ */
-+static bool is_borrowed_object_dir(struct odb_source_files *files,
-+ const char *path)
-+{
-+ struct strbuf real = STRBUF_INIT;
-+ struct strbuf objdir = STRBUF_INIT;
-+ struct strbuf self = STRBUF_INIT;
-+ bool ret = true;
-+
-+ if (!strbuf_realpath(&real, path, 0))
-+ goto out;
-+
-+ strbuf_addf(&objdir, "%s/objects", files->base.odb->repo->commondir);
-+ if (strbuf_realpath(&self, objdir.buf, 0) &&
-+ !fspathcmp(real.buf, self.buf)) {
-+ ret = false;
-+ goto out;
-+ }
-+
-+ if (files->quarantine_path &&
-+ strbuf_realpath(&self, files->quarantine_path, 0)) {
-+ strbuf_strip_file_from_path(&self);
-+ strbuf_trim_trailing_dir_sep(&self);
-+ if (!fspathcmp(real.buf, self.buf))
-+ ret = false;
-+ }
-+
-+out:
-+ strbuf_release(&real);
-+ strbuf_release(&objdir);
-+ strbuf_release(&self);
-+ return ret;
-+}
-+
- static void odb_add_alternate_recursively(struct odb_source_files *files,
- const char *path,
- int depth)
-@@ odb/source-files.c: static void odb_add_alternate_recursively(struct odb_source_files *files,
+@@ odb.c: static int refs_from_alternate_cb(struct odb_files_dir *alternate,
goto out;
+ strbuf_setlen(&path, base_len);
- alternate = odb_files_dir_new(files->base.odb, path, false);
-+ alternate->borrowed = is_borrowed_object_dir(files, alternate->abspath);
-
- /* add the alternate entry */
- *files->dirs_tail = alternate;
-@@ odb/source-files.c: struct odb_source_files *odb_source_files_new(struct object_database *odb,
- struct odb_source_files *files;
- char *object_dir = NULL;
- char *alternates = NULL;
-+ char *quarantine_path = NULL;
-
- if (flags & ODB_NEW_HONOR_ENV) {
- object_dir = xstrdup_or_null(getenv(DB_ENVIRONMENT));
- alternates = xstrdup_or_null(getenv(ALTERNATE_DB_ENVIRONMENT));
-+ quarantine_path =
-+ xstrdup_or_null(getenv(GIT_QUARANTINE_ENVIRONMENT));
- }
- if (!object_dir)
- object_dir = xstrfmt("%s/objects", odb->repo->commondir);
-
- CALLOC_ARRAY(files, 1);
-+ files->quarantine_path = quarantine_path;
- odb_source_init(&files->base, odb, ODB_SOURCE_FILES, object_dir);
-
- hashmap_init(&files->dirs_by_path, odb_files_dir_by_path_cmp, files, 0);
-
- ## odb/source-files.h ##
-@@ odb/source-files.h: struct odb_files_dir {
- * repository. Directories added via alternates are not local.
- */
- bool local;
++ /* Our own repository is not a source of alternate refs. */
++ if (strbuf_realpath(&repo, cb->repo->commondir, 0) &&
++ !fspathcmp(path.buf, repo.buf))
++ goto out;
+
-+ /*
-+ * Whether this directory is borrowed from another repository, so
-+ * that its refs are alternate refs. Not every directory added via
-+ * alternates is borrowed: inside an object quarantine, our own
-+ * object directory is passed to us as an alternate, too. Only set
-+ * for directories added via alternates.
-+ */
-+ bool borrowed;
- };
+ read_alternate_refs(cb->repo, path.buf, cb->fn, cb->payload);
- struct odb_files_dir *odb_files_dir_new(struct object_database *odb,
-@@ odb/source-files.h: struct odb_source_files {
- * determined by "core.ignoreCase".
- */
- int dirs_paths_icase;
-+
-+ /*
-+ * The value of GIT_QUARANTINE_PATH when this source was set up from
-+ * the environment (see ODB_NEW_HONOR_ENV), or NULL.
-+ */
-+ char *quarantine_path;
- };
+ out:
+ strbuf_release(&path);
++ strbuf_release(&repo);
+ return 0;
+ }
- /* Allocate and initialize a new object source. */
## t/perf/p5552-push-hidden-refs.sh (new) ##
@@
@@ t/t5618-alternate-refs.sh: test_expect_success 'log --source shows .alternate ma
+ git rev-list --alternate-refs >actual &&
+ test_cmp expect actual
+'
-+
-+# A quarantine is created inside our object directory, so its parent is
-+# ourselves, even when that is not under our commondir.
-+test_expect_success 'parent of the quarantine is not listed as an alternate' '
-+ test_when_finished "rm -rf store.git" &&
-+ git init --bare store.git &&
-+ git push store.git refs/remotes/origin/one:refs/heads/one &&
-+ quarantine="$(pwd)/store.git/objects/tmp_objdir-test" &&
-+ mkdir "$quarantine" &&
-+
-+ git rev-parse origin/one >expect &&
-+ GIT_OBJECT_DIRECTORY="$quarantine" \
-+ GIT_ALTERNATE_OBJECT_DIRECTORIES="$(pwd)/store.git/objects" \
-+ git rev-list --no-walk --alternate-refs --stdin </dev/null >actual &&
-+ test_cmp expect actual &&
-+
-+ GIT_QUARANTINE_PATH="$quarantine" \
-+ GIT_OBJECT_DIRECTORY="$quarantine" \
-+ GIT_ALTERNATE_OBJECT_DIRECTORIES="$(pwd)/store.git/objects" \
-+ git rev-list --no-walk --alternate-refs --stdin </dev/null >actual &&
-+ test_must_be_empty actual
-+'
+
test_done
Documentation/rev-list-options.adoc | 5 +++-
odb.c | 8 ++++++
t/perf/p5552-push-hidden-refs.sh | 37 ++++++++++++++++++++++++++++
t/t5547-push-quarantine.sh | 38 +++++++++++++++++++++++++++++
t/t5618-alternate-refs.sh | 12 +++++++++
5 files changed, 99 insertions(+), 1 deletion(-)
create mode 100755 t/perf/p5552-push-hidden-refs.sh
diff --git a/Documentation/rev-list-options.adoc b/Documentation/rev-list-options.adoc
index 285fb3809f..6e4c487d1e 100644
--- a/Documentation/rev-list-options.adoc
+++ b/Documentation/rev-list-options.adoc
@@ -223,7 +223,10 @@ explicitly.
Pretend as if all objects mentioned as ref tips of alternate
repositories were listed on the command line. An alternate
repository is any repository whose object directory is specified
- in `objects/info/alternates`. The set of included objects may
+ in `objects/info/alternates`. The repository's own object
+ directory does not count, even when it is passed in as an
+ alternate, as happens inside the object quarantine of
+ linkgit:git-receive-pack[1]. The set of included objects may
be modified by `core.alternateRefsCommand`, etc. See
linkgit:git-config[1].
diff --git a/odb.c b/odb.c
index 2c93a9490c..0f78ffed6a 100644
--- a/odb.c
+++ b/odb.c
@@ -2,6 +2,7 @@
#include "abspath.h"
#include "commit-graph.h"
#include "config.h"
+#include "dir.h"
#include "environment.h"
#include "gettext.h"
#include "hashmap.h"
@@ -183,6 +184,7 @@ static int refs_from_alternate_cb(struct odb_files_dir *alternate,
void *payload)
{
struct strbuf path = STRBUF_INIT;
+ struct strbuf repo = STRBUF_INIT;
size_t base_len;
struct alternate_refs_data *cb = payload;
@@ -198,10 +200,16 @@ static int refs_from_alternate_cb(struct odb_files_dir *alternate,
goto out;
strbuf_setlen(&path, base_len);
+ /* Our own repository is not a source of alternate refs. */
+ if (strbuf_realpath(&repo, cb->repo->commondir, 0) &&
+ !fspathcmp(path.buf, repo.buf))
+ goto out;
+
read_alternate_refs(cb->repo, path.buf, cb->fn, cb->payload);
out:
strbuf_release(&path);
+ strbuf_release(&repo);
return 0;
}
diff --git a/t/perf/p5552-push-hidden-refs.sh b/t/perf/p5552-push-hidden-refs.sh
new file mode 100755
index 0000000000..e9aa206298
--- /dev/null
+++ b/t/perf/p5552-push-hidden-refs.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+test_description='speed of push into a repository with many hidden refs'
+. ./perf-lib.sh
+
+test_perf_fresh_repo
+
+test_expect_success 'set up repository with many hidden refs' '
+ git init --bare dst.git &&
+ test_commit_bulk --ref=refs/hidden/base --id=hidden 1000 &&
+ git rev-list refs/hidden/base >commits &&
+ for i in $(test_seq 200)
+ do
+ sed "s|^\(.*\)$|create refs/hidden/$i/\1 \1|" commits || return 1
+ done >input &&
+ git push dst.git refs/hidden/base &&
+ git -C dst.git update-ref --stdin <input &&
+ git -C dst.git pack-refs --all &&
+ cp -R dst.git dst-visible.git &&
+ git -C dst.git config receive.hideRefs refs/hidden &&
+ git symbolic-ref HEAD refs/heads/main &&
+ test_commit_bulk --id=visible 1 &&
+ git push dst.git main &&
+ git push dst-visible.git main
+'
+
+test_perf 'push, hidden refs' '
+ git commit --allow-empty -m new &&
+ git push -f dst.git HEAD:refs/heads/new
+'
+
+test_perf 'push, no hidden refs' '
+ git commit --allow-empty -m new &&
+ git push -f dst-visible.git HEAD:refs/heads/new
+'
+
+test_done
diff --git a/t/t5547-push-quarantine.sh b/t/t5547-push-quarantine.sh
index 6c14dfc42b..3426aec531 100755
--- a/t/t5547-push-quarantine.sh
+++ b/t/t5547-push-quarantine.sh
@@ -125,4 +125,42 @@ test_expect_success '.keep file created outside of process is not removed' '
test_path_is_missing "${keep%.keep}.pack"
'
+test_expect_success 'quarantine does not list own refs as alternate refs' '
+ git init --bare hidden.git &&
+ git push hidden.git HEAD:refs/heads/main HEAD:refs/hidden/one &&
+ git -C hidden.git config receive.hideRefs refs/hidden &&
+ write_script hidden.git/alternate-refs <<-EOF &&
+ echo "\$1" >>"$(pwd)/alternate-refs.log"
+ EOF
+ git -C hidden.git config core.alternateRefsCommand ./alternate-refs &&
+ test_commit hidden-push &&
+ git push hidden.git HEAD:refs/heads/new &&
+ test_path_is_missing alternate-refs.log
+'
+
+test_expect_success 'quarantine lists refs of other alternates' '
+ test_when_finished "rm -f alternate-refs.log" &&
+ git init --bare other.git &&
+ git push other.git HEAD:refs/heads/other &&
+ echo "$(pwd)/other.git/objects" >hidden.git/objects/info/alternates &&
+ test_commit hidden-push-2 &&
+ git push hidden.git HEAD:refs/heads/new2 &&
+ (cd other.git && pwd -P) >expect &&
+ sort -u alternate-refs.log >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-list --alternate-refs in a hook skips own refs' '
+ test_when_finished "rm -rf altref.git" &&
+ git init --bare altref.git &&
+ git push altref.git HEAD:refs/heads/main &&
+ test_hook -C altref.git pre-receive <<-\EOF &&
+ git rev-list --no-walk --alternate-refs --stdin </dev/null \
+ >../hook-alternate-refs
+ EOF
+ test_commit altref-push &&
+ git push altref.git HEAD:refs/heads/new &&
+ test_must_be_empty hook-alternate-refs
+'
+
test_done
diff --git a/t/t5618-alternate-refs.sh b/t/t5618-alternate-refs.sh
index 2fb6d549d3..e64e190c48 100755
--- a/t/t5618-alternate-refs.sh
+++ b/t/t5618-alternate-refs.sh
@@ -58,4 +58,16 @@ test_expect_success 'log --source shows .alternate marker' '
test_cmp expect actual
'
+# Our own object directory as an alternate is not a source of alternate
+# refs, but the alternates it brings in with it still are.
+test_expect_success 'own object directory as alternate lists only real alternates' '
+ test_when_finished "rm -rf other-objects" &&
+ mkdir other-objects &&
+ git rev-list --remotes=origin >expect &&
+ GIT_OBJECT_DIRECTORY="$(pwd)/other-objects" \
+ GIT_ALTERNATE_OBJECT_DIRECTORIES="$(pwd)/.git/objects" \
+ git rev-list --alternate-refs >actual &&
+ test_cmp expect actual
+'
+
test_done
base-commit: 750f5de7dfe9a4062f95088212b063f189d50e91
--
gitgitgadget
next prev parent reply other threads:[~2026-11-05 7:43 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-28 15:18 [PATCH] odb: do not list our own refs as alternate refs in the quarantine Kristofer Karlsson via GitGitGadget
2026-10-29 16:57 ` Justin Tobler
2026-10-30 11:29 ` Kristofer Karlsson
2026-10-29 17:24 ` Junio C Hamano
2026-10-30 11:51 ` Kristofer Karlsson
2026-10-30 16:05 ` Junio C Hamano
2026-10-30 18:17 ` Jeff King
2026-11-02 11:45 ` [PATCH v2] " Kristofer Karlsson via GitGitGadget
2026-11-03 0:37 ` Junio C Hamano
2026-11-03 1:12 ` Junio C Hamano
2026-11-03 10:19 ` Kristofer Karlsson
2026-11-03 11:00 ` Patrick Steinhardt
2026-11-03 12:05 ` Kristofer Karlsson
2026-11-03 12:26 ` Patrick Steinhardt
2026-11-03 21:53 ` Justin Tobler
2026-11-04 10:32 ` Kristofer Karlsson
2026-11-04 16:58 ` Justin Tobler
2026-11-04 2:48 ` Jeff King
2026-11-04 10:25 ` Kristofer Karlsson
2026-11-04 18:05 ` Junio C Hamano
2026-11-05 18:56 ` Jeff King
2026-11-05 19:56 ` Junio C Hamano
2026-11-05 7:43 ` Kristofer Karlsson via GitGitGadget [this message]
2026-11-05 19:07 ` [PATCH v3] odb: do not list our own refs as alternate refs Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=pull.2285.v3.git.1793864602482.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
--cc=jltobler@gmail.com \
--cc=krka@spotify.com \
--cc=peff@peff.net \
--cc=ps@pks.im \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox