summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2019-07-19 18:30:21 (GMT)
committerJunio C Hamano <gitster@pobox.com>2019-07-19 18:30:21 (GMT)
commit68e65ded5b790bfd8a1072a7f551a8f283f62f29 (patch)
treecb8013cd29b7766aa63ba5812fd172aefcdbc0d6
parent1eb0a12ec3934b7fc398b118806fdf7550ae636e (diff)
parent39b44ba771a315602fd1fdca2e12dfc31ef9c613 (diff)
downloadgit-68e65ded5b790bfd8a1072a7f551a8f283f62f29.zip
git-68e65ded5b790bfd8a1072a7f551a8f283f62f29.tar.gz
git-68e65ded5b790bfd8a1072a7f551a8f283f62f29.tar.bz2
Merge branch 'jk/check-connected-with-alternates'
The tips of refs from the alternate object store can be used as starting point for reachability computation now. * jk/check-connected-with-alternates: check_everything_connected: assume alternate ref tips are valid object-store.h: move for_each_alternate_ref() from transport.h
-rw-r--r--Documentation/rev-list-options.txt8
-rw-r--r--builtin/receive-pack.c1
-rw-r--r--connected.c1
-rw-r--r--object-store.h2
-rw-r--r--revision.c29
-rw-r--r--sha1-file.c97
-rwxr-xr-xt/perf/p5600-clone-reference.sh27
-rwxr-xr-xt/t5618-alternate-refs.sh60
-rw-r--r--transport.c97
-rw-r--r--transport.h2
10 files changed, 224 insertions, 100 deletions
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 286fc16..bb1251c 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -182,6 +182,14 @@ explicitly.
Pretend as if all objects mentioned by reflogs are listed on the
command line as `<commit>`.
+--alternate-refs::
+ 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
+ be modified by `core.alternateRefsCommand`, etc. See
+ linkgit:git-config[1].
+
--single-worktree::
By default, all working trees will be examined by the
following options when there are more than one (see
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 610eadf..dcf3855 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -12,7 +12,6 @@
#include "object.h"
#include "remote.h"
#include "connect.h"
-#include "transport.h"
#include "string-list.h"
#include "sha1-array.h"
#include "connected.h"
diff --git a/connected.c b/connected.c
index 1ab481f..cd9b324 100644
--- a/connected.c
+++ b/connected.c
@@ -80,6 +80,7 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
argv_array_push(&rev_list.args, "--all");
}
argv_array_push(&rev_list.args, "--quiet");
+ argv_array_push(&rev_list.args, "--alternate-refs");
if (opt->progress)
argv_array_pushf(&rev_list.args, "--progress=%s",
_("Checking connectivity"));
diff --git a/object-store.h b/object-store.h
index 49f56ab..7f7b3cd 100644
--- a/object-store.h
+++ b/object-store.h
@@ -33,6 +33,8 @@ void prepare_alt_odb(struct repository *r);
char *compute_alternate_path(const char *path, struct strbuf *err);
typedef int alt_odb_fn(struct object_directory *, void *);
int foreach_alt_odb(alt_odb_fn, void*);
+typedef void alternate_ref_fn(const struct object_id *oid, void *);
+void for_each_alternate_ref(alternate_ref_fn, void *);
/*
* Add the directory to the on-disk alternates file; the new entry will also
diff --git a/revision.c b/revision.c
index 621feb9..0741229 100644
--- a/revision.c
+++ b/revision.c
@@ -1554,6 +1554,32 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
free_worktrees(worktrees);
}
+struct add_alternate_refs_data {
+ struct rev_info *revs;
+ unsigned int flags;
+};
+
+static void add_one_alternate_ref(const struct object_id *oid,
+ void *vdata)
+{
+ const char *name = ".alternate";
+ struct add_alternate_refs_data *data = vdata;
+ struct object *obj;
+
+ obj = get_reference(data->revs, name, oid, data->flags);
+ add_rev_cmdline(data->revs, obj, name, REV_CMD_REV, data->flags);
+ add_pending_object(data->revs, obj, name);
+}
+
+static void add_alternate_refs_to_pending(struct rev_info *revs,
+ unsigned int flags)
+{
+ struct add_alternate_refs_data data;
+ data.revs = revs;
+ data.flags = flags;
+ for_each_alternate_ref(add_one_alternate_ref, &data);
+}
+
static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
int exclude_parent)
{
@@ -1956,6 +1982,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
!strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") ||
!strcmp(arg, "--bisect") || starts_with(arg, "--glob=") ||
!strcmp(arg, "--indexed-objects") ||
+ !strcmp(arg, "--alternate-refs") ||
starts_with(arg, "--exclude=") ||
starts_with(arg, "--branches=") || starts_with(arg, "--tags=") ||
starts_with(arg, "--remotes=") || starts_with(arg, "--no-walk="))
@@ -2442,6 +2469,8 @@ static int handle_revision_pseudo_opt(const char *submodule,
add_reflogs_to_pending(revs, *flags);
} else if (!strcmp(arg, "--indexed-objects")) {
add_index_objects_to_pending(revs, *flags);
+ } else if (!strcmp(arg, "--alternate-refs")) {
+ add_alternate_refs_to_pending(revs, *flags);
} else if (!strcmp(arg, "--not")) {
*flags ^= UNINTERESTING | BOTTOM;
} else if (!strcmp(arg, "--no-walk")) {
diff --git a/sha1-file.c b/sha1-file.c
index 59b2e40..84fd02f 100644
--- a/sha1-file.c
+++ b/sha1-file.c
@@ -743,6 +743,103 @@ out:
return ref_git;
}
+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)
+{
+ struct child_process cmd = CHILD_PROCESS_INIT;
+ struct strbuf line = STRBUF_INIT;
+ FILE *fh;
+
+ fill_alternate_refs_command(&cmd, path);
+
+ if (start_command(&cmd))
+ return;
+
+ fh = xfdopen(cmd.out, "r");
+ while (strbuf_getline_lf(&line, fh) != EOF) {
+ struct object_id oid;
+ const char *p;
+
+ if (parse_oid_hex(line.buf, &oid, &p) || *p) {
+ warning(_("invalid line while parsing alternate refs: %s"),
+ line.buf);
+ break;
+ }
+
+ cb(&oid, data);
+ }
+
+ fclose(fh);
+ finish_command(&cmd);
+}
+
+struct alternate_refs_data {
+ alternate_ref_fn *fn;
+ void *data;
+};
+
+static int refs_from_alternate_cb(struct object_directory *e,
+ void *data)
+{
+ struct strbuf path = STRBUF_INIT;
+ size_t base_len;
+ struct alternate_refs_data *cb = data;
+
+ if (!strbuf_realpath(&path, e->path, 0))
+ goto out;
+ if (!strbuf_strip_suffix(&path, "/objects"))
+ goto out;
+ base_len = path.len;
+
+ /* Is this a git repository with refs? */
+ strbuf_addstr(&path, "/refs");
+ if (!is_directory(path.buf))
+ goto out;
+ strbuf_setlen(&path, base_len);
+
+ read_alternate_refs(path.buf, cb->fn, cb->data);
+
+out:
+ strbuf_release(&path);
+ return 0;
+}
+
+void for_each_alternate_ref(alternate_ref_fn fn, void *data)
+{
+ struct alternate_refs_data cb;
+ cb.fn = fn;
+ cb.data = data;
+ foreach_alt_odb(refs_from_alternate_cb, &cb);
+}
+
int foreach_alt_odb(alt_odb_fn fn, void *cb)
{
struct object_directory *ent;
diff --git a/t/perf/p5600-clone-reference.sh b/t/perf/p5600-clone-reference.sh
new file mode 100755
index 0000000..68fed66
--- /dev/null
+++ b/t/perf/p5600-clone-reference.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+test_description='speed of clone --reference'
+. ./perf-lib.sh
+
+test_perf_default_repo
+
+test_expect_success 'create shareable repository' '
+ git clone --bare . shared.git
+'
+
+test_expect_success 'advance base repository' '
+ # Do not use test_commit here; its test_tick will
+ # use some ancient hard-coded date. The resulting clock
+ # skew will cause pack-objects to traverse in a very
+ # sub-optimal order, skewing the results.
+ echo content >new-file-that-does-not-exist &&
+ git add new-file-that-does-not-exist &&
+ git commit -m "new commit"
+'
+
+test_perf 'clone --reference' '
+ rm -rf dst.git &&
+ git clone --no-local --bare --reference shared.git . dst.git
+'
+
+test_done
diff --git a/t/t5618-alternate-refs.sh b/t/t5618-alternate-refs.sh
new file mode 100755
index 0000000..3353216
--- /dev/null
+++ b/t/t5618-alternate-refs.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+test_description='test handling of --alternate-refs traversal'
+. ./test-lib.sh
+
+# Avoid test_commit because we want a specific and known set of refs:
+#
+# base -- one
+# \ \
+# two -- merged
+#
+# where "one" and "two" are on separate refs, and "merged" is available only in
+# the dependent child repository.
+test_expect_success 'set up local refs' '
+ git checkout -b one &&
+ test_tick &&
+ git commit --allow-empty -m base &&
+ test_tick &&
+ git commit --allow-empty -m one &&
+ git checkout -b two HEAD^ &&
+ test_tick &&
+ git commit --allow-empty -m two
+'
+
+# We'll enter the child repository after it's set up since that's where
+# all of the subsequent tests will want to run (and it's easy to forget a
+# "-C child" and get nonsense results).
+test_expect_success 'set up shared clone' '
+ git clone -s . child &&
+ cd child &&
+ git merge origin/one
+'
+
+test_expect_success 'rev-list --alternate-refs' '
+ git rev-list --remotes=origin >expect &&
+ git rev-list --alternate-refs >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-list --not --alternate-refs' '
+ git rev-parse HEAD >expect &&
+ git rev-list HEAD --not --alternate-refs >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'limiting with alternateRefsPrefixes' '
+ test_config core.alternateRefsPrefixes refs/heads/one &&
+ git rev-list origin/one >expect &&
+ git rev-list --alternate-refs >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --source shows .alternate marker' '
+ git log --oneline --source --remotes=origin >expect.orig &&
+ sed "s/origin.* /.alternate /" <expect.orig >expect &&
+ git log --oneline --source --alternate-refs >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/transport.c b/transport.c
index f1fcd2c..2def5a0 100644
--- a/transport.c
+++ b/transport.c
@@ -1380,100 +1380,3 @@ char *transport_anonymize_url(const char *url)
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)
-{
- struct child_process cmd = CHILD_PROCESS_INIT;
- struct strbuf line = STRBUF_INIT;
- FILE *fh;
-
- fill_alternate_refs_command(&cmd, path);
-
- if (start_command(&cmd))
- return;
-
- fh = xfdopen(cmd.out, "r");
- while (strbuf_getline_lf(&line, fh) != EOF) {
- struct object_id oid;
- const char *p;
-
- if (parse_oid_hex(line.buf, &oid, &p) || *p) {
- warning(_("invalid line while parsing alternate refs: %s"),
- line.buf);
- break;
- }
-
- cb(&oid, data);
- }
-
- fclose(fh);
- finish_command(&cmd);
-}
-
-struct alternate_refs_data {
- alternate_ref_fn *fn;
- void *data;
-};
-
-static int refs_from_alternate_cb(struct object_directory *e,
- void *data)
-{
- struct strbuf path = STRBUF_INIT;
- size_t base_len;
- struct alternate_refs_data *cb = data;
-
- if (!strbuf_realpath(&path, e->path, 0))
- goto out;
- if (!strbuf_strip_suffix(&path, "/objects"))
- goto out;
- base_len = path.len;
-
- /* Is this a git repository with refs? */
- strbuf_addstr(&path, "/refs");
- if (!is_directory(path.buf))
- goto out;
- strbuf_setlen(&path, base_len);
-
- read_alternate_refs(path.buf, cb->fn, cb->data);
-
-out:
- strbuf_release(&path);
- return 0;
-}
-
-void for_each_alternate_ref(alternate_ref_fn fn, void *data)
-{
- struct alternate_refs_data cb;
- cb.fn = fn;
- cb.data = data;
- foreach_alt_odb(refs_from_alternate_cb, &cb);
-}
diff --git a/transport.h b/transport.h
index 06e06d3..0b5f780 100644
--- a/transport.h
+++ b/transport.h
@@ -262,6 +262,4 @@ 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 struct object_id *oid, void *);
-void for_each_alternate_ref(alternate_ref_fn, void *);
#endif