git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 4/6] revision: add new parameter to exclude hidden refs

From
Patrick Steinhardt <ps@pks.im>
Date
Nov 7, 2022, 12:16 UTC
Message-ID
<de7c1aa210c2df9bdbbb6c19f44f72c37f56c5da.1667823042.git.ps@pks.im>
In-Reply-To
<cover.1667823042.git.ps@pks.im>

Users can optionally hide refs from remote users in git-upload-pack(1), git-receive-pack(1) and others via the `transfer.hideRefs`, but there is not an easy way to obtain the list of all visible or hidden refs right now. We'll require just that though for a performance improvement in our connectivity check.

Add a new option `--exclude-hidden=` that excludes any hidden refs from the next pseudo-ref like `--all` or `--branches`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 Documentation/rev-list-options.txt |   7 ++
 builtin/rev-list.c                 |   1 +
 revision.c                         |  43 +++++++-
 revision.h                         |   9 +-
 t/t6021-rev-list-exclude-hidden.sh | 159 +++++++++++++++++++++++++++++
 5 files changed, 217 insertions(+), 2 deletions(-)
 create mode 100755 t/t6021-rev-list-exclude-hidden.sh
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 1837509566..a178956613 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -195,6 +195,13 @@ respectively, and they must begin with `refs/` when applied to `--glob`
 or `--all`. If a trailing '/{asterisk}' is intended, it must be given
 explicitly.
 
+--exclude-hidden=[transfer|receive|uploadpack]::
+	Do not include refs that have been hidden via either one of
+	`transfer.hideRefs`, `receive.hideRefs` or `uploadpack.hideRefs` that
+	the next `--all`, `--branches`, `--tags`, `--remotes` or `--glob` would
+	otherwise consider.  This option is cleared when seeing one of these
+	pseudo-refs.
+
 --reflog::
 	Pretend as if all objects mentioned by reflogs are listed on the
 	command line as `<commit>`.
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 3acd93f71e..9eace06385 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -38,6 +38,7 @@ static const char rev_list_usage[] =
 "    --tags\n"
 "    --remotes\n"
 "    --stdin\n"
+"    --exclude-hidden=[transfer|receive|uploadpack]\n"
 "    --quiet\n"
 "  ordering output:\n"
 "    --topo-order\n"
diff --git a/revision.c b/revision.c
index e5eaaa24ba..45652f9b0b 100644
--- a/revision.c
+++ b/revision.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "config.h"
 #include "object-store.h"
 #include "tag.h"
 #include "blob.h"
@@ -1519,22 +1520,30 @@ static void add_rev_cmdline_list(struct rev_info *revs,
 
 int ref_excluded(const struct ref_exclusions *exclusions, const char *path)
 {
+	const char *stripped_path = strip_namespace(path);
 	struct string_list_item *item;
+
 	for_each_string_list_item(item, &exclusions->excluded_refs) {
 		if (!wildmatch(item->string, path, 0))
 			return 1;
 	}
+
+	if (ref_is_hidden(stripped_path, path, &exclusions->hidden_refs))
+		return 1;
+
 	return 0;
 }
 
 void init_ref_exclusions(struct ref_exclusions *exclusions)
 {
 	string_list_init_dup(&exclusions->excluded_refs);
+	string_list_init_dup(&exclusions->hidden_refs);
 }
 
 void clear_ref_exclusions(struct ref_exclusions *exclusions)
 {
 	string_list_clear(&exclusions->excluded_refs, 0);
+	string_list_clear(&exclusions->hidden_refs, 1);
 }
 
 void add_ref_exclusion(struct ref_exclusions *exclusions, const char *exclude)
@@ -1542,6 +1551,35 @@ void add_ref_exclusion(struct ref_exclusions *exclusions, const char *exclude)
 	string_list_append(&exclusions->excluded_refs, exclude);
 }
 
+struct exclude_hidden_refs_cb {
+	struct ref_exclusions *exclusions;
+	const char *section;
+};
+
+static int hide_refs_config(const char *var, const char *value, void *cb_data)
+{
+	struct exclude_hidden_refs_cb *cb = cb_data;
+	return parse_hide_refs_config(var, value, cb->section,
+				      &cb->exclusions->hidden_refs);
+}
+
+void exclude_hidden_refs(struct ref_exclusions *exclusions, const char *section)
+{
+	struct exclude_hidden_refs_cb cb;
+
+	if (strcmp(section, "transfer") && strcmp(section, "receive") &&
+	    strcmp(section, "uploadpack"))
+		die(_("unsupported section for hidden refs: %s"), section);
+
+	if (exclusions->hidden_refs.nr)
+		die(_("--exclude-hidden= passed more than once"));
+
+	cb.exclusions = exclusions;
+	cb.section = section;
+
+	git_config(hide_refs_config, &cb);
+}
+
 struct all_refs_cb {
 	int all_flags;
 	int warned_bad_reflog;
@@ -2220,7 +2258,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 	    !strcmp(arg, "--bisect") || starts_with(arg, "--glob=") ||
 	    !strcmp(arg, "--indexed-objects") ||
 	    !strcmp(arg, "--alternate-refs") ||
-	    starts_with(arg, "--exclude=") ||
+	    starts_with(arg, "--exclude=") || starts_with(arg, "--exclude-hidden=") ||
 	    starts_with(arg, "--branches=") || starts_with(arg, "--tags=") ||
 	    starts_with(arg, "--remotes=") || starts_with(arg, "--no-walk="))
 	{
@@ -2709,6 +2747,9 @@ static int handle_revision_pseudo_opt(struct rev_info *revs,
 	} else if ((argcount = parse_long_opt("exclude", argv, &optarg))) {
 		add_ref_exclusion(&revs->ref_excludes, optarg);
 		return argcount;
+	} else if ((argcount = parse_long_opt("exclude-hidden", argv, &optarg))) {
+		exclude_hidden_refs(&revs->ref_excludes, optarg);
+		return argcount;
 	} else if (skip_prefix(arg, "--branches=", &optarg)) {
 		struct all_refs_cb cb;
 		init_all_refs_cb(&cb, revs, *flags);
diff --git a/revision.h b/revision.h
index 87d6824c55..fef5e063d1 100644
--- a/revision.h
+++ b/revision.h
@@ -87,6 +87,12 @@ struct ref_exclusions {
 	 * patterns matches, the reference will be excluded.
 	 */
 	struct string_list excluded_refs;
+
+	/*
+	 * Hidden refs is a list of patterns that is to be hidden via
+	 * `ref_is_hidden()`.
+	 */
+	struct string_list hidden_refs;
 };
 
 struct oidset;
@@ -449,12 +455,13 @@ void show_object_with_name(FILE *, struct object *, const char *);
 /**
  * Helpers to check if a reference should be excluded.
  */
-#define REF_EXCLUSIONS_INIT { .excluded_refs = STRING_LIST_INIT_DUP }
+#define REF_EXCLUSIONS_INIT { .excluded_refs = STRING_LIST_INIT_DUP, .hidden_refs = STRING_LIST_INIT_DUP }
 
 int ref_excluded(const struct ref_exclusions *exclusions, const char *path);
 void init_ref_exclusions(struct ref_exclusions *);
 void clear_ref_exclusions(struct ref_exclusions *);
 void add_ref_exclusion(struct ref_exclusions *, const char *exclude);
+void exclude_hidden_refs(struct ref_exclusions *, const char *section);
 
 /**
  * This function can be used if you want to add commit objects as revision
diff --git a/t/t6021-rev-list-exclude-hidden.sh b/t/t6021-rev-list-exclude-hidden.sh
new file mode 100755
index 0000000000..d08fc2da93
--- /dev/null
+++ b/t/t6021-rev-list-exclude-hidden.sh
@@ -0,0 +1,159 @@
+#!/bin/sh
+
+test_description='git rev-list --exclude-hidden test'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	test_commit_bulk --id=commit --ref=refs/heads/main 1 &&
+	COMMIT=$(git rev-parse refs/heads/main) &&
+	test_commit_bulk --id=tag --ref=refs/tags/lightweight 1 &&
+	TAG=$(git rev-parse refs/tags/lightweight) &&
+	test_commit_bulk --id=hidden --ref=refs/hidden/commit 1 &&
+	HIDDEN=$(git rev-parse refs/hidden/commit) &&
+	test_commit_bulk --id=namespace --ref=refs/namespaces/namespace/refs/namespaced/commit 1 &&
+	NAMESPACE=$(git rev-parse refs/namespaces/namespace/refs/namespaced/commit)
+'
+
+test_expect_success 'invalid section' '
+	echo "fatal: unsupported section for hidden refs: unsupported" >expected &&
+	test_must_fail git rev-list --exclude-hidden=unsupported 2>err &&
+	test_cmp expected err
+'
+
+test_expect_success 'passed multiple times' '
+	echo "fatal: --exclude-hidden= passed more than once" >expected &&
+	test_must_fail git -c transfer.hideRefs=refs/hidden/ rev-list --exclude-hidden=transfer --exclude-hidden=transfer 2>err &&
+	test_cmp expected err
+'
+
+test_expect_success '--exclude-hidden without hiddenRefs' '
+	git rev-list --exclude-hidden=transfer --all >out &&
+	cat >expected <<-EOF &&
+	$NAMESPACE
+	$HIDDEN
+	$TAG
+	$COMMIT
+	EOF
+	test_cmp expected out
+'
+
+test_expect_success 'hidden via transfer.hideRefs' '
+	git -c transfer.hideRefs=refs/hidden/ rev-list --exclude-hidden=transfer --all >out &&
+	cat >expected <<-EOF &&
+	$NAMESPACE
+	$TAG
+	$COMMIT
+	EOF
+	test_cmp expected out
+'
+
+test_expect_success '--all --exclude-hidden=transfer --not --all without hidden refs' '
+	git rev-list --all --exclude-hidden=transfer --not --all >out &&
+	test_must_be_empty out
+'
+
+test_expect_success '--all --exclude-hidden=transfer --not --all with hidden ref' '
+	git -c transfer.hideRefs=refs/hidden/ rev-list --all --exclude-hidden=transfer --not --all >out &&
+	cat >expected <<-EOF &&
+	$HIDDEN
+	EOF
+	test_cmp expected out
+'
+
+test_expect_success '--exclude-hidden with --exclude' '
+	git -c transfer.hideRefs=refs/hidden/ rev-list --exclude=refs/tags/* --exclude-hidden=transfer --all >out &&
+	cat >expected <<-EOF &&
+	$NAMESPACE
+	$COMMIT
+	EOF
+	test_cmp expected out
+'
+
+test_expect_success '--exclude-hidden is reset' '
+	git -c transfer.hideRefs=refs/ rev-list --exclude-hidden=transfer --all --all >out &&
+	cat >expected <<-EOF &&
+	$NAMESPACE
+	$HIDDEN
+	$TAG
+	$COMMIT
+	EOF
+	test_cmp expected out
+'
+
+test_expect_success '--exclude-hidden operates on stripped refs by default' '
+	GIT_NAMESPACE=namespace git -c transfer.hideRefs=refs/namespaced/ rev-list --exclude-hidden=transfer --all >out &&
+	cat >expected <<-EOF &&
+	$HIDDEN
+	$TAG
+	$COMMIT
+	EOF
+	test_cmp expected out
+'
+
+test_expect_success '--exclude-hidden does not hide namespace by default' '
+	GIT_NAMESPACE=namespace git -c transfer.hideRefs=refs/namespaces/namespace/ rev-list --exclude-hidden=transfer --all >out &&
+	cat >expected <<-EOF &&
+	$NAMESPACE
+	$HIDDEN
+	$TAG
+	$COMMIT
+	EOF
+	test_cmp expected out
+'
+
+test_expect_success '--exclude-hidden= may operate on unstripped refs' '
+	GIT_NAMESPACE=namespace git -c transfer.hideRefs=^refs/namespaces/namespace/ rev-list --exclude-hidden=transfer --all >out &&
+	cat >expected <<-EOF &&
+	$HIDDEN
+	$TAG
+	$COMMIT
+	EOF
+	test_cmp expected out
+'
+
+for section in receive uploadpack
+do
+	test_expect_success "hidden via $section.hideRefs" '
+		git -c $section.hideRefs=refs/hidden/ rev-list --exclude-hidden=$section --all >out &&
+		cat >expected <<-EOF &&
+		$NAMESPACE
+		$TAG
+		$COMMIT
+		EOF
+		test_cmp expected out
+	'
+
+	test_expect_success "--exclude-hidden=$section respects transfer.hideRefs" '
+		git -c transfer.hideRefs=refs/hidden/ rev-list --exclude-hidden=$section --all >out &&
+		cat >expected <<-EOF &&
+		$NAMESPACE
+		$TAG
+		$COMMIT
+		EOF
+		test_cmp expected out
+	'
+
+	test_expect_success "--exclude-hidden=transfer ignores $section.hideRefs" '
+		git -c $section.hideRefs=refs/hidden/ rev-list --exclude-hidden=transfer --all >out &&
+		cat >expected <<-EOF &&
+		$NAMESPACE
+		$HIDDEN
+		$TAG
+		$COMMIT
+		EOF
+		test_cmp expected out
+	'
+
+	test_expect_success "--exclude-hidden=$section respects both transfer.hideRefs and $section.hideRefs" '
+		git -c transfer.hideRefs=refs/tags/ -c $section.hideRefs=refs/hidden/ rev-list --exclude-hidden=$section --all >out &&
+		cat >expected <<-EOF &&
+		$NAMESPACE
+		$COMMIT
+		EOF
+		test_cmp expected out
+	'
+done
+
+test_done
-- 
2.38.1
Previous: Jeff KingNext: Ævar Arnfjörð Bjarmason
Message 43 of 88 in “receive-pack: use advertised reference tips to inform connectivity check”
  1. 0/2 receive-pack: use advertised reference tips to inform connectivity checkPatrick Steinhardt, Oct 28, 2022
  2. 1/2 connected: allow supplying different view of reachable objectsPatrick Steinhardt, Oct 28, 2022
  3. Ævar Arnfjörð BjarmasonOct 28, 2022
  4. Junio C HamanoOct 28, 2022
  5. Taylor BlauOct 30, 2022
  6. Patrick SteinhardtOct 31, 2022
  7. Taylor BlauNov 1, 2022
  8. 2/2 receive-pack: use advertised reference tips to inform connectivity checkPatrick Steinhardt, Oct 28, 2022
  9. Ævar Arnfjörð BjarmasonOct 28, 2022
  10. Patrick SteinhardtOct 31, 2022
  11. Ævar Arnfjörð BjarmasonOct 31, 2022
  12. Taylor BlauOct 30, 2022
  13. Patrick SteinhardtOct 31, 2022
  14. Taylor BlauNov 1, 2022
  15. Patrick SteinhardtNov 1, 2022
  16. Patrick SteinhardtNov 1, 2022
  17. Taylor BlauNov 2, 2022
  18. Jeff KingNov 1, 2022
  19. Junio C HamanoOct 28, 2022
  20. Taylor BlauNov 1, 2022
  21. Jeff KingNov 1, 2022
  22. Patrick SteinhardtNov 1, 2022
  23. 0/3 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 3, 2022
  24. 1/3 refs: get rid of global list of hidden refsPatrick Steinhardt, Nov 3, 2022
  25. 2/3 revision: add new parameter to specify all visible refsPatrick Steinhardt, Nov 3, 2022
  26. Jeff KingNov 5, 2022
  27. Patrick SteinhardtNov 7, 2022
  28. Jeff KingNov 8, 2022
  29. Jeff KingNov 5, 2022
  30. 3/3 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 3, 2022
  31. Taylor BlauNov 5, 2022
  32. Jeff KingNov 5, 2022
  33. Jeff KingNov 5, 2022
  34. 0/6 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 7, 2022
  35. 2/6 revision: move together exclusion-related functionsPatrick Steinhardt, Nov 7, 2022
  36. 1/6 refs: get rid of global list of hidden refsPatrick Steinhardt, Nov 7, 2022
  37. 6/6 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 7, 2022
  38. 3/6 revision: introduce struct to handle exclusionsPatrick Steinhardt, Nov 7, 2022
  39. Ævar Arnfjörð BjarmasonNov 7, 2022
  40. Patrick SteinhardtNov 8, 2022
  41. 5/6 revparse: add `--exclude-hidden=` optionPatrick Steinhardt, Nov 7, 2022
  42. Jeff KingNov 8, 2022
  43. 4/6 revision: add new parameter to exclude hidden refsPatrick Steinhardt, Nov 7, 2022
  44. Ævar Arnfjörð BjarmasonNov 7, 2022
  45. Ævar Arnfjörð BjarmasonNov 7, 2022
  46. Patrick SteinhardtNov 8, 2022
  47. Patrick SteinhardtNov 8, 2022
  48. Taylor BlauNov 8, 2022
  49. Patrick SteinhardtNov 8, 2022
  50. Jeff KingNov 8, 2022
  51. Taylor BlauNov 8, 2022
  52. 0/6 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 8, 2022
  53. 1/6 refs: get rid of global list of hidden refsPatrick Steinhardt, Nov 8, 2022
  54. Ævar Arnfjörð BjarmasonNov 8, 2022
  55. Patrick SteinhardtNov 8, 2022
  56. Jeff KingNov 8, 2022
  57. 2/6 revision: move together exclusion-related functionsPatrick Steinhardt, Nov 8, 2022
  58. 5/6 rev-parse: add `--exclude-hidden=` optionPatrick Steinhardt, Nov 8, 2022
  59. 3/6 revision: introduce struct to handle exclusionsPatrick Steinhardt, Nov 8, 2022
  60. 4/6 revision: add new parameter to exclude hidden refsPatrick Steinhardt, Nov 8, 2022
  61. Jeff KingNov 8, 2022
  62. Taylor BlauNov 8, 2022
  63. Patrick SteinhardtNov 11, 2022
  64. 6/6 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 8, 2022
  65. 0/7 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 11, 2022
  66. 1/7 refs: fix memory leak when parsing hideRefs configPatrick Steinhardt, Nov 11, 2022
  67. 2/7 refs: get rid of global list of hidden refsPatrick Steinhardt, Nov 11, 2022
  68. 3/7 revision: move together exclusion-related functionsPatrick Steinhardt, Nov 11, 2022
  69. 4/7 revision: introduce struct to handle exclusionsPatrick Steinhardt, Nov 11, 2022
  70. 5/7 revision: add new parameter to exclude hidden refsPatrick Steinhardt, Nov 11, 2022
  71. 6/7 rev-parse: add `--exclude-hidden=` optionPatrick Steinhardt, Nov 11, 2022
  72. 7/7 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 11, 2022
  73. Taylor BlauNov 11, 2022
  74. Jeff KingNov 15, 2022
  75. Taylor BlauNov 16, 2022
  76. Jeff KingNov 16, 2022
  77. Taylor BlauNov 16, 2022
  78. Patrick SteinhardtNov 17, 2022
  79. 0/7 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 17, 2022
  80. 1/7 refs: fix memory leak when parsing hideRefs configPatrick Steinhardt, Nov 17, 2022
  81. 2/7 refs: get rid of global list of hidden refsPatrick Steinhardt, Nov 17, 2022
  82. 3/7 revision: move together exclusion-related functionsPatrick Steinhardt, Nov 17, 2022
  83. 4/7 revision: introduce struct to handle exclusionsPatrick Steinhardt, Nov 17, 2022
  84. 5/7 revision: add new parameter to exclude hidden refsPatrick Steinhardt, Nov 17, 2022
  85. 6/7 rev-parse: add `--exclude-hidden=` optionPatrick Steinhardt, Nov 17, 2022
  86. 7/7 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 17, 2022
  87. Jeff KingNov 17, 2022
  88. Taylor BlauNov 17, 2022

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.