зеркало из https://github.com/microsoft/git.git
Merge branch 'cc/multi-promisor'
Teach the lazy clone machinery that there can be more than one promisor remote and consult them in order when downloading missing objects on demand. * cc/multi-promisor: Move core_partial_clone_filter_default to promisor-remote.c Move repository_format_partial_clone to promisor-remote.c Remove fetch-object.{c,h} in favor of promisor-remote.{c,h} remote: add promisor and partial clone config to the doc partial-clone: add multiple remotes in the doc t0410: test fetching from many promisor remotes builtin/fetch: remove unique promisor remote limitation promisor-remote: parse remote.*.partialclonefilter Use promisor_remote_get_direct() and has_promisor_remote() promisor-remote: use repository_format_partial_clone promisor-remote: add promisor_remote_reinit() promisor-remote: implement promisor_remote_get_direct() Add initial support for many promisor remotes fetch-object: make functions return an error code t0410: remove pipes after git commands
This commit is contained in:
Коммит
b9ac6c59b8
|
@ -76,3 +76,11 @@ remote.<name>.pruneTags::
|
||||||
+
|
+
|
||||||
See also `remote.<name>.prune` and the PRUNING section of
|
See also `remote.<name>.prune` and the PRUNING section of
|
||||||
linkgit:git-fetch[1].
|
linkgit:git-fetch[1].
|
||||||
|
|
||||||
|
remote.<name>.promisor::
|
||||||
|
When set to true, this remote will be used to fetch promisor
|
||||||
|
objects.
|
||||||
|
|
||||||
|
remote.<name>.partialclonefilter::
|
||||||
|
The filter that will be applied when fetching from this
|
||||||
|
promisor remote.
|
||||||
|
|
|
@ -30,12 +30,20 @@ advance* during clone and fetch operations and thereby reduce download
|
||||||
times and disk usage. Missing objects can later be "demand fetched"
|
times and disk usage. Missing objects can later be "demand fetched"
|
||||||
if/when needed.
|
if/when needed.
|
||||||
|
|
||||||
|
A remote that can later provide the missing objects is called a
|
||||||
|
promisor remote, as it promises to send the objects when
|
||||||
|
requested. Initialy Git supported only one promisor remote, the origin
|
||||||
|
remote from which the user cloned and that was configured in the
|
||||||
|
"extensions.partialClone" config option. Later support for more than
|
||||||
|
one promisor remote has been implemented.
|
||||||
|
|
||||||
Use of partial clone requires that the user be online and the origin
|
Use of partial clone requires that the user be online and the origin
|
||||||
remote be available for on-demand fetching of missing objects. This may
|
remote or other promisor remotes be available for on-demand fetching
|
||||||
or may not be problematic for the user. For example, if the user can
|
of missing objects. This may or may not be problematic for the user.
|
||||||
stay within the pre-selected subset of the source tree, they may not
|
For example, if the user can stay within the pre-selected subset of
|
||||||
encounter any missing objects. Alternatively, the user could try to
|
the source tree, they may not encounter any missing objects.
|
||||||
pre-fetch various objects if they know that they are going offline.
|
Alternatively, the user could try to pre-fetch various objects if they
|
||||||
|
know that they are going offline.
|
||||||
|
|
||||||
|
|
||||||
Non-Goals
|
Non-Goals
|
||||||
|
@ -100,18 +108,18 @@ or commits that reference missing trees.
|
||||||
Handling Missing Objects
|
Handling Missing Objects
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
- An object may be missing due to a partial clone or fetch, or missing due
|
- An object may be missing due to a partial clone or fetch, or missing
|
||||||
to repository corruption. To differentiate these cases, the local
|
due to repository corruption. To differentiate these cases, the
|
||||||
repository specially indicates such filtered packfiles obtained from the
|
local repository specially indicates such filtered packfiles
|
||||||
promisor remote as "promisor packfiles".
|
obtained from promisor remotes as "promisor packfiles".
|
||||||
+
|
+
|
||||||
These promisor packfiles consist of a "<name>.promisor" file with
|
These promisor packfiles consist of a "<name>.promisor" file with
|
||||||
arbitrary contents (like the "<name>.keep" files), in addition to
|
arbitrary contents (like the "<name>.keep" files), in addition to
|
||||||
their "<name>.pack" and "<name>.idx" files.
|
their "<name>.pack" and "<name>.idx" files.
|
||||||
|
|
||||||
- The local repository considers a "promisor object" to be an object that
|
- The local repository considers a "promisor object" to be an object that
|
||||||
it knows (to the best of its ability) that the promisor remote has promised
|
it knows (to the best of its ability) that promisor remotes have promised
|
||||||
that it has, either because the local repository has that object in one of
|
that they have, either because the local repository has that object in one of
|
||||||
its promisor packfiles, or because another promisor object refers to it.
|
its promisor packfiles, or because another promisor object refers to it.
|
||||||
+
|
+
|
||||||
When Git encounters a missing object, Git can see if it is a promisor object
|
When Git encounters a missing object, Git can see if it is a promisor object
|
||||||
|
@ -123,12 +131,12 @@ expensive-to-modify list of missing objects.[a]
|
||||||
- Since almost all Git code currently expects any referenced object to be
|
- Since almost all Git code currently expects any referenced object to be
|
||||||
present locally and because we do not want to force every command to do
|
present locally and because we do not want to force every command to do
|
||||||
a dry-run first, a fallback mechanism is added to allow Git to attempt
|
a dry-run first, a fallback mechanism is added to allow Git to attempt
|
||||||
to dynamically fetch missing objects from the promisor remote.
|
to dynamically fetch missing objects from promisor remotes.
|
||||||
+
|
+
|
||||||
When the normal object lookup fails to find an object, Git invokes
|
When the normal object lookup fails to find an object, Git invokes
|
||||||
fetch-object to try to get the object from the server and then retry
|
promisor_remote_get_direct() to try to get the object from a promisor
|
||||||
the object lookup. This allows objects to be "faulted in" without
|
remote and then retry the object lookup. This allows objects to be
|
||||||
complicated prediction algorithms.
|
"faulted in" without complicated prediction algorithms.
|
||||||
+
|
+
|
||||||
For efficiency reasons, no check as to whether the missing object is
|
For efficiency reasons, no check as to whether the missing object is
|
||||||
actually a promisor object is performed.
|
actually a promisor object is performed.
|
||||||
|
@ -157,8 +165,7 @@ and prefetch those objects in bulk.
|
||||||
+
|
+
|
||||||
We are not happy with this global variable and would like to remove it,
|
We are not happy with this global variable and would like to remove it,
|
||||||
but that requires significant refactoring of the object code to pass an
|
but that requires significant refactoring of the object code to pass an
|
||||||
additional flag. We hope that concurrent efforts to add an ODB API can
|
additional flag.
|
||||||
encompass this.
|
|
||||||
|
|
||||||
|
|
||||||
Fetching Missing Objects
|
Fetching Missing Objects
|
||||||
|
@ -182,21 +189,63 @@ has been updated to not use any object flags when the corresponding argument
|
||||||
though they are not necessary.
|
though they are not necessary.
|
||||||
|
|
||||||
|
|
||||||
|
Using many promisor remotes
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Many promisor remotes can be configured and used.
|
||||||
|
|
||||||
|
This allows for example a user to have multiple geographically-close
|
||||||
|
cache servers for fetching missing blobs while continuing to do
|
||||||
|
filtered `git-fetch` commands from the central server.
|
||||||
|
|
||||||
|
When fetching objects, promisor remotes are tried one after the other
|
||||||
|
until all the objects have been fetched.
|
||||||
|
|
||||||
|
Remotes that are considered "promisor" remotes are those specified by
|
||||||
|
the following configuration variables:
|
||||||
|
|
||||||
|
- `extensions.partialClone = <name>`
|
||||||
|
|
||||||
|
- `remote.<name>.promisor = true`
|
||||||
|
|
||||||
|
- `remote.<name>.partialCloneFilter = ...`
|
||||||
|
|
||||||
|
Only one promisor remote can be configured using the
|
||||||
|
`extensions.partialClone` config variable. This promisor remote will
|
||||||
|
be the last one tried when fetching objects.
|
||||||
|
|
||||||
|
We decided to make it the last one we try, because it is likely that
|
||||||
|
someone using many promisor remotes is doing so because the other
|
||||||
|
promisor remotes are better for some reason (maybe they are closer or
|
||||||
|
faster for some kind of objects) than the origin, and the origin is
|
||||||
|
likely to be the remote specified by extensions.partialClone.
|
||||||
|
|
||||||
|
This justification is not very strong, but one choice had to be made,
|
||||||
|
and anyway the long term plan should be to make the order somehow
|
||||||
|
fully configurable.
|
||||||
|
|
||||||
|
For now though the other promisor remotes will be tried in the order
|
||||||
|
they appear in the config file.
|
||||||
|
|
||||||
Current Limitations
|
Current Limitations
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
- The remote used for a partial clone (or the first partial fetch
|
- It is not possible to specify the order in which the promisor
|
||||||
following a regular clone) is marked as the "promisor remote".
|
remotes are tried in other ways than the order in which they appear
|
||||||
|
in the config file.
|
||||||
+
|
+
|
||||||
We are currently limited to a single promisor remote and only that
|
It is also not possible to specify an order to be used when fetching
|
||||||
remote may be used for subsequent partial fetches.
|
from one remote and a different order when fetching from another
|
||||||
+
|
remote.
|
||||||
We accept this limitation because we believe initial users of this
|
|
||||||
feature will be using it on repositories with a strong single central
|
|
||||||
server.
|
|
||||||
|
|
||||||
- Dynamic object fetching will only ask the promisor remote for missing
|
- It is not possible to push only specific objects to a promisor
|
||||||
objects. We assume that the promisor remote has a complete view of the
|
remote.
|
||||||
|
+
|
||||||
|
It is not possible to push at the same time to multiple promisor
|
||||||
|
remote in a specific order.
|
||||||
|
|
||||||
|
- Dynamic object fetching will only ask promisor remotes for missing
|
||||||
|
objects. We assume that promisor remotes have a complete view of the
|
||||||
repository and can satisfy all such requests.
|
repository and can satisfy all such requests.
|
||||||
|
|
||||||
- Repack essentially treats promisor and non-promisor packfiles as 2
|
- Repack essentially treats promisor and non-promisor packfiles as 2
|
||||||
|
@ -218,15 +267,17 @@ server.
|
||||||
Future Work
|
Future Work
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
- Allow more than one promisor remote and define a strategy for fetching
|
- Improve the way to specify the order in which promisor remotes are
|
||||||
missing objects from specific promisor remotes or of iterating over the
|
tried.
|
||||||
set of promisor remotes until a missing object is found.
|
|
||||||
+
|
+
|
||||||
A user might want to have multiple geographically-close cache servers
|
For example this could allow to specify explicitly something like:
|
||||||
for fetching missing blobs while continuing to do filtered `git-fetch`
|
"When fetching from this remote, I want to use these promisor remotes
|
||||||
commands from the central server, for example.
|
in this order, though, when pushing or fetching to that remote, I want
|
||||||
|
to use those promisor remotes in that order."
|
||||||
|
|
||||||
|
- Allow pushing to promisor remotes.
|
||||||
+
|
+
|
||||||
Or the user might want to work in a triangular work flow with multiple
|
The user might want to work in a triangular work flow with multiple
|
||||||
promisor remotes that each have an incomplete view of the repository.
|
promisor remotes that each have an incomplete view of the repository.
|
||||||
|
|
||||||
- Allow repack to work on promisor packfiles (while keeping them distinct
|
- Allow repack to work on promisor packfiles (while keeping them distinct
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -884,7 +884,6 @@ LIB_OBJS += ewah/ewah_io.o
|
||||||
LIB_OBJS += ewah/ewah_rlw.o
|
LIB_OBJS += ewah/ewah_rlw.o
|
||||||
LIB_OBJS += exec-cmd.o
|
LIB_OBJS += exec-cmd.o
|
||||||
LIB_OBJS += fetch-negotiator.o
|
LIB_OBJS += fetch-negotiator.o
|
||||||
LIB_OBJS += fetch-object.o
|
|
||||||
LIB_OBJS += fetch-pack.o
|
LIB_OBJS += fetch-pack.o
|
||||||
LIB_OBJS += fsck.o
|
LIB_OBJS += fsck.o
|
||||||
LIB_OBJS += fsmonitor.o
|
LIB_OBJS += fsmonitor.o
|
||||||
|
@ -948,6 +947,7 @@ LIB_OBJS += preload-index.o
|
||||||
LIB_OBJS += pretty.o
|
LIB_OBJS += pretty.o
|
||||||
LIB_OBJS += prio-queue.o
|
LIB_OBJS += prio-queue.o
|
||||||
LIB_OBJS += progress.o
|
LIB_OBJS += progress.o
|
||||||
|
LIB_OBJS += promisor-remote.o
|
||||||
LIB_OBJS += prompt.o
|
LIB_OBJS += prompt.o
|
||||||
LIB_OBJS += protocol.o
|
LIB_OBJS += protocol.o
|
||||||
LIB_OBJS += quote.o
|
LIB_OBJS += quote.o
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "sha1-array.h"
|
#include "sha1-array.h"
|
||||||
#include "packfile.h"
|
#include "packfile.h"
|
||||||
#include "object-store.h"
|
#include "object-store.h"
|
||||||
|
#include "promisor-remote.h"
|
||||||
|
|
||||||
struct batch_options {
|
struct batch_options {
|
||||||
int enabled;
|
int enabled;
|
||||||
|
@ -524,8 +525,8 @@ static int batch_objects(struct batch_options *opt)
|
||||||
if (opt->all_objects) {
|
if (opt->all_objects) {
|
||||||
struct object_cb_data cb;
|
struct object_cb_data cb;
|
||||||
|
|
||||||
if (repository_format_partial_clone)
|
if (has_promisor_remote())
|
||||||
warning("This repository has extensions.partialClone set. Some objects may not be loaded.");
|
warning("This repository uses promisor remotes. Some objects may not be loaded.");
|
||||||
|
|
||||||
cb.opt = opt;
|
cb.opt = opt;
|
||||||
cb.expand = &data;
|
cb.expand = &data;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "list-objects-filter-options.h"
|
#include "list-objects-filter-options.h"
|
||||||
#include "commit-reach.h"
|
#include "commit-reach.h"
|
||||||
#include "branch.h"
|
#include "branch.h"
|
||||||
|
#include "promisor-remote.h"
|
||||||
|
|
||||||
#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
|
#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
|
||||||
|
|
||||||
|
@ -1559,37 +1560,27 @@ static inline void fetch_one_setup_partial(struct remote *remote)
|
||||||
* If no prior partial clone/fetch and the current fetch DID NOT
|
* If no prior partial clone/fetch and the current fetch DID NOT
|
||||||
* request a partial-fetch, do a normal fetch.
|
* request a partial-fetch, do a normal fetch.
|
||||||
*/
|
*/
|
||||||
if (!repository_format_partial_clone && !filter_options.choice)
|
if (!has_promisor_remote() && !filter_options.choice)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is the FIRST partial-fetch request, we enable partial
|
* If this is a partial-fetch request, we enable partial on
|
||||||
* on this repo and remember the given filter-spec as the default
|
* this repo if not already enabled and remember the given
|
||||||
* for subsequent fetches to this remote.
|
* filter-spec as the default for subsequent fetches to this
|
||||||
|
* remote.
|
||||||
*/
|
*/
|
||||||
if (!repository_format_partial_clone && filter_options.choice) {
|
if (filter_options.choice) {
|
||||||
partial_clone_register(remote->name, &filter_options);
|
partial_clone_register(remote->name, &filter_options);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* We are currently limited to only ONE promisor remote and only
|
|
||||||
* allow partial-fetches from the promisor remote.
|
|
||||||
*/
|
|
||||||
if (strcmp(remote->name, repository_format_partial_clone)) {
|
|
||||||
if (filter_options.choice)
|
|
||||||
die(_("--filter can only be used with the remote "
|
|
||||||
"configured in extensions.partialClone"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do a partial-fetch from the promisor remote using either the
|
* Do a partial-fetch from the promisor remote using either the
|
||||||
* explicitly given filter-spec or inherit the filter-spec from
|
* explicitly given filter-spec or inherit the filter-spec from
|
||||||
* the config.
|
* the config.
|
||||||
*/
|
*/
|
||||||
if (!filter_options.choice)
|
if (!filter_options.choice)
|
||||||
partial_clone_get_default_filter_spec(&filter_options);
|
partial_clone_get_default_filter_spec(&filter_options, remote->name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1710,7 +1701,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
|
||||||
if (depth || deepen_since || deepen_not.nr)
|
if (depth || deepen_since || deepen_not.nr)
|
||||||
deepen = 1;
|
deepen = 1;
|
||||||
|
|
||||||
if (filter_options.choice && !repository_format_partial_clone)
|
if (filter_options.choice && !has_promisor_remote())
|
||||||
die("--filter can only be used when extensions.partialClone is set");
|
die("--filter can only be used when extensions.partialClone is set");
|
||||||
|
|
||||||
if (all) {
|
if (all) {
|
||||||
|
@ -1744,7 +1735,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remote) {
|
if (remote) {
|
||||||
if (filter_options.choice || repository_format_partial_clone)
|
if (filter_options.choice || has_promisor_remote())
|
||||||
fetch_one_setup_partial(remote);
|
fetch_one_setup_partial(remote);
|
||||||
result = fetch_one(remote, argc, argv, prune_tags_ok);
|
result = fetch_one(remote, argc, argv, prune_tags_ok);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "pack-objects.h"
|
#include "pack-objects.h"
|
||||||
#include "blob.h"
|
#include "blob.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
|
#include "promisor-remote.h"
|
||||||
|
|
||||||
#define FAILED_RUN "failed to run %s"
|
#define FAILED_RUN "failed to run %s"
|
||||||
|
|
||||||
|
@ -659,7 +660,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
||||||
argv_array_push(&prune, prune_expire);
|
argv_array_push(&prune, prune_expire);
|
||||||
if (quiet)
|
if (quiet)
|
||||||
argv_array_push(&prune, "--no-progress");
|
argv_array_push(&prune, "--no-progress");
|
||||||
if (repository_format_partial_clone)
|
if (has_promisor_remote())
|
||||||
argv_array_push(&prune,
|
argv_array_push(&prune,
|
||||||
"--exclude-promisor-objects");
|
"--exclude-promisor-objects");
|
||||||
if (run_command_v_opt(prune.argv, RUN_GIT_CMD))
|
if (run_command_v_opt(prune.argv, RUN_GIT_CMD))
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include "thread-utils.h"
|
#include "thread-utils.h"
|
||||||
#include "packfile.h"
|
#include "packfile.h"
|
||||||
#include "object-store.h"
|
#include "object-store.h"
|
||||||
#include "fetch-object.h"
|
#include "promisor-remote.h"
|
||||||
|
|
||||||
static const char index_pack_usage[] =
|
static const char index_pack_usage[] =
|
||||||
"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
|
"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
|
||||||
|
@ -1352,7 +1352,7 @@ static void fix_unresolved_deltas(struct hashfile *f)
|
||||||
sorted_by_pos[i] = &ref_deltas[i];
|
sorted_by_pos[i] = &ref_deltas[i];
|
||||||
QSORT(sorted_by_pos, nr_ref_deltas, delta_pos_compare);
|
QSORT(sorted_by_pos, nr_ref_deltas, delta_pos_compare);
|
||||||
|
|
||||||
if (repository_format_partial_clone) {
|
if (has_promisor_remote()) {
|
||||||
/*
|
/*
|
||||||
* Prefetch the delta bases.
|
* Prefetch the delta bases.
|
||||||
*/
|
*/
|
||||||
|
@ -1366,8 +1366,8 @@ static void fix_unresolved_deltas(struct hashfile *f)
|
||||||
oid_array_append(&to_fetch, &d->oid);
|
oid_array_append(&to_fetch, &d->oid);
|
||||||
}
|
}
|
||||||
if (to_fetch.nr)
|
if (to_fetch.nr)
|
||||||
fetch_objects(repository_format_partial_clone,
|
promisor_remote_get_direct(the_repository,
|
||||||
to_fetch.oid, to_fetch.nr);
|
to_fetch.oid, to_fetch.nr);
|
||||||
oid_array_clear(&to_fetch);
|
oid_array_clear(&to_fetch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "midx.h"
|
#include "midx.h"
|
||||||
#include "packfile.h"
|
#include "packfile.h"
|
||||||
#include "object-store.h"
|
#include "object-store.h"
|
||||||
|
#include "promisor-remote.h"
|
||||||
|
|
||||||
static int delta_base_offset = 1;
|
static int delta_base_offset = 1;
|
||||||
static int pack_kept_objects = -1;
|
static int pack_kept_objects = -1;
|
||||||
|
@ -361,7 +362,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||||
argv_array_push(&cmd.args, "--all");
|
argv_array_push(&cmd.args, "--all");
|
||||||
argv_array_push(&cmd.args, "--reflog");
|
argv_array_push(&cmd.args, "--reflog");
|
||||||
argv_array_push(&cmd.args, "--indexed-objects");
|
argv_array_push(&cmd.args, "--indexed-objects");
|
||||||
if (repository_format_partial_clone)
|
if (has_promisor_remote())
|
||||||
argv_array_push(&cmd.args, "--exclude-promisor-objects");
|
argv_array_push(&cmd.args, "--exclude-promisor-objects");
|
||||||
if (write_bitmaps > 0)
|
if (write_bitmaps > 0)
|
||||||
argv_array_push(&cmd.args, "--write-bitmap-index");
|
argv_array_push(&cmd.args, "--write-bitmap-index");
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "cache-tree.h"
|
#include "cache-tree.h"
|
||||||
#include "object-store.h"
|
#include "object-store.h"
|
||||||
#include "replace-object.h"
|
#include "replace-object.h"
|
||||||
|
#include "promisor-remote.h"
|
||||||
|
|
||||||
#ifndef DEBUG_CACHE_TREE
|
#ifndef DEBUG_CACHE_TREE
|
||||||
#define DEBUG_CACHE_TREE 0
|
#define DEBUG_CACHE_TREE 0
|
||||||
|
@ -357,7 +358,7 @@ static int update_one(struct cache_tree *it,
|
||||||
}
|
}
|
||||||
|
|
||||||
ce_missing_ok = mode == S_IFGITLINK || missing_ok ||
|
ce_missing_ok = mode == S_IFGITLINK || missing_ok ||
|
||||||
(repository_format_partial_clone &&
|
(has_promisor_remote() &&
|
||||||
ce_skip_worktree(ce));
|
ce_skip_worktree(ce));
|
||||||
if (is_null_oid(oid) ||
|
if (is_null_oid(oid) ||
|
||||||
(!ce_missing_ok && !has_object_file(oid))) {
|
(!ce_missing_ok && !has_object_file(oid))) {
|
||||||
|
|
2
cache.h
2
cache.h
|
@ -937,8 +937,6 @@ extern int grafts_replace_parents;
|
||||||
#define GIT_REPO_VERSION 0
|
#define GIT_REPO_VERSION 0
|
||||||
#define GIT_REPO_VERSION_READ 1
|
#define GIT_REPO_VERSION_READ 1
|
||||||
extern int repository_format_precious_objects;
|
extern int repository_format_precious_objects;
|
||||||
extern char *repository_format_partial_clone;
|
|
||||||
extern const char *core_partial_clone_filter_default;
|
|
||||||
extern int repository_format_worktree_config;
|
extern int repository_format_worktree_config;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
5
config.c
5
config.c
|
@ -1379,11 +1379,6 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(var, "core.partialclonefilter")) {
|
|
||||||
return git_config_string(&core_partial_clone_filter_default,
|
|
||||||
var, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(var, "core.usereplacerefs")) {
|
if (!strcmp(var, "core.usereplacerefs")) {
|
||||||
read_replace_refs = git_config_bool(var, value);
|
read_replace_refs = git_config_bool(var, value);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "connected.h"
|
#include "connected.h"
|
||||||
#include "transport.h"
|
#include "transport.h"
|
||||||
#include "packfile.h"
|
#include "packfile.h"
|
||||||
|
#include "promisor-remote.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we feed all the commits we want to verify to this command
|
* If we feed all the commits we want to verify to this command
|
||||||
|
@ -73,7 +74,7 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
|
||||||
argv_array_push(&rev_list.args,"rev-list");
|
argv_array_push(&rev_list.args,"rev-list");
|
||||||
argv_array_push(&rev_list.args, "--objects");
|
argv_array_push(&rev_list.args, "--objects");
|
||||||
argv_array_push(&rev_list.args, "--stdin");
|
argv_array_push(&rev_list.args, "--stdin");
|
||||||
if (repository_format_partial_clone)
|
if (has_promisor_remote())
|
||||||
argv_array_push(&rev_list.args, "--exclude-promisor-objects");
|
argv_array_push(&rev_list.args, "--exclude-promisor-objects");
|
||||||
if (!opt->is_deepening_fetch) {
|
if (!opt->is_deepening_fetch) {
|
||||||
argv_array_push(&rev_list.args, "--not");
|
argv_array_push(&rev_list.args, "--not");
|
||||||
|
|
9
diff.c
9
diff.c
|
@ -25,7 +25,7 @@
|
||||||
#include "packfile.h"
|
#include "packfile.h"
|
||||||
#include "parse-options.h"
|
#include "parse-options.h"
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
#include "fetch-object.h"
|
#include "promisor-remote.h"
|
||||||
|
|
||||||
#ifdef NO_FAST_WORKING_DIRECTORY
|
#ifdef NO_FAST_WORKING_DIRECTORY
|
||||||
#define FAST_WORKING_DIRECTORY 0
|
#define FAST_WORKING_DIRECTORY 0
|
||||||
|
@ -6520,8 +6520,7 @@ static void add_if_missing(struct repository *r,
|
||||||
|
|
||||||
void diffcore_std(struct diff_options *options)
|
void diffcore_std(struct diff_options *options)
|
||||||
{
|
{
|
||||||
if (options->repo == the_repository &&
|
if (options->repo == the_repository && has_promisor_remote()) {
|
||||||
repository_format_partial_clone) {
|
|
||||||
/*
|
/*
|
||||||
* Prefetch the diff pairs that are about to be flushed.
|
* Prefetch the diff pairs that are about to be flushed.
|
||||||
*/
|
*/
|
||||||
|
@ -6538,8 +6537,8 @@ void diffcore_std(struct diff_options *options)
|
||||||
/*
|
/*
|
||||||
* NEEDSWORK: Consider deduplicating the OIDs sent.
|
* NEEDSWORK: Consider deduplicating the OIDs sent.
|
||||||
*/
|
*/
|
||||||
fetch_objects(repository_format_partial_clone,
|
promisor_remote_get_direct(options->repo,
|
||||||
to_fetch.oid, to_fetch.nr);
|
to_fetch.oid, to_fetch.nr);
|
||||||
oid_array_clear(&to_fetch);
|
oid_array_clear(&to_fetch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,8 +31,6 @@ int warn_ambiguous_refs = 1;
|
||||||
int warn_on_object_refname_ambiguity = 1;
|
int warn_on_object_refname_ambiguity = 1;
|
||||||
int ref_paranoia = -1;
|
int ref_paranoia = -1;
|
||||||
int repository_format_precious_objects;
|
int repository_format_precious_objects;
|
||||||
char *repository_format_partial_clone;
|
|
||||||
const char *core_partial_clone_filter_default;
|
|
||||||
int repository_format_worktree_config;
|
int repository_format_worktree_config;
|
||||||
const char *git_commit_encoding;
|
const char *git_commit_encoding;
|
||||||
const char *git_log_output_encoding;
|
const char *git_log_output_encoding;
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
#include "cache.h"
|
|
||||||
#include "packfile.h"
|
|
||||||
#include "pkt-line.h"
|
|
||||||
#include "strbuf.h"
|
|
||||||
#include "transport.h"
|
|
||||||
#include "fetch-object.h"
|
|
||||||
|
|
||||||
static void fetch_refs(const char *remote_name, struct ref *ref)
|
|
||||||
{
|
|
||||||
struct remote *remote;
|
|
||||||
struct transport *transport;
|
|
||||||
int original_fetch_if_missing = fetch_if_missing;
|
|
||||||
|
|
||||||
fetch_if_missing = 0;
|
|
||||||
remote = remote_get(remote_name);
|
|
||||||
if (!remote->url[0])
|
|
||||||
die(_("Remote with no URL"));
|
|
||||||
transport = transport_get(remote, remote->url[0]);
|
|
||||||
|
|
||||||
transport_set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
|
|
||||||
transport_set_option(transport, TRANS_OPT_NO_DEPENDENTS, "1");
|
|
||||||
transport_fetch_refs(transport, ref);
|
|
||||||
fetch_if_missing = original_fetch_if_missing;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fetch_objects(const char *remote_name, const struct object_id *oids,
|
|
||||||
int oid_nr)
|
|
||||||
{
|
|
||||||
struct ref *ref = NULL;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < oid_nr; i++) {
|
|
||||||
struct ref *new_ref = alloc_ref(oid_to_hex(&oids[i]));
|
|
||||||
oidcpy(&new_ref->old_oid, &oids[i]);
|
|
||||||
new_ref->exact_oid = 1;
|
|
||||||
new_ref->next = ref;
|
|
||||||
ref = new_ref;
|
|
||||||
}
|
|
||||||
fetch_refs(remote_name, ref);
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
#ifndef FETCH_OBJECT_H
|
|
||||||
#define FETCH_OBJECT_H
|
|
||||||
|
|
||||||
struct object_id;
|
|
||||||
|
|
||||||
void fetch_objects(const char *remote_name, const struct object_id *oids,
|
|
||||||
int oid_nr);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "list-objects.h"
|
#include "list-objects.h"
|
||||||
#include "list-objects-filter.h"
|
#include "list-objects-filter.h"
|
||||||
#include "list-objects-filter-options.h"
|
#include "list-objects-filter-options.h"
|
||||||
|
#include "promisor-remote.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse value of the argument to the "filter" keyword.
|
* Parse value of the argument to the "filter" keyword.
|
||||||
|
@ -29,6 +30,9 @@ static int gently_parse_list_objects_filter(
|
||||||
{
|
{
|
||||||
const char *v0;
|
const char *v0;
|
||||||
|
|
||||||
|
if (!arg)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (filter_options->choice) {
|
if (filter_options->choice) {
|
||||||
if (errbuf) {
|
if (errbuf) {
|
||||||
strbuf_addstr(
|
strbuf_addstr(
|
||||||
|
@ -146,41 +150,42 @@ void partial_clone_register(
|
||||||
const char *remote,
|
const char *remote,
|
||||||
const struct list_objects_filter_options *filter_options)
|
const struct list_objects_filter_options *filter_options)
|
||||||
{
|
{
|
||||||
/*
|
char *cfg_name;
|
||||||
* Record the name of the partial clone remote in the
|
char *filter_name;
|
||||||
* config and in the global variable -- the latter is
|
|
||||||
* used throughout to indicate that partial clone is
|
|
||||||
* enabled and to expect missing objects.
|
|
||||||
*/
|
|
||||||
if (repository_format_partial_clone &&
|
|
||||||
*repository_format_partial_clone &&
|
|
||||||
strcmp(remote, repository_format_partial_clone))
|
|
||||||
die(_("cannot change partial clone promisor remote"));
|
|
||||||
|
|
||||||
git_config_set("core.repositoryformatversion", "1");
|
/* Check if it is already registered */
|
||||||
git_config_set("extensions.partialclone", remote);
|
if (!promisor_remote_find(remote)) {
|
||||||
|
git_config_set("core.repositoryformatversion", "1");
|
||||||
|
|
||||||
repository_format_partial_clone = xstrdup(remote);
|
/* Add promisor config for the remote */
|
||||||
|
cfg_name = xstrfmt("remote.%s.promisor", remote);
|
||||||
|
git_config_set(cfg_name, "true");
|
||||||
|
free(cfg_name);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Record the initial filter-spec in the config as
|
* Record the initial filter-spec in the config as
|
||||||
* the default for subsequent fetches from this remote.
|
* the default for subsequent fetches from this remote.
|
||||||
*/
|
*/
|
||||||
core_partial_clone_filter_default =
|
filter_name = xstrfmt("remote.%s.partialclonefilter", remote);
|
||||||
xstrdup(filter_options->filter_spec);
|
git_config_set(filter_name, filter_options->filter_spec);
|
||||||
git_config_set("core.partialclonefilter",
|
free(filter_name);
|
||||||
core_partial_clone_filter_default);
|
|
||||||
|
/* Make sure the config info are reset */
|
||||||
|
promisor_remote_reinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void partial_clone_get_default_filter_spec(
|
void partial_clone_get_default_filter_spec(
|
||||||
struct list_objects_filter_options *filter_options)
|
struct list_objects_filter_options *filter_options,
|
||||||
|
const char *remote)
|
||||||
{
|
{
|
||||||
|
struct promisor_remote *promisor = promisor_remote_find(remote);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse default value, but silently ignore it if it is invalid.
|
* Parse default value, but silently ignore it if it is invalid.
|
||||||
*/
|
*/
|
||||||
if (!core_partial_clone_filter_default)
|
if (promisor)
|
||||||
return;
|
gently_parse_list_objects_filter(filter_options,
|
||||||
gently_parse_list_objects_filter(filter_options,
|
promisor->partial_clone_filter,
|
||||||
core_partial_clone_filter_default,
|
NULL);
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,6 +87,7 @@ void partial_clone_register(
|
||||||
const char *remote,
|
const char *remote,
|
||||||
const struct list_objects_filter_options *filter_options);
|
const struct list_objects_filter_options *filter_options);
|
||||||
void partial_clone_get_default_filter_spec(
|
void partial_clone_get_default_filter_spec(
|
||||||
struct list_objects_filter_options *filter_options);
|
struct list_objects_filter_options *filter_options,
|
||||||
|
const char *remote);
|
||||||
|
|
||||||
#endif /* LIST_OBJECTS_FILTER_OPTIONS_H */
|
#endif /* LIST_OBJECTS_FILTER_OPTIONS_H */
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "object-store.h"
|
#include "object-store.h"
|
||||||
#include "midx.h"
|
#include "midx.h"
|
||||||
#include "commit-graph.h"
|
#include "commit-graph.h"
|
||||||
|
#include "promisor-remote.h"
|
||||||
|
|
||||||
char *odb_pack_name(struct strbuf *buf,
|
char *odb_pack_name(struct strbuf *buf,
|
||||||
const unsigned char *sha1,
|
const unsigned char *sha1,
|
||||||
|
@ -2132,7 +2133,7 @@ int is_promisor_object(const struct object_id *oid)
|
||||||
static int promisor_objects_prepared;
|
static int promisor_objects_prepared;
|
||||||
|
|
||||||
if (!promisor_objects_prepared) {
|
if (!promisor_objects_prepared) {
|
||||||
if (repository_format_partial_clone) {
|
if (has_promisor_remote()) {
|
||||||
for_each_packed_object(add_promisor_object,
|
for_each_packed_object(add_promisor_object,
|
||||||
&promisor_objects,
|
&promisor_objects,
|
||||||
FOR_EACH_OBJECT_PROMISOR_ONLY);
|
FOR_EACH_OBJECT_PROMISOR_ONLY);
|
||||||
|
|
|
@ -0,0 +1,265 @@
|
||||||
|
#include "cache.h"
|
||||||
|
#include "object-store.h"
|
||||||
|
#include "promisor-remote.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "transport.h"
|
||||||
|
|
||||||
|
static char *repository_format_partial_clone;
|
||||||
|
static const char *core_partial_clone_filter_default;
|
||||||
|
|
||||||
|
void set_repository_format_partial_clone(char *partial_clone)
|
||||||
|
{
|
||||||
|
repository_format_partial_clone = xstrdup_or_null(partial_clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fetch_refs(const char *remote_name, struct ref *ref)
|
||||||
|
{
|
||||||
|
struct remote *remote;
|
||||||
|
struct transport *transport;
|
||||||
|
int original_fetch_if_missing = fetch_if_missing;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
fetch_if_missing = 0;
|
||||||
|
remote = remote_get(remote_name);
|
||||||
|
if (!remote->url[0])
|
||||||
|
die(_("Remote with no URL"));
|
||||||
|
transport = transport_get(remote, remote->url[0]);
|
||||||
|
|
||||||
|
transport_set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
|
||||||
|
transport_set_option(transport, TRANS_OPT_NO_DEPENDENTS, "1");
|
||||||
|
res = transport_fetch_refs(transport, ref);
|
||||||
|
fetch_if_missing = original_fetch_if_missing;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fetch_objects(const char *remote_name,
|
||||||
|
const struct object_id *oids,
|
||||||
|
int oid_nr)
|
||||||
|
{
|
||||||
|
struct ref *ref = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < oid_nr; i++) {
|
||||||
|
struct ref *new_ref = alloc_ref(oid_to_hex(&oids[i]));
|
||||||
|
oidcpy(&new_ref->old_oid, &oids[i]);
|
||||||
|
new_ref->exact_oid = 1;
|
||||||
|
new_ref->next = ref;
|
||||||
|
ref = new_ref;
|
||||||
|
}
|
||||||
|
return fetch_refs(remote_name, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct promisor_remote *promisors;
|
||||||
|
static struct promisor_remote **promisors_tail = &promisors;
|
||||||
|
|
||||||
|
static struct promisor_remote *promisor_remote_new(const char *remote_name)
|
||||||
|
{
|
||||||
|
struct promisor_remote *r;
|
||||||
|
|
||||||
|
if (*remote_name == '/') {
|
||||||
|
warning(_("promisor remote name cannot begin with '/': %s"),
|
||||||
|
remote_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLEX_ALLOC_STR(r, name, remote_name);
|
||||||
|
|
||||||
|
*promisors_tail = r;
|
||||||
|
promisors_tail = &r->next;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct promisor_remote *promisor_remote_lookup(const char *remote_name,
|
||||||
|
struct promisor_remote **previous)
|
||||||
|
{
|
||||||
|
struct promisor_remote *r, *p;
|
||||||
|
|
||||||
|
for (p = NULL, r = promisors; r; p = r, r = r->next)
|
||||||
|
if (!strcmp(r->name, remote_name)) {
|
||||||
|
if (previous)
|
||||||
|
*previous = p;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void promisor_remote_move_to_tail(struct promisor_remote *r,
|
||||||
|
struct promisor_remote *previous)
|
||||||
|
{
|
||||||
|
if (previous)
|
||||||
|
previous->next = r->next;
|
||||||
|
else
|
||||||
|
promisors = r->next ? r->next : r;
|
||||||
|
r->next = NULL;
|
||||||
|
*promisors_tail = r;
|
||||||
|
promisors_tail = &r->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int promisor_remote_config(const char *var, const char *value, void *data)
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
int namelen;
|
||||||
|
const char *subkey;
|
||||||
|
|
||||||
|
if (!strcmp(var, "core.partialclonefilter"))
|
||||||
|
return git_config_string(&core_partial_clone_filter_default,
|
||||||
|
var, value);
|
||||||
|
|
||||||
|
if (parse_config_key(var, "remote", &name, &namelen, &subkey) < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!strcmp(subkey, "promisor")) {
|
||||||
|
char *remote_name;
|
||||||
|
|
||||||
|
if (!git_config_bool(var, value))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
remote_name = xmemdupz(name, namelen);
|
||||||
|
|
||||||
|
if (!promisor_remote_lookup(remote_name, NULL))
|
||||||
|
promisor_remote_new(remote_name);
|
||||||
|
|
||||||
|
free(remote_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!strcmp(subkey, "partialclonefilter")) {
|
||||||
|
struct promisor_remote *r;
|
||||||
|
char *remote_name = xmemdupz(name, namelen);
|
||||||
|
|
||||||
|
r = promisor_remote_lookup(remote_name, NULL);
|
||||||
|
if (!r)
|
||||||
|
r = promisor_remote_new(remote_name);
|
||||||
|
|
||||||
|
free(remote_name);
|
||||||
|
|
||||||
|
if (!r)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return git_config_string(&r->partial_clone_filter, var, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int initialized;
|
||||||
|
|
||||||
|
static void promisor_remote_init(void)
|
||||||
|
{
|
||||||
|
if (initialized)
|
||||||
|
return;
|
||||||
|
initialized = 1;
|
||||||
|
|
||||||
|
git_config(promisor_remote_config, NULL);
|
||||||
|
|
||||||
|
if (repository_format_partial_clone) {
|
||||||
|
struct promisor_remote *o, *previous;
|
||||||
|
|
||||||
|
o = promisor_remote_lookup(repository_format_partial_clone,
|
||||||
|
&previous);
|
||||||
|
if (o)
|
||||||
|
promisor_remote_move_to_tail(o, previous);
|
||||||
|
else
|
||||||
|
promisor_remote_new(repository_format_partial_clone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void promisor_remote_clear(void)
|
||||||
|
{
|
||||||
|
while (promisors) {
|
||||||
|
struct promisor_remote *r = promisors;
|
||||||
|
promisors = promisors->next;
|
||||||
|
free(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
promisors_tail = &promisors;
|
||||||
|
}
|
||||||
|
|
||||||
|
void promisor_remote_reinit(void)
|
||||||
|
{
|
||||||
|
initialized = 0;
|
||||||
|
promisor_remote_clear();
|
||||||
|
promisor_remote_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct promisor_remote *promisor_remote_find(const char *remote_name)
|
||||||
|
{
|
||||||
|
promisor_remote_init();
|
||||||
|
|
||||||
|
if (!remote_name)
|
||||||
|
return promisors;
|
||||||
|
|
||||||
|
return promisor_remote_lookup(remote_name, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int has_promisor_remote(void)
|
||||||
|
{
|
||||||
|
return !!promisor_remote_find(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remove_fetched_oids(struct repository *repo,
|
||||||
|
struct object_id **oids,
|
||||||
|
int oid_nr, int to_free)
|
||||||
|
{
|
||||||
|
int i, remaining_nr = 0;
|
||||||
|
int *remaining = xcalloc(oid_nr, sizeof(*remaining));
|
||||||
|
struct object_id *old_oids = *oids;
|
||||||
|
struct object_id *new_oids;
|
||||||
|
|
||||||
|
for (i = 0; i < oid_nr; i++)
|
||||||
|
if (oid_object_info_extended(repo, &old_oids[i], NULL,
|
||||||
|
OBJECT_INFO_SKIP_FETCH_OBJECT)) {
|
||||||
|
remaining[i] = 1;
|
||||||
|
remaining_nr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remaining_nr) {
|
||||||
|
int j = 0;
|
||||||
|
new_oids = xcalloc(remaining_nr, sizeof(*new_oids));
|
||||||
|
for (i = 0; i < oid_nr; i++)
|
||||||
|
if (remaining[i])
|
||||||
|
oidcpy(&new_oids[j++], &old_oids[i]);
|
||||||
|
*oids = new_oids;
|
||||||
|
if (to_free)
|
||||||
|
free(old_oids);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(remaining);
|
||||||
|
|
||||||
|
return remaining_nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int promisor_remote_get_direct(struct repository *repo,
|
||||||
|
const struct object_id *oids,
|
||||||
|
int oid_nr)
|
||||||
|
{
|
||||||
|
struct promisor_remote *r;
|
||||||
|
struct object_id *remaining_oids = (struct object_id *)oids;
|
||||||
|
int remaining_nr = oid_nr;
|
||||||
|
int to_free = 0;
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
|
promisor_remote_init();
|
||||||
|
|
||||||
|
for (r = promisors; r; r = r->next) {
|
||||||
|
if (fetch_objects(r->name, remaining_oids, remaining_nr) < 0) {
|
||||||
|
if (remaining_nr == 1)
|
||||||
|
continue;
|
||||||
|
remaining_nr = remove_fetched_oids(repo, &remaining_oids,
|
||||||
|
remaining_nr, to_free);
|
||||||
|
if (remaining_nr) {
|
||||||
|
to_free = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to_free)
|
||||||
|
free(remaining_oids);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef PROMISOR_REMOTE_H
|
||||||
|
#define PROMISOR_REMOTE_H
|
||||||
|
|
||||||
|
struct object_id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Promisor remote linked list
|
||||||
|
*
|
||||||
|
* Information in its fields come from remote.XXX config entries or
|
||||||
|
* from extensions.partialclone or core.partialclonefilter.
|
||||||
|
*/
|
||||||
|
struct promisor_remote {
|
||||||
|
struct promisor_remote *next;
|
||||||
|
const char *partial_clone_filter;
|
||||||
|
const char name[FLEX_ARRAY];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void promisor_remote_reinit(void);
|
||||||
|
extern struct promisor_remote *promisor_remote_find(const char *remote_name);
|
||||||
|
extern int has_promisor_remote(void);
|
||||||
|
extern int promisor_remote_get_direct(struct repository *repo,
|
||||||
|
const struct object_id *oids,
|
||||||
|
int oid_nr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This should be used only once from setup.c to set the value we got
|
||||||
|
* from the extensions.partialclone config option.
|
||||||
|
*/
|
||||||
|
extern void set_repository_format_partial_clone(char *partial_clone);
|
||||||
|
|
||||||
|
#endif /* PROMISOR_REMOTE_H */
|
3
setup.c
3
setup.c
|
@ -4,6 +4,7 @@
|
||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
#include "string-list.h"
|
#include "string-list.h"
|
||||||
#include "chdir-notify.h"
|
#include "chdir-notify.h"
|
||||||
|
#include "promisor-remote.h"
|
||||||
|
|
||||||
static int inside_git_dir = -1;
|
static int inside_git_dir = -1;
|
||||||
static int inside_work_tree = -1;
|
static int inside_work_tree = -1;
|
||||||
|
@ -478,7 +479,7 @@ static int check_repository_format_gently(const char *gitdir, struct repository_
|
||||||
}
|
}
|
||||||
|
|
||||||
repository_format_precious_objects = candidate->precious_objects;
|
repository_format_precious_objects = candidate->precious_objects;
|
||||||
repository_format_partial_clone = xstrdup_or_null(candidate->partial_clone);
|
set_repository_format_partial_clone(candidate->partial_clone);
|
||||||
repository_format_worktree_config = candidate->worktree_config;
|
repository_format_worktree_config = candidate->worktree_config;
|
||||||
string_list_clear(&candidate->unknown_extensions, 0);
|
string_list_clear(&candidate->unknown_extensions, 0);
|
||||||
|
|
||||||
|
|
15
sha1-file.c
15
sha1-file.c
|
@ -30,8 +30,8 @@
|
||||||
#include "mergesort.h"
|
#include "mergesort.h"
|
||||||
#include "quote.h"
|
#include "quote.h"
|
||||||
#include "packfile.h"
|
#include "packfile.h"
|
||||||
#include "fetch-object.h"
|
|
||||||
#include "object-store.h"
|
#include "object-store.h"
|
||||||
|
#include "promisor-remote.h"
|
||||||
|
|
||||||
/* The maximum size for an object header. */
|
/* The maximum size for an object header. */
|
||||||
#define MAX_HEADER_LEN 32
|
#define MAX_HEADER_LEN 32
|
||||||
|
@ -1471,16 +1471,17 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if it is a missing object */
|
/* Check if it is a missing object */
|
||||||
if (fetch_if_missing && repository_format_partial_clone &&
|
if (fetch_if_missing && has_promisor_remote() &&
|
||||||
!already_retried && r == the_repository &&
|
!already_retried && r == the_repository &&
|
||||||
!(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) {
|
!(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) {
|
||||||
/*
|
/*
|
||||||
* TODO Investigate having fetch_object() return
|
* TODO Investigate checking promisor_remote_get_direct()
|
||||||
* TODO error/success and stopping the music here.
|
* TODO return value and stopping on error here.
|
||||||
* TODO Pass a repository struct through fetch_object,
|
* TODO Pass a repository struct through
|
||||||
* such that arbitrary repositories work.
|
* promisor_remote_get_direct(), such that arbitrary
|
||||||
|
* repositories work.
|
||||||
*/
|
*/
|
||||||
fetch_objects(repository_format_partial_clone, real, 1);
|
promisor_remote_get_direct(r, real, 1);
|
||||||
already_retried = 1;
|
already_retried = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ promise_and_delete () {
|
||||||
test_expect_success 'extensions.partialclone without filter' '
|
test_expect_success 'extensions.partialclone without filter' '
|
||||||
test_create_repo server &&
|
test_create_repo server &&
|
||||||
git clone --filter="blob:none" "file://$(pwd)/server" client &&
|
git clone --filter="blob:none" "file://$(pwd)/server" client &&
|
||||||
git -C client config --unset core.partialclonefilter &&
|
git -C client config --unset remote.origin.partialclonefilter &&
|
||||||
git -C client fetch origin
|
git -C client fetch origin
|
||||||
'
|
'
|
||||||
|
|
||||||
|
@ -166,8 +166,9 @@ test_expect_success 'fetching of missing objects' '
|
||||||
# associated packfile contains the object
|
# associated packfile contains the object
|
||||||
ls repo/.git/objects/pack/pack-*.promisor >promisorlist &&
|
ls repo/.git/objects/pack/pack-*.promisor >promisorlist &&
|
||||||
test_line_count = 1 promisorlist &&
|
test_line_count = 1 promisorlist &&
|
||||||
IDX=$(cat promisorlist | sed "s/promisor$/idx/") &&
|
IDX=$(sed "s/promisor$/idx/" promisorlist) &&
|
||||||
git verify-pack --verbose "$IDX" | grep "$HASH"
|
git verify-pack --verbose "$IDX" >out &&
|
||||||
|
grep "$HASH" out
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'fetching of missing objects works with ref-in-want enabled' '
|
test_expect_success 'fetching of missing objects works with ref-in-want enabled' '
|
||||||
|
@ -182,8 +183,55 @@ test_expect_success 'fetching of missing objects works with ref-in-want enabled'
|
||||||
grep "git< fetch=.*ref-in-want" trace
|
grep "git< fetch=.*ref-in-want" trace
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'fetching of missing objects from another promisor remote' '
|
||||||
|
git clone "file://$(pwd)/server" server2 &&
|
||||||
|
test_commit -C server2 bar &&
|
||||||
|
git -C server2 repack -a -d --write-bitmap-index &&
|
||||||
|
HASH2=$(git -C server2 rev-parse bar) &&
|
||||||
|
|
||||||
|
git -C repo remote add server2 "file://$(pwd)/server2" &&
|
||||||
|
git -C repo config remote.server2.promisor true &&
|
||||||
|
git -C repo cat-file -p "$HASH2" &&
|
||||||
|
|
||||||
|
git -C repo fetch server2 &&
|
||||||
|
rm -rf repo/.git/objects/* &&
|
||||||
|
git -C repo cat-file -p "$HASH2" &&
|
||||||
|
|
||||||
|
# Ensure that the .promisor file is written, and check that its
|
||||||
|
# associated packfile contains the object
|
||||||
|
ls repo/.git/objects/pack/pack-*.promisor >promisorlist &&
|
||||||
|
test_line_count = 1 promisorlist &&
|
||||||
|
IDX=$(sed "s/promisor$/idx/" promisorlist) &&
|
||||||
|
git verify-pack --verbose "$IDX" >out &&
|
||||||
|
grep "$HASH2" out
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'fetching of missing objects configures a promisor remote' '
|
||||||
|
git clone "file://$(pwd)/server" server3 &&
|
||||||
|
test_commit -C server3 baz &&
|
||||||
|
git -C server3 repack -a -d --write-bitmap-index &&
|
||||||
|
HASH3=$(git -C server3 rev-parse baz) &&
|
||||||
|
git -C server3 config uploadpack.allowfilter 1 &&
|
||||||
|
|
||||||
|
rm repo/.git/objects/pack/pack-*.promisor &&
|
||||||
|
|
||||||
|
git -C repo remote add server3 "file://$(pwd)/server3" &&
|
||||||
|
git -C repo fetch --filter="blob:none" server3 $HASH3 &&
|
||||||
|
|
||||||
|
test_cmp_config -C repo true remote.server3.promisor &&
|
||||||
|
|
||||||
|
# Ensure that the .promisor file is written, and check that its
|
||||||
|
# associated packfile contains the object
|
||||||
|
ls repo/.git/objects/pack/pack-*.promisor >promisorlist &&
|
||||||
|
test_line_count = 1 promisorlist &&
|
||||||
|
IDX=$(sed "s/promisor$/idx/" promisorlist) &&
|
||||||
|
git verify-pack --verbose "$IDX" >out &&
|
||||||
|
grep "$HASH3" out
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'fetching of missing blobs works' '
|
test_expect_success 'fetching of missing blobs works' '
|
||||||
rm -rf server repo &&
|
rm -rf server server2 repo &&
|
||||||
|
rm -rf server server3 repo &&
|
||||||
test_create_repo server &&
|
test_create_repo server &&
|
||||||
test_commit -C server foo &&
|
test_commit -C server foo &&
|
||||||
git -C server repack -a -d --write-bitmap-index &&
|
git -C server repack -a -d --write-bitmap-index &&
|
||||||
|
@ -514,8 +562,9 @@ test_expect_success 'fetching of missing objects from an HTTP server' '
|
||||||
# associated packfile contains the object
|
# associated packfile contains the object
|
||||||
ls repo/.git/objects/pack/pack-*.promisor >promisorlist &&
|
ls repo/.git/objects/pack/pack-*.promisor >promisorlist &&
|
||||||
test_line_count = 1 promisorlist &&
|
test_line_count = 1 promisorlist &&
|
||||||
IDX=$(cat promisorlist | sed "s/promisor$/idx/") &&
|
IDX=$(sed "s/promisor$/idx/" promisorlist) &&
|
||||||
git verify-pack --verbose "$IDX" | grep "$HASH"
|
git verify-pack --verbose "$IDX" >out &&
|
||||||
|
grep "$HASH" out
|
||||||
'
|
'
|
||||||
|
|
||||||
# DO NOT add non-httpd-specific tests here, because the last part of this
|
# DO NOT add non-httpd-specific tests here, because the last part of this
|
||||||
|
|
|
@ -654,7 +654,8 @@ partial_clone () {
|
||||||
git -C client fsck &&
|
git -C client fsck &&
|
||||||
|
|
||||||
# Ensure that unneeded blobs are not inadvertently fetched.
|
# Ensure that unneeded blobs are not inadvertently fetched.
|
||||||
test_config -C client extensions.partialclone "not a remote" &&
|
test_config -C client remote.origin.promisor "false" &&
|
||||||
|
git -C client config --unset remote.origin.partialclonefilter &&
|
||||||
test_must_fail git -C client cat-file -e "$HASH1" &&
|
test_must_fail git -C client cat-file -e "$HASH1" &&
|
||||||
|
|
||||||
# But this blob was fetched, because clone performs an initial checkout
|
# But this blob was fetched, because clone performs an initial checkout
|
||||||
|
|
|
@ -42,8 +42,8 @@ test_expect_success 'do partial clone 1' '
|
||||||
|
|
||||||
test_cmp expect_1.oids observed.oids &&
|
test_cmp expect_1.oids observed.oids &&
|
||||||
test "$(git -C pc1 config --local core.repositoryformatversion)" = "1" &&
|
test "$(git -C pc1 config --local core.repositoryformatversion)" = "1" &&
|
||||||
test "$(git -C pc1 config --local extensions.partialclone)" = "origin" &&
|
test "$(git -C pc1 config --local remote.origin.promisor)" = "true" &&
|
||||||
test "$(git -C pc1 config --local core.partialclonefilter)" = "blob:none"
|
test "$(git -C pc1 config --local remote.origin.partialclonefilter)" = "blob:none"
|
||||||
'
|
'
|
||||||
|
|
||||||
# checkout master to force dynamic object fetch of blobs at HEAD.
|
# checkout master to force dynamic object fetch of blobs at HEAD.
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include "submodule-config.h"
|
#include "submodule-config.h"
|
||||||
#include "fsmonitor.h"
|
#include "fsmonitor.h"
|
||||||
#include "object-store.h"
|
#include "object-store.h"
|
||||||
#include "fetch-object.h"
|
#include "promisor-remote.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Error messages expected by scripts out of plumbing commands such as
|
* Error messages expected by scripts out of plumbing commands such as
|
||||||
|
@ -400,7 +400,7 @@ static int check_updates(struct unpack_trees_options *o)
|
||||||
load_gitmodules_file(index, &state);
|
load_gitmodules_file(index, &state);
|
||||||
|
|
||||||
enable_delayed_checkout(&state);
|
enable_delayed_checkout(&state);
|
||||||
if (repository_format_partial_clone && o->update && !o->dry_run) {
|
if (has_promisor_remote() && o->update && !o->dry_run) {
|
||||||
/*
|
/*
|
||||||
* Prefetch the objects that are to be checked out in the loop
|
* Prefetch the objects that are to be checked out in the loop
|
||||||
* below.
|
* below.
|
||||||
|
@ -419,8 +419,8 @@ static int check_updates(struct unpack_trees_options *o)
|
||||||
oid_array_append(&to_fetch, &ce->oid);
|
oid_array_append(&to_fetch, &ce->oid);
|
||||||
}
|
}
|
||||||
if (to_fetch.nr)
|
if (to_fetch.nr)
|
||||||
fetch_objects(repository_format_partial_clone,
|
promisor_remote_get_direct(the_repository,
|
||||||
to_fetch.oid, to_fetch.nr);
|
to_fetch.oid, to_fetch.nr);
|
||||||
oid_array_clear(&to_fetch);
|
oid_array_clear(&to_fetch);
|
||||||
}
|
}
|
||||||
for (i = 0; i < index->cache_nr; i++) {
|
for (i = 0; i < index->cache_nr; i++) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче