[PATCH v3 0/4] Filter alternate references
- From
Taylor Blau <me@ttaylorr.com>
- Date
- Sep 28, 2018, 04:25 UTC
- Message-ID
- <cover.1538108385.git.me@ttaylorr.com>
- In-Reply-To
- <cover.1537466087.git.me@ttaylorr.com>
Hi,
Attached is the third re-roll of mine and Peff's series to introduce 'core.alternateRefsCommand', and 'core.alternateRefsPrefixes' to filter the initial ".have" advertisement when an alternate has a pathologically large number of references.
A range-diff against v2 is included below, but the major changes between the two revisions are as follows:
1. Documentation and testing clean-up, per helpful input from Junio,
Peff, and brian carlson. 2. Included also is a preparatory patch from Peff, to change the
requirement that we provide refnames for alternate references. We
no longer allow this, and the first commit sent makes that such
change.I imagine that we may hit one more re-roll, depending on the outcome of this review. The series has not fundamentally changed since v2, so I think that we are at a point of stasis there. Anything that is left outstanding from v3 should hopefully be similarly-not-earth-shattering ;-).
Thanks in advance for your review.
Thanks, Taylor
Jeff King (1): transport: drop refnames from for_each_alternate_ref
Taylor Blau (3): transport.c: extract 'fill_alternate_refs_command' transport.c: introduce core.alternateRefsCommand transport.c: introduce core.alternateRefsPrefixes
Documentation/config.txt | 18 +++++++++++++ builtin/receive-pack.c | 3 +-- fetch-pack.c | 3 +-- t/t5410-receive-pack.sh | 57 ++++++++++++++++++++++++++++++++++++++++ transport.c | 38 +++++++++++++++++++++------ transport.h | 2 +- 6 files changed, 108 insertions(+), 13 deletions(-) create mode 100755 t/t5410-receive-pack.sh
Range-diff against v2:
-: ---------- > 1: 037273dab0 transport: drop refnames from for_each_alternate_ref
1: 6e3a58afe7 ! 2: 9479470cb1 transport.c: extract 'fill_alternate_refs_command'
@@ -24,7 +24,7 @@
+ cmd->git_cmd = 1;
+ argv_array_pushf(&cmd->args, "--git-dir=%s", repo_path);
+ argv_array_push(&cmd->args, "for-each-ref");
-+ argv_array_push(&cmd->args, "--format=%(objectname) %(refname)");
++ argv_array_push(&cmd->args, "--format=%(objectname)");
+ cmd->env = local_repo_env;
+ cmd->out = -1;
+}
@@ -39,7 +39,7 @@
- cmd.git_cmd = 1;
- argv_array_pushf(&cmd.args, "--git-dir=%s", path);
- argv_array_push(&cmd.args, "for-each-ref");
-- argv_array_push(&cmd.args, "--format=%(objectname) %(refname)");
+- argv_array_push(&cmd.args, "--format=%(objectname)");
- cmd.env = local_repo_env;
- cmd.out = -1;
+ fill_alternate_refs_command(&cmd, path);
2: 9797f52551 ! 3: 2dbcd54190 transport.c: introduce core.alternateRefsCommand
@@ -3,24 +3,24 @@
transport.c: introduce core.alternateRefsCommand When in a repository containing one or more alternates, Git would
- sometimes like to list references from its alternates. For example, 'git
- receive-pack' list the objects pointed to by alternate references as
- special ".have" references.
+ sometimes like to list references from those alternates. For example,
+ 'git receive-pack' lists the "tips" pointed to by references in those
+ alternates as special ".have" references. Listing ".have" references is designed to make pushing changes from
upstream to a fork a lightweight operation, by advertising to the pusher
that the fork already has the objects (via its alternate). Thus, the
client can avoid sending them. - However, when the alternate has a pathologically large number of
- references, the initial advertisement is too expensive. In fact, it can
- dominate any such optimization where the pusher avoids sending certain
- objects.
+ However, when the alternate (upstream, in the previous example) has a
+ pathologically large number of references, the initial advertisement is
+ too expensive. In fact, it can dominate any such optimization where the
+ pusher avoids sending certain objects. Introduce "core.alternateRefsCommand" in order to provide a facility to
limit or filter alternate references. This can be used, for example, to
- filter out "uninteresting" references from the initial advertisement in
- the above scenario.
+ filter out references the alternate does not wish to send (for space
+ concerns, or otherwise) during the initial advertisement. Let the repository that has alternates configure this command to avoid
trusting the alternate to provide us a safe command to run in the shell.
@@ -38,15 +38,15 @@
expect HEAD to be a symbolic link. +core.alternateRefsCommand::
-+ When listing references from an alternate (e.g., in the case of ".have"), use
-+ the shell to execute the specified command instead of
-+ linkgit:git-for-each-ref[1]. The first argument is the path of the alternate.
-+ Output must be of the form: `%(objectname) SPC %(refname)`.
++ When advertising tips of available history from an alternate, use the shell to
++ execute the specified command instead of linkgit:git-for-each-ref[1]. The
++ first argument is the absolute path of the alternate. Output must be of the
++ form: `%(objectname)`, where multiple tips are separated by newlines.
++
+This is useful when a repository only wishes to advertise some of its
+alternate's references as ".have"'s. For example, to only advertise branch
+heads, configure `core.alternateRefsCommand` to the path of a script which runs
-+`git --git-dir="$1" for-each-ref refs/heads`.
++`git --git-dir="$1" for-each-ref --format='%(objectname)' refs/heads`.
+
core.bare::
If true this repository is assumed to be 'bare' and has no
@@ -74,8 +74,7 @@
+ git clone fork pusher &&
+ (
+ cd fork &&
-+ git config receive.advertisealternates true &&
-+ cat <<-EOF | git update-ref --stdin &&
++ git update-ref --stdin <<-\EOF &&
+ delete refs/heads/a
+ delete refs/heads/b
+ delete refs/heads/c
@@ -88,23 +87,19 @@
+ )
+'
+
-+expect_haves () {
-+ printf "%s .have\n" $(git rev-parse $@) >expect
-+}
-+
+extract_haves () {
-+ depacketize - | grep '\.have' | sed -e 's/\\0.*$//g'
++ depacketize | perl -lne '/^(\S+) \.have/ and print $1'
+}
+
+test_expect_success 'with core.alternateRefsCommand' '
+ write_script fork/alternate-refs <<-\EOF &&
+ git --git-dir="$1" for-each-ref \
-+ --format="%(objectname) %(refname)" \
++ --format="%(objectname)" \
+ refs/heads/a \
+ refs/heads/c
+ EOF
+ test_config -C fork core.alternateRefsCommand alternate-refs &&
-+ expect_haves a c >expect &&
++ git rev-parse a c >expect &&
+ printf "0000" | git receive-pack fork >actual &&
+ extract_haves <actual >actual.haves &&
+ test_cmp expect actual.haves
@@ -122,7 +117,7 @@
- cmd->git_cmd = 1;
- argv_array_pushf(&cmd->args, "--git-dir=%s", repo_path);
- argv_array_push(&cmd->args, "for-each-ref");
-- argv_array_push(&cmd->args, "--format=%(objectname) %(refname)");
+- argv_array_push(&cmd->args, "--format=%(objectname)");
+ const char *value;
+
+ if (!git_config_get_value("core.alternateRefsCommand", &value)) {
@@ -135,7 +130,7 @@
+
+ argv_array_pushf(&cmd->args, "--git-dir=%s", repo_path);
+ argv_array_push(&cmd->args, "for-each-ref");
-+ argv_array_push(&cmd->args, "--format=%(objectname) %(refname)");
++ argv_array_push(&cmd->args, "--format=%(objectname)");
+ }
+
cmd->env = local_repo_env;
3: 6e8f65a16d ! 4: 48eb774c9e transport.c: introduce core.alternateRefsPrefixes
@@ -12,9 +12,7 @@
'core.alternateRefsCommand' would have to do: $ git config core.alternateRefsCommand ' \
- git -C "$1" for-each-ref refs/tags \
- --format="%(objectname) %(refname)" \
- '
+ git -C "$1" for-each-ref refs/tags --format="%(objectname)"' The above is cumbersome to write, so let's introduce a
"core.alternateRefsPrefixes" to address this common case. Instead, the
@@ -41,7 +39,7 @@
+++ b/Documentation/config.txt
@@
heads, configure `core.alternateRefsCommand` to the path of a script which runs
- `git --git-dir="$1" for-each-ref refs/heads`.
+ `git --git-dir="$1" for-each-ref --format='%(objectname)' refs/heads`. +core.alternateRefsPrefixes::
+ When listing references from an alternate, list only references that begin
@@ -63,7 +61,7 @@ +test_expect_success 'with core.alternateRefsPrefixes' '
+ test_config -C fork core.alternateRefsPrefixes "refs/tags" &&
-+ expect_haves one three two >expect &&
++ git rev-parse one three two >expect &&
+ printf "0000" | git receive-pack fork >actual &&
+ extract_haves <actual >actual.haves &&
+ test_cmp expect actual.haves
@@ -77,7 +75,7 @@
@@
argv_array_pushf(&cmd->args, "--git-dir=%s", repo_path);
argv_array_push(&cmd->args, "for-each-ref");
- argv_array_push(&cmd->args, "--format=%(objectname) %(refname)");
+ argv_array_push(&cmd->args, "--format=%(objectname)");
+
+ if (!git_config_get_value("core.alternateRefsPrefixes", &value)) {
+ argv_array_push(&cmd->args, "--");
--
2.19.0.221.g150f307af