Merge branch 'ds/fetch-disable-force-notice'
authorJunio C Hamano <gitster@pobox.com>
Tue, 9 Jul 2019 22:25:46 +0000 (15:25 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 9 Jul 2019 22:25:46 +0000 (15:25 -0700)
"git fetch" and "git pull" reports when a fetch results in
non-fast-forward updates to let the user notice unusual situation.
The commands learned "--no-shown-forced-updates" option to disable
this safety feature.

* ds/fetch-disable-force-notice:
  pull: add --[no-]show-forced-updates passthrough
  fetch: warn about forced updates in branch listing
  fetch: add --[no-]show-forced-updates argument

Documentation/config/advice.txt
Documentation/config/fetch.txt
Documentation/fetch-options.txt
advice.c
advice.h
builtin/fetch.c
builtin/pull.c
t/t5510-fetch.sh

index 0103faa..ee85c53 100644 (file)
@@ -4,6 +4,10 @@ advice.*::
        can tell Git that you do not need help by setting these to 'false':
 +
 --
+       fetchShowForcedUpdates::
+               Advice shown when linkgit:git-fetch[1] takes a long time
+               to calculate forced updates after ref updates, or to warn
+               that the check is disabled.
        pushUpdateRejected::
                Set this variable to 'false' if you want to disable
                'pushNonFFCurrent',
index cbfad6c..ba890b5 100644 (file)
@@ -63,3 +63,8 @@ fetch.negotiationAlgorithm::
        Unknown values will cause 'git fetch' to error out.
 +
 See also the `--negotiation-tip` option for linkgit:git-fetch[1].
+
+fetch.showForcedUpdates::
+       Set to false to enable `--no-show-forced-updates` in
+       linkgit:git-fetch[1] and linkgit:git-pull[1] commands.
+       Defaults to true.
index 592f391..3c9b4f9 100644 (file)
@@ -225,6 +225,19 @@ endif::git-pull[]
        When multiple `--server-option=<option>` are given, they are all
        sent to the other side in the order listed on the command line.
 
+--show-forced-updates::
+       By default, git checks if a branch is force-updated during
+       fetch. This can be disabled through fetch.showForcedUpdates, but
+       the --show-forced-updates option guarantees this check occurs.
+       See linkgit:git-config[1].
+
+--no-show-forced-updates::
+       By default, git checks if a branch is force-updated during
+       fetch. Pass --no-show-forced-updates or set fetch.showForcedUpdates
+       to false to skip this check for performance reasons. If used during
+       'git-pull' the --ff-only option will still check for forced updates
+       before attempting a fast-forward update. See linkgit:git-config[1].
+
 -4::
 --ipv4::
        Use IPv4 addresses only, ignoring IPv6 addresses.
index 2d330d2..67de6de 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -3,6 +3,7 @@
 #include "color.h"
 #include "help.h"
 
+int advice_fetch_show_forced_updates = 1;
 int advice_push_update_rejected = 1;
 int advice_push_non_ff_current = 1;
 int advice_push_non_ff_matching = 1;
@@ -60,6 +61,7 @@ static struct {
        const char *name;
        int *preference;
 } advice_config[] = {
+       { "fetchShowForcedUpdates", &advice_fetch_show_forced_updates },
        { "pushUpdateRejected", &advice_push_update_rejected },
        { "pushNonFFCurrent", &advice_push_non_ff_current },
        { "pushNonFFMatching", &advice_push_non_ff_matching },
index c86de9b..940c4c2 100644 (file)
--- a/advice.h
+++ b/advice.h
@@ -3,6 +3,7 @@
 
 #include "git-compat-util.h"
 
+extern int advice_fetch_show_forced_updates;
 extern int advice_push_update_rejected;
 extern int advice_push_non_ff_current;
 extern int advice_push_non_ff_matching;
index 667f2ce..53ce99d 100644 (file)
@@ -24,6 +24,8 @@
 #include "list-objects-filter-options.h"
 #include "commit-reach.h"
 
+#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
+
 static const char * const builtin_fetch_usage[] = {
        N_("git fetch [<options>] [<repository> [<refspec>...]]"),
        N_("git fetch [<options>] <group>"),
@@ -39,6 +41,8 @@ enum {
 };
 
 static int fetch_prune_config = -1; /* unspecified */
+static int fetch_show_forced_updates = 1;
+static uint64_t forced_updates_ms = 0;
 static int prune = -1; /* unspecified */
 #define PRUNE_BY_DEFAULT 0 /* do we prune by default? */
 
@@ -80,6 +84,11 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
                return 0;
        }
 
+       if (!strcmp(k, "fetch.showforcedupdates")) {
+               fetch_show_forced_updates = git_config_bool(k, v);
+               return 0;
+       }
+
        if (!strcmp(k, "submodule.recurse")) {
                int r = git_config_bool(k, v) ?
                        RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
@@ -172,6 +181,8 @@ static struct option builtin_fetch_options[] = {
        OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
        OPT_BOOL(0, "auto-gc", &enable_auto_gc,
                 N_("run 'gc --auto' after fetching")),
+       OPT_BOOL(0, "show-forced-updates", &fetch_show_forced_updates,
+                N_("check for forced-updates on all updated branches")),
        OPT_END()
 };
 
@@ -710,6 +721,7 @@ static int update_local_ref(struct ref *ref,
        enum object_type type;
        struct branch *current_branch = branch_get(NULL);
        const char *pretty_ref = prettify_refname(ref->name);
+       int fast_forward = 0;
 
        type = oid_object_info(the_repository, &ref->new_oid, NULL);
        if (type < 0)
@@ -784,9 +796,18 @@ static int update_local_ref(struct ref *ref,
                return r;
        }
 
-       if (in_merge_bases(current, updated)) {
+       if (fetch_show_forced_updates) {
+               uint64_t t_before = getnanotime();
+               fast_forward = in_merge_bases(current, updated);
+               forced_updates_ms += (getnanotime() - t_before) / 1000000;
+       } else {
+               fast_forward = 1;
+       }
+
+       if (fast_forward) {
                struct strbuf quickref = STRBUF_INIT;
                int r;
+
                strbuf_add_unique_abbrev(&quickref, &current->object.oid, DEFAULT_ABBREV);
                strbuf_addstr(&quickref, "..");
                strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
@@ -982,6 +1003,17 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
                      " 'git remote prune %s' to remove any old, conflicting "
                      "branches"), remote_name);
 
+       if (advice_fetch_show_forced_updates) {
+               if (!fetch_show_forced_updates) {
+                       warning(_("Fetch normally indicates which branches had a forced update, but that check has been disabled."));
+                       warning(_("To re-enable, use '--show-forced-updates' flag or run 'git config fetch.showForcedUpdates true'."));
+               } else if (forced_updates_ms > FORCED_UPDATES_DELAY_WARNING_IN_MS) {
+                       warning(_("It took %.2f seconds to check forced updates. You can use '--no-show-forced-updates'\n"),
+                               forced_updates_ms / 1000.0);
+                       warning(_("or run 'git config fetch.showForcedUpdates false' to avoid this check.\n"));
+               }
+       }
+
  abort:
        strbuf_release(&note);
        free(url);
index 9dd32a1..f1eaf6e 100644 (file)
@@ -128,6 +128,7 @@ static char *opt_update_shallow;
 static char *opt_refmap;
 static char *opt_ipv4;
 static char *opt_ipv6;
+static int opt_show_forced_updates = -1;
 
 static struct option pull_options[] = {
        /* Shared options */
@@ -240,6 +241,8 @@ static struct option pull_options[] = {
        OPT_PASSTHRU('6',  "ipv6", &opt_ipv6, NULL,
                N_("use IPv6 addresses only"),
                PARSE_OPT_NOARG),
+       OPT_BOOL(0, "show-forced-updates", &opt_show_forced_updates,
+                N_("check for forced-updates on all updated branches")),
 
        OPT_END()
 };
@@ -549,6 +552,10 @@ static int run_fetch(const char *repo, const char **refspecs)
                argv_array_push(&args, opt_ipv4);
        if (opt_ipv6)
                argv_array_push(&args, opt_ipv6);
+       if (opt_show_forced_updates > 0)
+               argv_array_push(&args, "--show-forced-updates");
+       else if (opt_show_forced_updates == 0)
+               argv_array_push(&args, "--no-show-forced-updates");
 
        if (repo) {
                argv_array_push(&args, repo);
index e98d90d..139f710 100755 (executable)
@@ -978,4 +978,27 @@ test_expect_success '--negotiation-tip limits "have" lines sent with HTTP protoc
        check_negotiation_tip
 '
 
+test_expect_success '--no-show-forced-updates' '
+       mkdir forced-updates &&
+       (
+               cd forced-updates &&
+               git init &&
+               test_commit 1 &&
+               test_commit 2
+       ) &&
+       git clone forced-updates forced-update-clone &&
+       git clone forced-updates no-forced-update-clone &&
+       git -C forced-updates reset --hard HEAD~1 &&
+       (
+               cd forced-update-clone &&
+               git fetch --show-forced-updates origin 2>output &&
+               test_i18ngrep "(forced update)" output
+       ) &&
+       (
+               cd no-forced-update-clone &&
+               git fetch --no-show-forced-updates origin 2>output &&
+               ! test_i18ngrep "(forced update)" output
+       )
+'
+
 test_done