From ffaac5c14115d0156de5f99f4460cd3eaede674e Mon Sep 17 00:00:00 2001 From: "Faisal M. AlOtaibi" <205647957+hub966@users.noreply.github.com> Date: Thu, 21 May 2026 08:39:19 +0300 Subject: [PATCH] Revert "Jch" --- Documentation/config.adoc | 50 --------- Documentation/config/remote.adoc | 40 -------- Documentation/fetch-options.adoc | 27 ----- Documentation/git-cat-file.adoc | 5 - Documentation/git-push.adoc | 73 ++------------ Documentation/git-repack.adoc | 4 +- Makefile | 1 - autocorrect.c | 89 ---------------- autocorrect.h | 32 ------ builtin/cat-file.c | 37 +------ builtin/fetch.c | 101 +++++++++---------- builtin/notes.c | 10 +- builtin/pull.c | 6 -- builtin/push.c | 123 ++++++----------------- builtin/remote.c | 12 ++- config.c | 39 +++---- fetch-pack.c | 114 +++------------------ fetch-pack.h | 14 +-- help.c | 107 ++++++++++++++++---- meson.build | 1 - pack-write.c | 9 -- parse-options.c | 162 ++++++++---------------------- parse-options.h | 1 - promisor-remote.c | 9 +- remote.c | 49 --------- remote.h | 14 --- repack-promisor.c | 156 +++------------------------- send-pack.c | 34 ++----- send-pack.h | 2 - t/meson.build | 2 - t/t0410-partial-clone.sh | 45 +-------- t/t1305-config-include.sh | 66 ------------ t/t4203-mailmap.sh | 105 ------------------- t/t5510-fetch.sh | 159 ----------------------------- t/t5516-fetch-push.sh | 32 +----- t/t5566-push-group.sh | 153 ---------------------------- t/t5616-partial-clone.sh | 60 ----------- t/t5702-protocol-v2.sh | 4 +- t/t7700-repack.sh | 60 ----------- t/t7703-repack-geometric.sh | 33 ------ t/t9004-autocorrect-subcommand.sh | 51 ---------- transport-helper.c | 2 +- transport.c | 16 ++- transport.h | 10 +- unpack-trees.c | 14 +-- xdiff/xdiffi.c | 2 +- xdiff/xprepare.c | 86 +++++++--------- xdiff/xutils.c | 4 +- xdiff/xutils.h | 2 +- 49 files changed, 350 insertions(+), 1877 deletions(-) delete mode 100644 autocorrect.c delete mode 100644 autocorrect.h delete mode 100755 t/t5566-push-group.sh delete mode 100755 t/t9004-autocorrect-subcommand.sh diff --git a/Documentation/config.adoc b/Documentation/config.adoc index 92edf1a775145e..dcea3c0c15e2a9 100644 --- a/Documentation/config.adoc +++ b/Documentation/config.adoc @@ -146,48 +146,6 @@ refer to linkgit:gitignore[5] for details. For convenience: This is the same as `gitdir` except that matching is done case-insensitively (e.g. on case-insensitive file systems) -`worktree`:: - The data that follows the keyword `worktree` and a colon is used as a - glob pattern. If the working directory of the current worktree matches - the pattern, the include condition is met. -+ -The worktree location is the path where files are checked out (as returned -by `git rev-parse --show-toplevel`). This is different from `gitdir`, which -matches the `.git` directory path. In a linked worktree, the worktree path -is the directory where that worktree's files are located, not the main -repository's `.git` directory. -+ -The pattern can contain standard globbing wildcards and two additional -ones, `**/` and `/**`, that can match multiple path components. Please -refer to linkgit:gitignore[5] for details. For convenience: - - * If the pattern starts with `~/`, `~` will be substituted with the - content of the environment variable `HOME`. - - * If the pattern starts with `./`, it is replaced with the directory - containing the current config file. - - * If the pattern does not start with either `~/`, `./` or `/`, `**/` - will be automatically prepended. For example, the pattern `foo/bar` - becomes `**/foo/bar` and would match `/any/path/to/foo/bar`. - - * If the pattern ends with `/`, `**` will be automatically added. For - example, the pattern `foo/` becomes `foo/**`. In other words, it - matches "foo" and everything inside, recursively. -+ -This condition will never match in a bare repository (which has no worktree). -+ -This is useful when you need to use different `user.name`, `user.email`, or -GPG keys in different worktrees of the same repository. While -`extensions.worktreeConfig` also allows per-worktree configuration, it -requires changes inside each repository. This condition can be set in the -user's global configuration file (e.g. `~/.config/git/config`) and applies -to multiple repositories at once. - -`worktree/i`:: - This is the same as `worktree` except that matching is done - case-insensitively (e.g. on case-insensitive file systems) - `onbranch`:: The data that follows the keyword `onbranch` and a colon is taken to be a pattern with standard globbing wildcards and two additional @@ -286,14 +244,6 @@ Example [includeIf "gitdir:~/to/group/"] path = /path/to/foo.inc -; include if the worktree is at /path/to/project-build -[includeIf "worktree:/path/to/project-build"] - path = build-config.inc - -; include for all worktrees inside /path/to/group -[includeIf "worktree:/path/to/group/"] - path = group-config.inc - ; relative paths are always relative to the including ; file (if the condition is true); their location is not ; affected by the condition diff --git a/Documentation/config/remote.adoc b/Documentation/config/remote.adoc index 9dbe820275dd19..91e46f66f5dd1c 100644 --- a/Documentation/config/remote.adoc +++ b/Documentation/config/remote.adoc @@ -107,46 +107,6 @@ priority configuration file (e.g. `.git/config` in a repository) to clear the values inherited from a lower priority configuration files (e.g. `$HOME/.gitconfig`). -remote..negotiationRestrict:: - When negotiating with this remote during `git fetch` and `git push`, - restrict the commits advertised as "have" lines to only those - reachable from refs matching the given patterns. This multi-valued - config option behaves like `--negotiation-restrict` on the command - line. -+ -Each value is either an exact ref name (e.g. `refs/heads/release`) or a -glob pattern (e.g. `refs/heads/release/*`). The pattern syntax is the -same as for `--negotiation-restrict`. -+ -These config values are used as defaults for the `--negotiation-restrict` -command-line option. If `--negotiation-restrict` (or its synonym -`--negotiation-tip`) is specified on the command line, then the config -values are not used. - -remote..negotiationRequire:: - When negotiating with this remote during `git fetch` and `git push`, - the client advertises a list of commits that exist locally. In - repos with many references, this list of "haves" can be truncated. - Depending on data shape, dropping certain references may be - expensive. This multi-valued config option specifies ref patterns - whose tips should always be sent as "have" commits during fetch - negotiation with this remote. -+ -Each value is either an exact ref name (e.g. `refs/heads/release`) or a -glob pattern (e.g. `refs/heads/release/*`). The pattern syntax is the same -as for `--negotiation-restrict`. -+ -These config values are used as defaults for the `--negotiation-require` -command-line option. If `--negotiation-require` is specified on the -command line, then the config values are not used. -+ -This option is additive with the normal negotiation process: the -negotiation algorithm still runs and advertises its own selected commits, -but the refs matching `remote..negotiationRequire` are sent -unconditionally on top of those heuristically selected commits. This -option is also used during push negotiation when `push.negotiate` is -enabled. - remote..followRemoteHEAD:: How linkgit:git-fetch[1] should handle updates to `remotes//HEAD` when fetching using the configured refspecs of a remote. diff --git a/Documentation/fetch-options.adoc b/Documentation/fetch-options.adoc index 16c6e8cee91531..81a9d7f9bbc11d 100644 --- a/Documentation/fetch-options.adoc +++ b/Documentation/fetch-options.adoc @@ -49,7 +49,6 @@ the current repository has the same history as the source repository. `.git/shallow`. This option updates `.git/shallow` and accepts such refs. -`--negotiation-restrict=(|)`:: `--negotiation-tip=(|)`:: By default, Git will report, to the server, commits reachable from all local refs to find common commits in an attempt to @@ -59,9 +58,6 @@ the current repository has the same history as the source repository. local ref is likely to have commits in common with the upstream ref being fetched. + -`--negotiation-restrict` is the preferred name for this option; -`--negotiation-tip` is accepted as a synonym. -+ This option may be specified more than once; if so, Git will report commits reachable from any of the given commits. + @@ -73,29 +69,6 @@ See also the `fetch.negotiationAlgorithm` and `push.negotiate` configuration variables documented in linkgit:git-config[1], and the `--negotiate-only` option below. -`--negotiation-require=`:: - Ensure that the given ref tip is always sent as a "have" line - during fetch negotiation, regardless of what the negotiation - algorithm selects. This is useful to guarantee that common - history reachable from specific refs is always considered, even - when `--negotiation-restrict` restricts the set of tips or when - the negotiation algorithm would otherwise skip them. -+ -This option may be specified more than once; if so, each ref is sent -unconditionally. -+ -The argument may be an exact ref name (e.g. `refs/heads/release`) or a -glob pattern (e.g. `refs/heads/release/{asterisk}`). The pattern syntax -is the same as for `--negotiation-restrict`. -+ -If `--negotiation-restrict` is used, the have set is first restricted by -that option and then increased to include the tips specified by -`--negotiation-require`. -+ -If this option is not specified on the command line, then any -`remote..negotiationRequire` config values for the current remote -are used instead. - `--negotiate-only`:: Do not fetch anything from the server, and instead print the ancestors of the provided `--negotiation-tip=` arguments, diff --git a/Documentation/git-cat-file.adoc b/Documentation/git-cat-file.adoc index 86b9181599317e..c139f55a168d61 100644 --- a/Documentation/git-cat-file.adoc +++ b/Documentation/git-cat-file.adoc @@ -174,11 +174,6 @@ flush:: since the beginning or since the last flush was issued. When `--buffer` is used, no output will come until a `flush` is issued. When `--buffer` is not used, commands are flushed each time without issuing `flush`. - -`mailmap ()`:: - Enable or disable mailmap for subsequent commands. The `` - argument accepts the same boolean values as linkgit:git-config[1]. - The mailmap data is read upon the first use and only once. -- + diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc index b7f617a290592b..e5ba3a67421edc 100644 --- a/Documentation/git-push.adoc +++ b/Documentation/git-push.adoc @@ -18,28 +18,17 @@ git push [--all | --branches | --mirror | --tags] [--follow-tags] [--atomic] [-n DESCRIPTION ----------- -Updates one or more branches, tags, or other references in one or more -remote repositories from your local repository, and sends all necessary -data that isn't already on the remote. + +Updates one or more branches, tags, or other references in a remote +repository from your local repository, and sends all necessary data +that isn't already on the remote. The simplest way to push is `git push `. `git push origin main` will push the local `main` branch to the `main` branch on the remote named `origin`. -You can also push to multiple remotes at once by using a remote group. -A remote group is a named list of remotes configured via `remotes.` -in your git config: - - $ git config remotes.all-remotes "origin gitlab backup" - -Then `git push all-remotes` will push to `origin`, `gitlab`, and -`backup` in turn, as if you had run `git push` against each one -individually. Each remote is pushed independently using its own -push mapping configuration. There is a `remotes.` entry in -the configuration file. (See linkgit:git-config[1]). - -The `` argument defaults to the upstream for the current -branch, or `origin` if there's no configured upstream. +The `` argument defaults to the upstream for the current branch, +or `origin` if there's no configured upstream. To decide which branches, tags, or other refs to push, Git uses (in order of precedence): @@ -66,10 +55,8 @@ OPTIONS __:: The "remote" repository that is the destination of a push operation. This parameter can be either a URL - (see the section <> below), the name - of a remote (see the section <> below), - or the name of a remote group - (see the section <> below). + (see the section <> below) or the name + of a remote (see the section <> below). `...`:: Specify what destination ref to update with what source object. @@ -443,50 +430,6 @@ further recursion will occur. In this case, `only` is treated as `on-demand`. include::urls-remotes.adoc[] -[[REMOTE-GROUPS]] -REMOTE GROUPS -------------- - -A remote group is a named list of remotes configured via `remotes.` -in your git config: - - $ git config remotes.all-remotes "r1 r2 r3" - -When a group name is given as the `` argument, the push is -performed to each member remote in turn. The defining principle is: - - git push all-remotes - -is exactly equivalent to: - - git push r1 - git push r2 - ... - git push rN - -where r1, r2, ..., rN are the members of `all-remotes`. No special -behaviour is added or removed — the group is purely a shorthand for -running the same push command against each member remote individually. - -The behaviour upon failure depends on the kind of error encountered: - -If a member remote rejects the push, for example due to a -non-fast-forward update, force needed but not given, an existing tag, -or a server-side hook refusing a ref, Git reports the error and continues -pushing to the remaining remotes in the group. The overall exit code is -non-zero if any member push fails. - -If a member remote cannot be contacted at all, for example because the -repository does not exist, authentication fails, or the network is -unreachable, the push stops at that point and the remaining remotes -are not attempted. - -This means the user is responsible for ensuring that the sequence of -individual pushes makes sense. If `git push r1`` would fail for a given -set of options and arguments, then `git push all-remotes` will fail in -the same way when it reaches r1. The group push does not do anything -special to make a failing individual push succeed. - OUTPUT ------ diff --git a/Documentation/git-repack.adoc b/Documentation/git-repack.adoc index 33d3c8afbd1660..673ce91083720d 100644 --- a/Documentation/git-repack.adoc +++ b/Documentation/git-repack.adoc @@ -45,8 +45,8 @@ other objects in that pack they already have locally. + Promisor packfiles are repacked separately: if there are packfiles that have an associated ".promisor" file, these packfiles will be repacked -into another separate pack, and a ".promisor" file corresponding to the -new separate pack will be written (with arbitrary contents). +into another separate pack, and an empty ".promisor" file corresponding +to the new separate pack will be written. -A:: Same as `-a`, unless `-d` is used. Then any unreachable diff --git a/Makefile b/Makefile index 13c3ee2e8c0cf7..f86173f93a590c 100644 --- a/Makefile +++ b/Makefile @@ -1100,7 +1100,6 @@ LIB_OBJS += archive-tar.o LIB_OBJS += archive-zip.o LIB_OBJS += archive.o LIB_OBJS += attr.o -LIB_OBJS += autocorrect.o LIB_OBJS += base85.o LIB_OBJS += bisect.o LIB_OBJS += blame.o diff --git a/autocorrect.c b/autocorrect.c deleted file mode 100644 index b2ee9f51e8c09a..00000000000000 --- a/autocorrect.c +++ /dev/null @@ -1,89 +0,0 @@ -#define USE_THE_REPOSITORY_VARIABLE - -#include "git-compat-util.h" -#include "autocorrect.h" -#include "config.h" -#include "parse.h" -#include "strbuf.h" -#include "prompt.h" -#include "gettext.h" - -static enum autocorrect_mode parse_autocorrect(const char *value) -{ - switch (git_parse_maybe_bool_text(value)) { - case 1: - return AUTOCORRECT_IMMEDIATELY; - case 0: - return AUTOCORRECT_HINT; - default: /* other random text */ - break; - } - - if (!strcmp(value, "prompt")) - return AUTOCORRECT_PROMPT; - else if (!strcmp(value, "never")) - return AUTOCORRECT_NEVER; - else if (!strcmp(value, "immediate")) - return AUTOCORRECT_IMMEDIATELY; - else if (!strcmp(value, "show")) - return AUTOCORRECT_HINT; - else - return AUTOCORRECT_DELAY; -} - -static int resolve_autocorrect(const char *var, const char *value, - const struct config_context *ctx, void *data) -{ - struct autocorrect *conf = data; - - if (strcmp(var, "help.autocorrect")) - return 0; - - conf->mode = parse_autocorrect(value); - - /* - * Disable autocorrection prompt in a non-interactive session - */ - if (conf->mode == AUTOCORRECT_PROMPT && (!isatty(0) || !isatty(2))) - conf->mode = AUTOCORRECT_NEVER; - - if (conf->mode == AUTOCORRECT_DELAY) { - conf->delay = git_config_int(var, value, ctx->kvi); - - if (!conf->delay) - conf->mode = AUTOCORRECT_HINT; - else if (conf->delay < 0 || conf->delay == 1) - conf->mode = AUTOCORRECT_IMMEDIATELY; - } - - return 0; -} - -void autocorrect_resolve(struct autocorrect *conf) -{ - read_early_config(the_repository, resolve_autocorrect, conf); -} - -void autocorrect_confirm(struct autocorrect *conf, const char *assumed) -{ - if (conf->mode == AUTOCORRECT_IMMEDIATELY) { - fprintf_ln(stderr, - _("Continuing under the assumption that you meant '%s'."), - assumed); - } else if (conf->mode == AUTOCORRECT_PROMPT) { - char *answer; - struct strbuf msg = STRBUF_INIT; - - strbuf_addf(&msg, _("Run '%s' instead [y/N]? "), assumed); - answer = git_prompt(msg.buf, PROMPT_ECHO); - strbuf_release(&msg); - - if (!(starts_with(answer, "y") || starts_with(answer, "Y"))) - exit(1); - } else if (conf->mode == AUTOCORRECT_DELAY) { - fprintf_ln(stderr, - _("Continuing in %0.1f seconds, assuming that you meant '%s'."), - conf->delay / 10.0, assumed); - sleep_millisec(conf->delay * 100); - } -} diff --git a/autocorrect.h b/autocorrect.h deleted file mode 100644 index bfa3ba20a4fb73..00000000000000 --- a/autocorrect.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef AUTOCORRECT_H -#define AUTOCORRECT_H - -enum autocorrect_mode { - AUTOCORRECT_HINT, - AUTOCORRECT_NEVER, - AUTOCORRECT_PROMPT, - AUTOCORRECT_IMMEDIATELY, - AUTOCORRECT_DELAY, -}; - -/** - * `mode` indicates which action will be performed by autocorrect_confirm(). - * `delay` is the timeout before autocorrect_confirm() returns, in tenths of a - * second. Use it only with AUTOCORRECT_DELAY. - */ -struct autocorrect { - enum autocorrect_mode mode; - int delay; -}; - -/** - * Resolve the autocorrect configuration into `conf`. - */ -void autocorrect_resolve(struct autocorrect *conf); - -/** - * Interact with the user in different ways depending on `conf->mode`. - */ -void autocorrect_confirm(struct autocorrect *conf, const char *assumed); - -#endif /* AUTOCORRECT_H */ diff --git a/builtin/cat-file.c b/builtin/cat-file.c index fa45f774d7a8b7..d9fbad535868bb 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -57,20 +57,6 @@ static int use_mailmap; static char *replace_idents_using_mailmap(char *, size_t *); -/* - * The mailmap is initialized with .strdup_strings set to 0, - * but read_mailmap() sets the bit to 1 (this is true even when - * not a single mailmap entry is read), so it can be used for - * lazy loading. - */ -static void load_mailmap(void) -{ - if (mailmap.strdup_strings) - return; - - read_mailmap(the_repository, &mailmap); -} - static char *replace_idents_using_mailmap(char *object_buf, size_t *size) { struct strbuf sb = STRBUF_INIT; @@ -706,20 +692,6 @@ static void parse_cmd_info(struct batch_options *opt, batch_one_object(line, output, opt, data); } -static void parse_cmd_mailmap(struct batch_options *opt UNUSED, - const char *line, - struct strbuf *output UNUSED, - struct expand_data *data UNUSED) -{ - use_mailmap = git_parse_maybe_bool(line); - - if (use_mailmap < 0) - die(_("mailmap: invalid boolean '%s'"), line); - - if (use_mailmap) - load_mailmap(); -} - static void dispatch_calls(struct batch_options *opt, struct strbuf *output, struct expand_data *data, @@ -753,10 +725,9 @@ static const struct parse_cmd { parse_cmd_fn_t fn; unsigned takes_args; } commands[] = { - { "contents", parse_cmd_contents, 1 }, - { "info", parse_cmd_info, 1 }, - { "flush", NULL, 0 }, - { "mailmap", parse_cmd_mailmap, 1 }, + { "contents", parse_cmd_contents, 1}, + { "info", parse_cmd_info, 1}, + { "flush", NULL, 0}, }; static void batch_objects_command(struct batch_options *opt, @@ -1160,7 +1131,7 @@ int cmd_cat_file(int argc, opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's'); if (use_mailmap) - load_mailmap(); + read_mailmap(the_repository, &mailmap); switch (batch.objects_filter.choice) { case LOFC_DISABLED: diff --git a/builtin/fetch.c b/builtin/fetch.c index 01649c64d3e823..a22c3194670e9a 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -99,7 +99,6 @@ static struct transport *gsecondary; static struct refspec refmap = REFSPEC_INIT_FETCH; static struct string_list server_options = STRING_LIST_INIT_DUP; static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP; -static struct string_list negotiation_require = STRING_LIST_INIT_NODUP; struct fetch_config { enum display_format display_format; @@ -1535,7 +1534,7 @@ static int add_oid(const struct reference *ref, void *cb_data) return 0; } -static void add_negotiation_restrict_tips(struct git_transport_options *smart_options) +static void add_negotiation_tips(struct git_transport_options *smart_options) { struct oid_array *oids = xcalloc(1, sizeof(*oids)); int i; @@ -1559,10 +1558,10 @@ static void add_negotiation_restrict_tips(struct git_transport_options *smart_op refs_for_each_ref_ext(get_main_ref_store(the_repository), add_oid, oids, &opts); if (old_nr == oids->nr) - warning(_("ignoring %s=%s because it does not match any refs"), - "--negotiation-restrict", s); + warning("ignoring --negotiation-tip=%s because it does not match any refs", + s); } - smart_options->negotiation_restrict_tips = oids; + smart_options->negotiation_tips = oids; } static struct transport *prepare_transport(struct remote *remote, int deepen, @@ -1598,40 +1597,9 @@ static struct transport *prepare_transport(struct remote *remote, int deepen, } if (negotiation_tip.nr) { if (transport->smart_options) - add_negotiation_restrict_tips(transport->smart_options); + add_negotiation_tips(transport->smart_options); else - warning(_("ignoring %s because the protocol does not support it"), - "--negotiation-restrict"); - } else if (remote->negotiation_restrict.nr) { - struct string_list_item *item; - for_each_string_list_item(item, &remote->negotiation_restrict) - string_list_append(&negotiation_tip, item->string); - if (transport->smart_options) - add_negotiation_restrict_tips(transport->smart_options); - else { - struct strbuf config_name = STRBUF_INIT; - strbuf_addf(&config_name, "remote.%s.negotiationRestrict", remote->name); - warning(_("ignoring %s because the protocol does not support it"), - config_name.buf); - strbuf_release(&config_name); - } - } - if (negotiation_require.nr) { - if (transport->smart_options) - transport->smart_options->negotiation_require = &negotiation_require; - else - warning(_("ignoring %s because the protocol does not support it"), - "--negotiation-require"); - } else if (remote->negotiation_require.nr) { - if (transport->smart_options) { - transport->smart_options->negotiation_require = &remote->negotiation_require; - } else { - struct strbuf config_name = STRBUF_INIT; - strbuf_addf(&config_name, "remote.%s.negotiationRequire", remote->name); - warning(_("ignoring %s because the protocol does not support it"), - config_name.buf); - strbuf_release(&config_name); - } + warning("ignoring --negotiation-tip because the protocol does not support it"); } return transport; } @@ -2170,6 +2138,48 @@ static int get_one_remote_for_fetch(struct remote *remote, void *priv) return 0; } +struct remote_group_data { + const char *name; + struct string_list *list; +}; + +static int get_remote_group(const char *key, const char *value, + const struct config_context *ctx UNUSED, + void *priv) +{ + struct remote_group_data *g = priv; + + if (skip_prefix(key, "remotes.", &key) && !strcmp(key, g->name)) { + /* split list by white space */ + while (*value) { + size_t wordlen = strcspn(value, " \t\n"); + + if (wordlen >= 1) + string_list_append_nodup(g->list, + xstrndup(value, wordlen)); + value += wordlen + (value[wordlen] != '\0'); + } + } + + return 0; +} + +static int add_remote_or_group(const char *name, struct string_list *list) +{ + int prev_nr = list->nr; + struct remote_group_data g; + g.name = name; g.list = list; + + repo_config(the_repository, get_remote_group, &g); + if (list->nr == prev_nr) { + struct remote *remote = remote_get(name); + if (!remote_is_configured(remote, 0)) + return 0; + string_list_append(list, remote->name); + } + return 1; +} + static void add_options_to_argv(struct strvec *argv, const struct fetch_config *config) { @@ -2557,10 +2567,6 @@ int cmd_fetch(int argc, OPT_IPVERSION(&family), OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"), N_("report that we have only objects reachable from this object")), - OPT_STRING_LIST(0, "negotiation-restrict", &negotiation_tip, N_("revision"), - N_("report that we have only objects reachable from this object")), - OPT_STRING_LIST(0, "negotiation-require", &negotiation_require, N_("revision"), - N_("ensure this ref is always sent as a negotiation have")), OPT_BOOL(0, "negotiate-only", &negotiate_only, N_("do not fetch a packfile; instead, print ancestors of negotiation tips")), OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options), @@ -2650,12 +2656,8 @@ int cmd_fetch(int argc, config.display_format = DISPLAY_FORMAT_PORCELAIN; } - if (negotiate_only && !negotiation_tip.nr) { - /* - * Defer this check: remote..negotiationRestrict may - * provide defaults in prepare_transport(). - */ - } + if (negotiate_only && !negotiation_tip.nr) + die(_("--negotiate-only needs one or more --negotiation-tip=*")); if (deepen_relative) { if (deepen_relative < 0) @@ -2744,9 +2746,6 @@ int cmd_fetch(int argc, if (!remote) die(_("must supply remote when using --negotiate-only")); gtransport = prepare_transport(remote, 1, &filter_options); - if (!gtransport->smart_options || - !gtransport->smart_options->negotiation_restrict_tips) - die(_("--negotiate-only needs one or more --negotiation-restrict=*")); if (gtransport->smart_options) { gtransport->smart_options->acked_commits = &acked_commits; } else { diff --git a/builtin/notes.c b/builtin/notes.c index 087eb898a4415f..9af602bdd7b402 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -1149,10 +1149,14 @@ int cmd_notes(int argc, repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, options, git_notes_usage, - PARSE_OPT_SUBCOMMAND_OPTIONAL | - PARSE_OPT_SUBCOMMAND_AUTOCORR); - if (!fn) + PARSE_OPT_SUBCOMMAND_OPTIONAL); + if (!fn) { + if (argc) { + error(_("unknown subcommand: `%s'"), argv[0]); + usage_with_options(git_notes_usage, options); + } fn = list; + } if (override_notes_ref) { struct strbuf sb = STRBUF_INIT; diff --git a/builtin/pull.c b/builtin/pull.c index 973186ecdcb307..7e67fdce97fd1d 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -999,12 +999,6 @@ int cmd_pull(int argc, OPT_PASSTHRU_ARGV(0, "negotiation-tip", &opt_fetch, N_("revision"), N_("report that we have only objects reachable from this object"), 0), - OPT_PASSTHRU_ARGV(0, "negotiation-restrict", &opt_fetch, N_("revision"), - N_("report that we have only objects reachable from this object"), - 0), - OPT_PASSTHRU_ARGV(0, "negotiation-require", &opt_fetch, N_("revision"), - N_("ensure this ref is always sent as a negotiation have"), - 0), OPT_BOOL(0, "show-forced-updates", &opt_show_forced_updates, N_("check for forced-updates on all updated branches")), OPT_PASSTHRU(0, "set-upstream", &set_upstream, NULL, diff --git a/builtin/push.c b/builtin/push.c index ed292c48fc45e6..7100ffba5da17e 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -552,13 +552,12 @@ int cmd_push(int argc, int flags = 0; int tags = 0; int push_cert = -1; - int rc = 0; - int base_flags; + int rc; const char *repo = NULL; /* default repository */ struct string_list push_options_cmdline = STRING_LIST_INIT_DUP; - struct string_list remote_group = STRING_LIST_INIT_DUP; struct string_list *push_options; const struct string_list_item *item; + struct remote *remote; struct option options[] = { OPT__VERBOSITY(&verbosity), @@ -621,45 +620,39 @@ int cmd_push(int argc, else if (recurse_submodules == RECURSE_SUBMODULES_ONLY) flags |= TRANSPORT_RECURSE_SUBMODULES_ONLY; + if (tags) + refspec_append(&rs, "refs/tags/*"); + if (argc > 0) repo = argv[0]; - if (repo) { - if (!add_remote_or_group(repo, &remote_group)) { - /* - * Not a configured remote name or group name. - * Try treating it as a direct URL or path, e.g. - * git push /tmp/foo.git - * git push https://github.com/user/repo.git - * pushremote_get() creates an anonymous remote - * from the URL so the loop below can handle it - * identically to a named remote. - */ - struct remote *r = pushremote_get(repo); - if (!r) - die(_("bad repository '%s'"), repo); - string_list_append(&remote_group, r->name); - } - } else { - struct remote *r = pushremote_get(NULL); - if (!r) - die(_("No configured push destination.\n" - "Either specify the URL from the command-line or configure a remote repository using\n" - "\n" - " git remote add \n" - "\n" - "and then push using the remote name\n" - "\n" - " git push \n" - "\n" - "To push to multiple remotes at once, configure a remote group using\n" - "\n" - " git config remotes. \" \"\n" - "\n" - "and then push using the group name\n" - "\n" - " git push \n")); - string_list_append(&remote_group, r->name); + remote = pushremote_get(repo); + if (!remote) { + if (repo) + die(_("bad repository '%s'"), repo); + die(_("No configured push destination.\n" + "Either specify the URL from the command-line or configure a remote repository using\n" + "\n" + " git remote add \n" + "\n" + "and then push using the remote name\n" + "\n" + " git push \n")); + } + + if (argc > 0) + set_refspecs(argv + 1, argc - 1, remote); + + if (remote->mirror) + flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE); + + if (flags & TRANSPORT_PUSH_ALL) { + if (argc >= 2) + die(_("--all can't be combined with refspecs")); + } + if (flags & TRANSPORT_PUSH_MIRROR) { + if (argc >= 2) + die(_("--mirror can't be combined with refspecs")); } if (!is_empty_cas(&cas) && (flags & TRANSPORT_PUSH_FORCE_IF_INCLUDES)) @@ -669,60 +662,10 @@ int cmd_push(int argc, if (strchr(item->string, '\n')) die(_("push options must not have new line characters")); - /* - * Push to each remote in remote_group. For a plain "git push " - * or a default push, remote_group has exactly one entry and the loop - * runs once — there is nothing structurally special about that case. - * For a group, the loop runs once per member remote. - * - * Mirror detection and the --mirror/--all + refspec conflict checks - * are done per remote inside the loop. A remote configured with - * remote.NAME.mirror=true implies mirror mode for that remote only — - * other non-mirror remotes in the same group are unaffected. - * - * rs is rebuilt from scratch for each remote so that per-remote push - * mappings (remote.NAME.push config) are resolved against the correct - * remote. iter_flags is derived from a clean snapshot of flags taken - * before the loop so that a mirror remote cannot bleed - * TRANSPORT_PUSH_FORCE into subsequent non-mirror remotes in the - * same group. - */ - base_flags = flags; - for (size_t i = 0; i < remote_group.nr; i++) { - int iter_flags = base_flags; - struct remote *r = pushremote_get(remote_group.items[i].string); - if (!r) - die(_("no such remote or remote group: %s"), - remote_group.items[i].string); - - if (r->mirror) - iter_flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE); - - if (iter_flags & TRANSPORT_PUSH_ALL) { - if (argc >= 2) - die(_("--all can't be combined with refspecs")); - } - if (iter_flags & TRANSPORT_PUSH_MIRROR) { - if (argc >= 2) - die(_("--mirror can't be combined with refspecs")); - } - - refspec_clear(&rs); - rs = (struct refspec) REFSPEC_INIT_PUSH; - - if (tags) - refspec_append(&rs, "refs/tags/*"); - if (argc > 0) - set_refspecs(argv + 1, argc - 1, r); - - rc |= do_push(iter_flags, push_options, r); - } - + rc = do_push(flags, push_options, remote); string_list_clear(&push_options_cmdline, 0); string_list_clear(&push_options_config, 0); - string_list_clear(&remote_group, 0); clear_cas_option(&cas); - if (rc == -1) usage_with_options(push_usage, options); else diff --git a/builtin/remote.c b/builtin/remote.c index 3684a091f925f5..de989ea3ba9691 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -1953,11 +1953,15 @@ int cmd_remote(int argc, }; argc = parse_options(argc, argv, prefix, options, builtin_remote_usage, - PARSE_OPT_SUBCOMMAND_OPTIONAL | - PARSE_OPT_SUBCOMMAND_AUTOCORR); + PARSE_OPT_SUBCOMMAND_OPTIONAL); - if (fn) + if (fn) { return !!fn(argc, argv, prefix, repo); - else + } else { + if (argc) { + error(_("unknown subcommand: `%s'"), argv[0]); + usage_with_options(builtin_remote_usage, options); + } return !!show_all(); + } } diff --git a/config.c b/config.c index 709cf7eeaa90cc..a1b92fe083cf43 100644 --- a/config.c +++ b/config.c @@ -235,20 +235,23 @@ static int prepare_include_condition_pattern(const struct key_value_info *kvi, return 0; } -static int include_by_path(const struct key_value_info *kvi, - const char *path, - const char *cond, size_t cond_len, int icase) +static int include_by_gitdir(const struct key_value_info *kvi, + const struct config_options *opts, + const char *cond, size_t cond_len, int icase) { struct strbuf text = STRBUF_INIT; struct strbuf pattern = STRBUF_INIT; size_t prefix; int ret = 0; + const char *git_dir; int already_tried_absolute = 0; - if (!path) + if (opts->git_dir) + git_dir = opts->git_dir; + else goto done; - strbuf_realpath(&text, path, 1); + strbuf_realpath(&text, git_dir, 1); strbuf_add(&pattern, cond, cond_len); ret = prepare_include_condition_pattern(kvi, &pattern, &prefix); if (ret < 0) @@ -281,7 +284,7 @@ static int include_by_path(const struct key_value_info *kvi, * which'll do the right thing */ strbuf_reset(&text); - strbuf_add_absolute_path(&text, path); + strbuf_add_absolute_path(&text, git_dir); already_tried_absolute = 1; goto again; } @@ -397,15 +400,9 @@ static int include_condition_is_true(const struct key_value_info *kvi, const struct config_options *opts = inc->opts; if (skip_prefix_mem(cond, cond_len, "gitdir:", &cond, &cond_len)) - return include_by_path(kvi, opts->git_dir, cond, cond_len, 0); + return include_by_gitdir(kvi, opts, cond, cond_len, 0); else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len)) - return include_by_path(kvi, opts->git_dir, cond, cond_len, 1); - else if (skip_prefix_mem(cond, cond_len, "worktree:", &cond, &cond_len)) - return include_by_path(kvi, inc->repo ? repo_get_work_tree(inc->repo) : NULL, - cond, cond_len, 0); - else if (skip_prefix_mem(cond, cond_len, "worktree/i:", &cond, &cond_len)) - return include_by_path(kvi, inc->repo ? repo_get_work_tree(inc->repo) : NULL, - cond, cond_len, 1); + return include_by_gitdir(kvi, opts, cond, cond_len, 1); else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len)) return include_by_branch(inc, cond, cond_len); else if (skip_prefix_mem(cond, cond_len, "hasconfig:remote.*.url:", &cond, @@ -2934,14 +2931,6 @@ char *git_config_prepare_comment_string(const char *comment) return prepared; } -/* - * How long to retry acquiring config.lock when another process holds it. - * The lock is held only for the duration of rewriting a small file, so - * 100 ms covers any realistic contention while still failing fast if - * a stale lock has been left behind by a crashed process. - */ -#define CONFIG_LOCK_TIMEOUT_MS 100 - static void validate_comment_string(const char *comment) { size_t leading_blanks; @@ -3025,8 +3014,7 @@ int repo_config_set_multivar_in_file_gently(struct repository *r, * The lock serves a purpose in addition to locking: the new * contents of .git/config will be written into it. */ - fd = hold_lock_file_for_update_timeout(&lock, config_filename, 0, - CONFIG_LOCK_TIMEOUT_MS); + fd = hold_lock_file_for_update(&lock, config_filename, 0); if (fd < 0) { error_errno(_("could not lock config file %s"), config_filename); ret = CONFIG_NO_LOCK; @@ -3371,8 +3359,7 @@ static int repo_config_copy_or_rename_section_in_file( if (!config_filename) config_filename = filename_buf = repo_git_path(r, "config"); - out_fd = hold_lock_file_for_update_timeout(&lock, config_filename, 0, - CONFIG_LOCK_TIMEOUT_MS); + out_fd = hold_lock_file_for_update(&lock, config_filename, 0); if (out_fd < 0) { ret = error(_("could not lock config file %s"), config_filename); goto out; diff --git a/fetch-pack.c b/fetch-pack.c index 37b9a4f798f4e6..c8fa0a609ac6de 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -25,7 +25,6 @@ #include "oidset.h" #include "packfile.h" #include "odb.h" -#include "object-name.h" #include "path.h" #include "connected.h" #include "fetch-negotiator.h" @@ -291,21 +290,21 @@ static int next_flush(int stateless_rpc, int count) } static void mark_tips(struct fetch_negotiator *negotiator, - const struct oid_array *negotiation_restrict_tips) + const struct oid_array *negotiation_tips) { struct refs_for_each_ref_options opts = { .flags = REFS_FOR_EACH_INCLUDE_BROKEN, }; int i; - if (!negotiation_restrict_tips) { + if (!negotiation_tips) { refs_for_each_ref_ext(get_main_ref_store(the_repository), rev_list_insert_ref_oid, negotiator, &opts); return; } - for (i = 0; i < negotiation_restrict_tips->nr; i++) - rev_list_insert_ref(negotiator, &negotiation_restrict_tips->oid[i]); + for (i = 0; i < negotiation_tips->nr; i++) + rev_list_insert_ref(negotiator, &negotiation_tips->oid[i]); return; } @@ -332,41 +331,6 @@ static void send_filter(struct fetch_pack_args *args, } } -static int add_oid_to_oidset(const struct reference *ref, void *cb_data) -{ - struct oidset *set = cb_data; - if (odb_has_object(the_repository->objects, ref->oid, 0)) - oidset_insert(set, ref->oid); - return 0; -} - -static void resolve_negotiation_require(const struct string_list *negotiation_require, - struct oidset *result) -{ - struct string_list_item *item; - - if (!negotiation_require || !negotiation_require->nr) - return; - - for_each_string_list_item(item, negotiation_require) { - if (!has_glob_specials(item->string)) { - struct object_id oid; - if (repo_get_oid(the_repository, item->string, &oid)) - continue; - if (!odb_has_object(the_repository->objects, &oid, 0)) - continue; - oidset_insert(result, &oid); - } else { - struct refs_for_each_ref_options opts = { - .pattern = item->string, - }; - refs_for_each_ref_ext( - get_main_ref_store(the_repository), - add_oid_to_oidset, result, &opts); - } - } -} - static int find_common(struct fetch_negotiator *negotiator, struct fetch_pack_args *args, int fd[2], struct object_id *result_oid, @@ -382,7 +346,6 @@ static int find_common(struct fetch_negotiator *negotiator, struct strbuf req_buf = STRBUF_INIT; size_t state_len = 0; struct packet_reader reader; - struct oidset negotiation_require_oids = OIDSET_INIT; if (args->stateless_rpc && multi_ack == 1) die(_("the option '%s' requires '%s'"), "--stateless-rpc", "multi_ack_detailed"); @@ -391,7 +354,7 @@ static int find_common(struct fetch_negotiator *negotiator, PACKET_READ_CHOMP_NEWLINE | PACKET_READ_DIE_ON_ERR_PACKET); - mark_tips(negotiator, args->negotiation_restrict_tips); + mark_tips(negotiator, args->negotiation_tips); for_each_cached_alternate(negotiator, insert_one_alternate_object); fetching = 0; @@ -510,25 +473,7 @@ static int find_common(struct fetch_negotiator *negotiator, trace2_region_enter("fetch-pack", "negotiation_v0_v1", the_repository); flushes = 0; retval = -1; - - /* Send unconditional haves from --negotiation-require */ - resolve_negotiation_require(args->negotiation_require, - &negotiation_require_oids); - if (oidset_size(&negotiation_require_oids)) { - struct oidset_iter iter; - oidset_iter_init(&negotiation_require_oids, &iter); - - while ((oid = oidset_iter_next(&iter))) { - packet_buf_write(&req_buf, "have %s\n", - oid_to_hex(oid)); - print_verbose(args, "have %s", oid_to_hex(oid)); - } - } - while ((oid = negotiator->next(negotiator))) { - /* avoid duplicate oids from --negotiation-require */ - if (oidset_contains(&negotiation_require_oids, oid)) - continue; packet_buf_write(&req_buf, "have %s\n", oid_to_hex(oid)); print_verbose(args, "have %s", oid_to_hex(oid)); in_vain++; @@ -638,7 +583,6 @@ static int find_common(struct fetch_negotiator *negotiator, flushes++; } strbuf_release(&req_buf); - oidset_clear(&negotiation_require_oids); if (!got_ready || !no_done) consume_shallow_list(args, &reader); @@ -1360,26 +1304,12 @@ static void add_common(struct strbuf *req_buf, struct oidset *common) static int add_haves(struct fetch_negotiator *negotiator, struct strbuf *req_buf, - int *haves_to_send, - struct oidset *negotiation_require_oids) + int *haves_to_send) { int haves_added = 0; const struct object_id *oid; - /* Send unconditional haves from --negotiation-require */ - if (negotiation_require_oids) { - struct oidset_iter iter; - oidset_iter_init(negotiation_require_oids, &iter); - - while ((oid = oidset_iter_next(&iter))) - packet_buf_write(req_buf, "have %s\n", - oid_to_hex(oid)); - } - while ((oid = negotiator->next(negotiator))) { - if (negotiation_require_oids && - oidset_contains(negotiation_require_oids, oid)) - continue; packet_buf_write(req_buf, "have %s\n", oid_to_hex(oid)); if (++haves_added >= *haves_to_send) break; @@ -1427,8 +1357,7 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out, struct fetch_pack_args *args, const struct ref *wants, struct oidset *common, int *haves_to_send, int *in_vain, - int sideband_all, int seen_ack, - struct oidset *negotiation_require_oids) + int sideband_all, int seen_ack) { int haves_added; int done_sent = 0; @@ -1483,8 +1412,7 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out, /* Add all of the common commits we've found in previous rounds */ add_common(&req_buf, common); - haves_added = add_haves(negotiator, &req_buf, haves_to_send, - negotiation_require_oids); + haves_added = add_haves(negotiator, &req_buf, haves_to_send); *in_vain += haves_added; trace2_data_intmax("negotiation_v2", the_repository, "haves_added", haves_added); trace2_data_intmax("negotiation_v2", the_repository, "in_vain", *in_vain); @@ -1729,7 +1657,6 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, struct ref *ref = copy_ref_list(orig_ref); enum fetch_state state = FETCH_CHECK_LOCAL; struct oidset common = OIDSET_INIT; - struct oidset negotiation_require_oids = OIDSET_INIT; struct packet_reader reader; int in_vain = 0, negotiation_started = 0; int negotiation_round = 0; @@ -1803,9 +1730,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, else state = FETCH_SEND_REQUEST; - mark_tips(negotiator, args->negotiation_restrict_tips); - resolve_negotiation_require(args->negotiation_require, - &negotiation_require_oids); + mark_tips(negotiator, args->negotiation_tips); for_each_cached_alternate(negotiator, insert_one_alternate_object); break; @@ -1824,8 +1749,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, &common, &haves_to_send, &in_vain, reader.use_sideband, - seen_ack, - &negotiation_require_oids)) { + seen_ack)) { trace2_region_leave_printf("negotiation_v2", "round", the_repository, "%d", negotiation_round); @@ -1962,7 +1886,6 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, fsck_options_clear(&fsck_options); oidset_clear(&common); - oidset_clear(&negotiation_require_oids); return ref; } @@ -2257,18 +2180,16 @@ static void clear_common_flag(struct oidset *s) } } -void negotiate_using_fetch(const struct oid_array *negotiation_restrict_tips, +void negotiate_using_fetch(const struct oid_array *negotiation_tips, const struct string_list *server_options, int stateless_rpc, int fd[], - struct oidset *acked_commits, - const struct string_list *negotiation_require) + struct oidset *acked_commits) { struct fetch_negotiator negotiator; struct packet_reader reader; struct object_array nt_object_array = OBJECT_ARRAY_INIT; struct strbuf req_buf = STRBUF_INIT; - struct oidset negotiation_require_oids = OIDSET_INIT; int haves_to_send = INITIAL_FLUSH; int in_vain = 0; int seen_ack = 0; @@ -2277,16 +2198,13 @@ void negotiate_using_fetch(const struct oid_array *negotiation_restrict_tips, timestamp_t min_generation = GENERATION_NUMBER_INFINITY; fetch_negotiator_init(the_repository, &negotiator); - mark_tips(&negotiator, negotiation_restrict_tips); - - resolve_negotiation_require(negotiation_require, - &negotiation_require_oids); + mark_tips(&negotiator, negotiation_tips); packet_reader_init(&reader, fd[0], NULL, 0, PACKET_READ_CHOMP_NEWLINE | PACKET_READ_DIE_ON_ERR_PACKET); - oid_array_for_each((struct oid_array *) negotiation_restrict_tips, + oid_array_for_each((struct oid_array *) negotiation_tips, add_to_object_array, &nt_object_array); @@ -2306,8 +2224,7 @@ void negotiate_using_fetch(const struct oid_array *negotiation_restrict_tips, packet_buf_write(&req_buf, "wait-for-done"); - haves_added = add_haves(&negotiator, &req_buf, &haves_to_send, - &negotiation_require_oids); + haves_added = add_haves(&negotiator, &req_buf, &haves_to_send); in_vain += haves_added; if (!haves_added || (seen_ack && in_vain >= MAX_IN_VAIN)) last_iteration = 1; @@ -2359,7 +2276,6 @@ void negotiate_using_fetch(const struct oid_array *negotiation_restrict_tips, clear_common_flag(acked_commits); object_array_clear(&nt_object_array); - oidset_clear(&negotiation_require_oids); negotiator.release(&negotiator); strbuf_release(&req_buf); } diff --git a/fetch-pack.h b/fetch-pack.h index 1daea8c542dc9e..9d3470366f85ec 100644 --- a/fetch-pack.h +++ b/fetch-pack.h @@ -21,14 +21,7 @@ struct fetch_pack_args { * If not NULL, during packfile negotiation, fetch-pack will send "have" * lines only with these tips and their ancestors. */ - const struct oid_array *negotiation_restrict_tips; - - /* - * If non-empty, ref patterns whose tips should always be sent - * as "have" lines during negotiation, regardless of what the - * negotiation algorithm selects. - */ - const struct string_list *negotiation_require; + const struct oid_array *negotiation_tips; unsigned deepen_relative:1; unsigned quiet:1; @@ -96,12 +89,11 @@ struct ref *fetch_pack(struct fetch_pack_args *args, * In the capability advertisement that has happened prior to invoking this * function, the "wait-for-done" capability must be present. */ -void negotiate_using_fetch(const struct oid_array *negotiation_restrict_tips, +void negotiate_using_fetch(const struct oid_array *negotiation_tips, const struct string_list *server_options, int stateless_rpc, int fd[], - struct oidset *acked_commits, - const struct string_list *negotiation_require); + struct oidset *acked_commits); /* * Print an appropriate error message for each sought ref that wasn't diff --git a/help.c b/help.c index 0fff43545cc167..3e59d07c370b83 100644 --- a/help.c +++ b/help.c @@ -22,7 +22,6 @@ #include "repository.h" #include "alias.h" #include "utf8.h" -#include "autocorrect.h" #ifndef NO_CURL #include "git-curl-compat.h" /* For LIBCURL_VERSION only */ @@ -537,23 +536,70 @@ int is_in_cmdlist(struct cmdnames *c, const char *s) return 0; } -static int resolve_aliases(const char *var, const char *value UNUSED, - const struct config_context *ctx UNUSED, void *data) +struct help_unknown_cmd_config { + int autocorrect; + struct cmdnames aliases; +}; + +#define AUTOCORRECT_SHOW (-4) +#define AUTOCORRECT_PROMPT (-3) +#define AUTOCORRECT_NEVER (-2) +#define AUTOCORRECT_IMMEDIATELY (-1) + +static int parse_autocorrect(const char *value) { - struct cmdnames *aliases = data; + switch (git_parse_maybe_bool_text(value)) { + case 1: + return AUTOCORRECT_IMMEDIATELY; + case 0: + return AUTOCORRECT_SHOW; + default: /* other random text */ + break; + } + + if (!strcmp(value, "prompt")) + return AUTOCORRECT_PROMPT; + if (!strcmp(value, "never")) + return AUTOCORRECT_NEVER; + if (!strcmp(value, "immediate")) + return AUTOCORRECT_IMMEDIATELY; + if (!strcmp(value, "show")) + return AUTOCORRECT_SHOW; + + return 0; +} + +static int git_unknown_cmd_config(const char *var, const char *value, + const struct config_context *ctx, + void *cb) +{ + struct help_unknown_cmd_config *cfg = cb; const char *subsection, *key; size_t subsection_len; + if (!strcmp(var, "help.autocorrect")) { + int v = parse_autocorrect(value); + + if (!v) { + v = git_config_int(var, value, ctx->kvi); + if (v < 0 || v == 1) + v = AUTOCORRECT_IMMEDIATELY; + } + + cfg->autocorrect = v; + } + + /* Also use aliases for command lookup */ if (!parse_config_key(var, "alias", &subsection, &subsection_len, &key)) { if (subsection) { /* [alias "name"] command = value */ if (!strcmp(key, "command")) - add_cmdname(aliases, subsection, + add_cmdname(&cfg->aliases, subsection, subsection_len); } else { /* alias.name = value */ - add_cmdname(aliases, key, strlen(key)); + add_cmdname(&cfg->aliases, key, strlen(key)); } } @@ -590,26 +636,28 @@ static const char bad_interpreter_advice[] = char *help_unknown_cmd(const char *cmd) { - struct cmdnames aliases = { 0 }; - struct autocorrect autocorrect = { 0 }; + struct help_unknown_cmd_config cfg = { 0 }; int i, n, best_similarity = 0; struct cmdnames main_cmds = { 0 }; struct cmdnames other_cmds = { 0 }; struct cmdname_help *common_cmds; - autocorrect_resolve(&autocorrect); + read_early_config(the_repository, git_unknown_cmd_config, &cfg); + + /* + * Disable autocorrection prompt in a non-interactive session + */ + if ((cfg.autocorrect == AUTOCORRECT_PROMPT) && (!isatty(0) || !isatty(2))) + cfg.autocorrect = AUTOCORRECT_NEVER; - if (autocorrect.mode == AUTOCORRECT_NEVER) { + if (cfg.autocorrect == AUTOCORRECT_NEVER) { fprintf_ln(stderr, _("git: '%s' is not a git command. See 'git --help'."), cmd); exit(1); } load_command_list("git-", &main_cmds, &other_cmds); - /* Also use aliases for command lookup */ - read_early_config(the_repository, resolve_aliases, &aliases); - - add_cmd_list(&main_cmds, &aliases); + add_cmd_list(&main_cmds, &cfg.aliases); add_cmd_list(&main_cmds, &other_cmds); QSORT(main_cmds.names, main_cmds.cnt, cmdname_compare); uniq(&main_cmds); @@ -668,18 +716,37 @@ char *help_unknown_cmd(const char *cmd) n++) ; /* still counting */ } - - if (autocorrect.mode != AUTOCORRECT_HINT && n == 1 && + if (cfg.autocorrect && cfg.autocorrect != AUTOCORRECT_SHOW && n == 1 && SIMILAR_ENOUGH(best_similarity)) { char *assumed = xstrdup(main_cmds.names[0]->name); fprintf_ln(stderr, - _("WARNING: You called a Git command named '%s', which does not exist."), + _("WARNING: You called a Git command named '%s', " + "which does not exist."), cmd); + if (cfg.autocorrect == AUTOCORRECT_IMMEDIATELY) + fprintf_ln(stderr, + _("Continuing under the assumption that " + "you meant '%s'."), + assumed); + else if (cfg.autocorrect == AUTOCORRECT_PROMPT) { + char *answer; + struct strbuf msg = STRBUF_INIT; + strbuf_addf(&msg, _("Run '%s' instead [y/N]? "), assumed); + answer = git_prompt(msg.buf, PROMPT_ECHO); + strbuf_release(&msg); + if (!(starts_with(answer, "y") || + starts_with(answer, "Y"))) + exit(1); + } else { + fprintf_ln(stderr, + _("Continuing in %0.1f seconds, " + "assuming that you meant '%s'."), + (float)cfg.autocorrect/10.0, assumed); + sleep_millisec(cfg.autocorrect * 100); + } - autocorrect_confirm(&autocorrect, assumed); - - cmdnames_release(&aliases); + cmdnames_release(&cfg.aliases); cmdnames_release(&main_cmds); cmdnames_release(&other_cmds); return assumed; diff --git a/meson.build b/meson.build index bd3272084178bf..098345ec524c55 100644 --- a/meson.build +++ b/meson.build @@ -290,7 +290,6 @@ libgit_sources = [ 'archive-zip.c', 'archive.c', 'attr.c', - 'autocorrect.c', 'base85.c', 'bisect.c', 'blame.c', diff --git a/pack-write.c b/pack-write.c index b8ab9510fff098..83eaf88541eefb 100644 --- a/pack-write.c +++ b/pack-write.c @@ -603,15 +603,6 @@ void write_promisor_file(const char *promisor_name, struct ref **sought, int nr_ int i, err; FILE *output = xfopen(promisor_name, "w"); - /* - * Write in the .promisor file the ref names and associated hashes, - * obtained by fetch-pack, at the point of generation of the - * corresponding packfile. These pieces of info are only used to make - * it easier to debug issues with partial clones, as we can identify - * what refs (and their associated hashes) were fetched at the time - * the packfile was downloaded, and if necessary, compare those hashes - * against what the promisor remote reports now. - */ for (i = 0; i < nr_sought; i++) fprintf(output, "%s %s\n", oid_to_hex(&sought[i]->old_oid), sought[i]->name); diff --git a/parse-options.c b/parse-options.c index 4ecbb901f57bd1..a676da86f5d617 100644 --- a/parse-options.c +++ b/parse-options.c @@ -7,8 +7,6 @@ #include "string-list.h" #include "strmap.h" #include "utf8.h" -#include "autocorrect.h" -#include "levenshtein.h" static int disallow_abbreviated_options; @@ -608,119 +606,17 @@ static enum parse_opt_result parse_nodash_opt(struct parse_opt_ctx_t *p, return PARSE_OPT_ERROR; } -static int parse_subcommand(const char *arg, const struct option *options) -{ - for (; options->type != OPTION_END; options++) { - parse_opt_subcommand_fn **opt_val; - - if (options->type != OPTION_SUBCOMMAND || - strcmp(options->long_name, arg)) - continue; - - opt_val = options->value; - *opt_val = options->subcommand_fn; - return 0; - } - - return -1; -} - -static void find_subcommands(struct string_list *list, - const struct option *options) -{ - for (; options->type != OPTION_END; options++) { - if (options->type == OPTION_SUBCOMMAND) - string_list_append(list, options->long_name); - } -} - -static int similar_enough(const char *cmd, unsigned int edit) -{ - size_t len = strlen(cmd); - unsigned int allowed = len < 3 ? 0 : len < 6 ? 1 : 2; - - return edit <= allowed; -} - -static const char *autocorrect_subcommand(const char *cmd, - struct string_list *cmds) +static enum parse_opt_result parse_subcommand(const char *arg, + const struct option *options) { - struct autocorrect autocorrect = { 0 }; - unsigned int min = UINT_MAX; - unsigned int ties = 0; - struct string_list_item *cand; - struct string_list_item *best = NULL; - - autocorrect_resolve(&autocorrect); - - /* - * Builtin subcommands are small enough that printing them all via - * usage_with_options() is sufficient. Therefore, AUTOCORRECT_HINT - * acts like AUTOCORRECT_NEVER. - */ - if (autocorrect.mode == AUTOCORRECT_HINT || - autocorrect.mode == AUTOCORRECT_NEVER) - return NULL; - - for_each_string_list_item(cand, cmds) { - unsigned int edit = levenshtein(cmd, cand->string, 1, 1, 1, 1); - - if (edit < min) { - min = edit; - best = cand; - ties = 0; - } else if (edit == min) { - ties++; + for (; options->type != OPTION_END; options++) + if (options->type == OPTION_SUBCOMMAND && + !strcmp(options->long_name, arg)) { + *(parse_opt_subcommand_fn **)options->value = options->subcommand_fn; + return PARSE_OPT_SUBCOMMAND; } - } - - if (!ties && similar_enough(cmd, min)) { - fprintf_ln(stderr, - _("WARNING: You called a subcommand named '%s', which does not exist."), - cmd); - autocorrect_confirm(&autocorrect, best->string); - return best->string; - } - - return NULL; -} - -static enum parse_opt_result handle_subcommand(struct parse_opt_ctx_t *ctx, - const char *arg, - const struct option *options, - const char * const usagestr[]) -{ - int err; - const char *assumed; - struct string_list cmds = STRING_LIST_INIT_NODUP; - - err = parse_subcommand(arg, options); - if (!err) - return PARSE_OPT_SUBCOMMAND; - - if (ctx->flags & PARSE_OPT_SUBCOMMAND_OPTIONAL && - !(ctx->flags & PARSE_OPT_SUBCOMMAND_AUTOCORR)) { - /* - * arg is neither a short or long option nor a subcommand. - * Since this command has a default operation mode, we have to - * treat this arg and all remaining args as args meant to that - * default operation mode. So we are done parsing. - */ - return PARSE_OPT_DONE; - } - - find_subcommands(&cmds, options); - assumed = autocorrect_subcommand(arg, &cmds); - - if (!assumed) { - error(_("unknown subcommand: `%s'"), arg); - usage_with_options(usagestr, options); - } - - string_list_clear(&cmds, 0); - parse_subcommand(assumed, options); - return PARSE_OPT_SUBCOMMAND; + return PARSE_OPT_UNKNOWN; } static void check_typos(const char *arg, const struct option *options) @@ -1115,16 +1011,38 @@ enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx, if (*arg != '-' || !arg[1]) { if (parse_nodash_opt(ctx, arg, options) == 0) continue; - - if (ctx->has_subcommands) - return handle_subcommand(ctx, arg, options, - usagestr); - - if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) - return PARSE_OPT_NON_OPTION; - - ctx->out[ctx->cpidx++] = ctx->argv[0]; - continue; + if (!ctx->has_subcommands) { + if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) + return PARSE_OPT_NON_OPTION; + ctx->out[ctx->cpidx++] = ctx->argv[0]; + continue; + } + switch (parse_subcommand(arg, options)) { + case PARSE_OPT_SUBCOMMAND: + return PARSE_OPT_SUBCOMMAND; + case PARSE_OPT_UNKNOWN: + if (ctx->flags & PARSE_OPT_SUBCOMMAND_OPTIONAL) + /* + * arg is neither a short or long + * option nor a subcommand. Since + * this command has a default + * operation mode, we have to treat + * this arg and all remaining args + * as args meant to that default + * operation mode. + * So we are done parsing. + */ + return PARSE_OPT_DONE; + error(_("unknown subcommand: `%s'"), arg); + usage_with_options(usagestr, options); + case PARSE_OPT_COMPLETE: + case PARSE_OPT_HELP: + case PARSE_OPT_ERROR: + case PARSE_OPT_DONE: + case PARSE_OPT_NON_OPTION: + /* Impossible. */ + BUG("parse_subcommand() cannot return these"); + } } /* lone -h asks for help */ diff --git a/parse-options.h b/parse-options.h index f29ac337893c92..706de9729f6b3f 100644 --- a/parse-options.h +++ b/parse-options.h @@ -40,7 +40,6 @@ enum parse_opt_flags { PARSE_OPT_ONE_SHOT = 1 << 5, PARSE_OPT_SHELL_EVAL = 1 << 6, PARSE_OPT_SUBCOMMAND_OPTIONAL = 1 << 7, - PARSE_OPT_SUBCOMMAND_AUTOCORR = 1 << 8, }; enum parse_opt_option_flags { diff --git a/promisor-remote.c b/promisor-remote.c index f486056493365e..38fa05054227f6 100644 --- a/promisor-remote.c +++ b/promisor-remote.c @@ -42,18 +42,11 @@ static int fetch_objects(struct repository *repo, child.in = -1; if (repo != the_repository) prepare_other_repo_env(&child.env, repo->gitdir); - /* - * Prevent the child's index-pack from recursing back into - * fetch_objects() when resolving REF_DELTA bases it does not - * have. With noop negotiation the server should never need - * to send such deltas, so a depth-2 fetch would not help. - */ - strvec_pushf(&child.env, "%s=1", NO_LAZY_FETCH_ENVIRONMENT); strvec_pushl(&child.args, "-c", "fetch.negotiationAlgorithm=noop", "fetch", remote_name, "--no-tags", "--no-write-fetch-head", "--recurse-submodules=no", "--filter=blob:none", "--stdin", NULL); - if (!repo_config_get_bool(repo, "promisor.quiet", &quiet) && quiet) + if (!repo_config_get_bool(the_repository, "promisor.quiet", &quiet) && quiet) strvec_push(&child.args, "--quiet"); if (start_command(&child)) die(_("promisor-remote: unable to fork off fetch subprocess")); diff --git a/remote.c b/remote.c index 4a951ddf02a40c..a664cd166aa3b9 100644 --- a/remote.c +++ b/remote.c @@ -152,8 +152,6 @@ static struct remote *make_remote(struct remote_state *remote_state, refspec_init_push(&ret->push); refspec_init_fetch(&ret->fetch); string_list_init_dup(&ret->server_options); - string_list_init_dup(&ret->negotiation_restrict); - string_list_init_dup(&ret->negotiation_require); ALLOC_GROW(remote_state->remotes, remote_state->remotes_nr + 1, remote_state->remotes_alloc); @@ -181,8 +179,6 @@ static void remote_clear(struct remote *remote) FREE_AND_NULL(remote->http_proxy); FREE_AND_NULL(remote->http_proxy_authmethod); string_list_clear(&remote->server_options, 0); - string_list_clear(&remote->negotiation_restrict, 0); - string_list_clear(&remote->negotiation_require, 0); } static void add_merge(struct branch *branch, const char *name) @@ -566,14 +562,6 @@ static int handle_config(const char *key, const char *value, } else if (!strcmp(subkey, "serveroption")) { return parse_transport_option(key, value, &remote->server_options); - } else if (!strcmp(subkey, "negotiationrestrict")) { - if (!value) - return config_error_nonbool(key); - string_list_append(&remote->negotiation_restrict, value); - } else if (!strcmp(subkey, "negotiationrequire")) { - if (!value) - return config_error_nonbool(key); - string_list_append(&remote->negotiation_require, value); } else if (!strcmp(subkey, "followremotehead")) { const char *no_warn_branch; if (!strcmp(value, "never")) @@ -2126,43 +2114,6 @@ int get_fetch_map(const struct ref *remote_refs, return 0; } -int get_remote_group(const char *key, const char *value, - const struct config_context *ctx UNUSED, - void *priv) -{ - struct remote_group_data *g = priv; - - if (skip_prefix(key, "remotes.", &key) && !strcmp(key, g->name)) { - /* split list by white space */ - while (*value) { - size_t wordlen = strcspn(value, " \t\n"); - - if (wordlen >= 1) - string_list_append_nodup(g->list, - xstrndup(value, wordlen)); - value += wordlen + (value[wordlen] != '\0'); - } - } - - return 0; -} - -int add_remote_or_group(const char *name, struct string_list *list) -{ - int prev_nr = list->nr; - struct remote_group_data g; - g.name = name; g.list = list; - - repo_config(the_repository, get_remote_group, &g); - if (list->nr == prev_nr) { - struct remote *remote = remote_get(name); - if (!remote_is_configured(remote, 0)) - return 0; - string_list_append(list, remote->name); - } - return 1; -} - int resolve_remote_symref(struct ref *ref, struct ref *list) { if (!ref->symref) diff --git a/remote.h b/remote.h index ffc0a97ef0f8b5..fc052945ee451d 100644 --- a/remote.h +++ b/remote.h @@ -117,8 +117,6 @@ struct remote { char *http_proxy_authmethod; struct string_list server_options; - struct string_list negotiation_restrict; - struct string_list negotiation_require; enum follow_remote_head_settings follow_remote_head; const char *no_warn_branch; @@ -349,18 +347,6 @@ int branch_has_merge_config(struct branch *branch); int branch_merge_matches(struct branch *, int n, const char *); -/* list of the remote in a group as configured */ -struct remote_group_data { - const char *name; - struct string_list *list; -}; - -int get_remote_group(const char *key, const char *value, - const struct config_context *ctx, - void *priv); - -int add_remote_or_group(const char *name, struct string_list *list); - /** * Return the fully-qualified refname of the tracking branch for `branch`. * I.e., what "branch@{upstream}" would give you. Returns NULL if no diff --git a/repack-promisor.c b/repack-promisor.c index c7025e97f25b24..90318ce15093f5 100644 --- a/repack-promisor.c +++ b/repack-promisor.c @@ -1,17 +1,11 @@ #include "git-compat-util.h" #include "repack.h" -#include "hash.h" #include "hex.h" -#include "odb.h" #include "pack.h" #include "packfile.h" #include "path.h" #include "repository.h" #include "run-command.h" -#include "strbuf.h" -#include "string-list.h" -#include "strmap.h" -#include "strvec.h" struct write_oid_context { struct child_process *cmd; @@ -40,131 +34,10 @@ static int write_oid(const struct object_id *oid, return 0; } -/* - * Go through all .promisor files contained in repo (excluding those whose name - * appears in not_repacked_basenames, which acts as a ignorelist), and copies - * their content inside the destination file "-.promisor". - * Each line of a never repacked .promisor file is: " " (as described - * in the write_promisor_file() function). - * After a repack, the copied lines will be: "