Merge branch 'tb/filter-alternate-refs'
When pushing into a repository that borrows its objects from an alternate object store, "git receive-pack" that responds to the push request on the other side lists the tips of refs in the alternate to reduce the amount of objects transferred. This sometimes is detrimental when the number of refs in the alternate is absurdly large, in which case the bandwidth saved in potentially fewer objects transferred is wasted in excessively large ref advertisement. The alternate refs that are advertised are now configurable with a pair of configuration variables. * tb/filter-alternate-refs: transport.c: introduce core.alternateRefsPrefixes transport.c: introduce core.alternateRefsCommand transport.c: extract 'fill_alternate_refs_command' transport: drop refnames from for_each_alternate_ref
This commit is contained in:
commit
465e73fff3
@ -616,6 +616,24 @@ core.preferSymlinkRefs::
|
||||
This is sometimes needed to work with old scripts that
|
||||
expect HEAD to be a symbolic link.
|
||||
|
||||
core.alternateRefsCommand::
|
||||
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 contain one
|
||||
hex object id per line (i.e., the same as produce by `git for-each-ref
|
||||
--format='%(objectname)'`).
|
||||
+
|
||||
Note that you cannot generally put `git for-each-ref` directly into the config
|
||||
value, as it does not take a repository path as an argument (but you can wrap
|
||||
the command above in a shell script).
|
||||
|
||||
core.alternateRefsPrefixes::
|
||||
When listing references from an alternate, list only references that begin
|
||||
with the given prefix. Prefixes match as if they were given as arguments to
|
||||
linkgit:git-for-each-ref[1]. To list multiple prefixes, separate them with
|
||||
whitespace. If `core.alternateRefsCommand` is set, setting
|
||||
`core.alternateRefsPrefixes` has no effect.
|
||||
|
||||
core.bare::
|
||||
If true this repository is assumed to be 'bare' and has no
|
||||
working directory associated with it. If this is the case a
|
||||
|
@ -281,8 +281,7 @@ static int show_ref_cb(const char *path_full, const struct object_id *oid,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void show_one_alternate_ref(const char *refname,
|
||||
const struct object_id *oid,
|
||||
static void show_one_alternate_ref(const struct object_id *oid,
|
||||
void *data)
|
||||
{
|
||||
struct oidset *seen = data;
|
||||
|
@ -76,8 +76,7 @@ struct alternate_object_cache {
|
||||
size_t nr, alloc;
|
||||
};
|
||||
|
||||
static void cache_one_alternate(const char *refname,
|
||||
const struct object_id *oid,
|
||||
static void cache_one_alternate(const struct object_id *oid,
|
||||
void *vcache)
|
||||
{
|
||||
struct alternate_object_cache *cache = vcache;
|
||||
|
41
t/t5410-receive-pack-alternates.sh
Executable file
41
t/t5410-receive-pack-alternates.sh
Executable file
@ -0,0 +1,41 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='git receive-pack with alternate ref filtering'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'setup' '
|
||||
test_commit base &&
|
||||
git clone -s --bare . fork &&
|
||||
git checkout -b public/branch master &&
|
||||
test_commit public &&
|
||||
git checkout -b private/branch master &&
|
||||
test_commit private
|
||||
'
|
||||
|
||||
extract_haves () {
|
||||
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)" \
|
||||
refs/heads/public/
|
||||
EOF
|
||||
test_config -C fork core.alternateRefsCommand alternate-refs &&
|
||||
git rev-parse public/branch >expect &&
|
||||
printf "0000" | git receive-pack fork >actual &&
|
||||
extract_haves <actual >actual.haves &&
|
||||
test_cmp expect actual.haves
|
||||
'
|
||||
|
||||
test_expect_success 'with core.alternateRefsPrefixes' '
|
||||
test_config -C fork core.alternateRefsPrefixes "refs/heads/private" &&
|
||||
git rev-parse private/branch >expect &&
|
||||
printf "0000" | git receive-pack fork >actual &&
|
||||
extract_haves <actual >actual.haves &&
|
||||
test_cmp expect actual.haves
|
||||
'
|
||||
|
||||
test_done
|
38
transport.c
38
transport.c
@ -1370,6 +1370,33 @@ literal_copy:
|
||||
return xstrdup(url);
|
||||
}
|
||||
|
||||
static void fill_alternate_refs_command(struct child_process *cmd,
|
||||
const char *repo_path)
|
||||
{
|
||||
const char *value;
|
||||
|
||||
if (!git_config_get_value("core.alternateRefsCommand", &value)) {
|
||||
cmd->use_shell = 1;
|
||||
|
||||
argv_array_push(&cmd->args, value);
|
||||
argv_array_push(&cmd->args, repo_path);
|
||||
} else {
|
||||
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)");
|
||||
|
||||
if (!git_config_get_value("core.alternateRefsPrefixes", &value)) {
|
||||
argv_array_push(&cmd->args, "--");
|
||||
argv_array_split(&cmd->args, value);
|
||||
}
|
||||
}
|
||||
|
||||
cmd->env = local_repo_env;
|
||||
cmd->out = -1;
|
||||
}
|
||||
|
||||
static void read_alternate_refs(const char *path,
|
||||
alternate_ref_fn *cb,
|
||||
void *data)
|
||||
@ -1378,12 +1405,7 @@ static void read_alternate_refs(const char *path,
|
||||
struct strbuf line = STRBUF_INIT;
|
||||
FILE *fh;
|
||||
|
||||
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)");
|
||||
cmd.env = local_repo_env;
|
||||
cmd.out = -1;
|
||||
fill_alternate_refs_command(&cmd, path);
|
||||
|
||||
if (start_command(&cmd))
|
||||
return;
|
||||
@ -1393,13 +1415,13 @@ static void read_alternate_refs(const char *path,
|
||||
struct object_id oid;
|
||||
|
||||
if (get_oid_hex(line.buf, &oid) ||
|
||||
line.buf[GIT_SHA1_HEXSZ] != ' ') {
|
||||
line.buf[GIT_SHA1_HEXSZ]) {
|
||||
warning(_("invalid line while parsing alternate refs: %s"),
|
||||
line.buf);
|
||||
break;
|
||||
}
|
||||
|
||||
cb(line.buf + GIT_SHA1_HEXSZ + 1, &oid, data);
|
||||
cb(&oid, data);
|
||||
}
|
||||
|
||||
fclose(fh);
|
||||
|
@ -261,6 +261,6 @@ int transport_refs_pushed(struct ref *ref);
|
||||
void transport_print_push_status(const char *dest, struct ref *refs,
|
||||
int verbose, int porcelain, unsigned int *reject_reasons);
|
||||
|
||||
typedef void alternate_ref_fn(const char *refname, const struct object_id *oid, void *);
|
||||
typedef void alternate_ref_fn(const struct object_id *oid, void *);
|
||||
extern void for_each_alternate_ref(alternate_ref_fn, void *);
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user