Merge branch 'ds/commit-graph-on-fetch'
authorJunio C Hamano <gitster@pobox.com>
Mon, 30 Sep 2019 04:19:32 +0000 (13:19 +0900)
committerJunio C Hamano <gitster@pobox.com>
Mon, 30 Sep 2019 04:19:32 +0000 (13:19 +0900)
A configuration variable tells "git fetch" to write the commit
graph after finishing.

* ds/commit-graph-on-fetch:
fetch: add fetch.writeCommitGraph config setting

1  2 
builtin/fetch.c
t/t5510-fetch.sh
diff --combined builtin/fetch.c
index 9b27ae968199a75e62a617b649b56788e501e076,d36a40385959a16eda95638a5a95355673d3cb9d..67c0eb88c655ab949845b626367b3f2192e9ccb6
@@@ -23,8 -23,7 +23,9 @@@
  #include "packfile.h"
  #include "list-objects-filter-options.h"
  #include "commit-reach.h"
 +#include "branch.h"
 +#include "promisor-remote.h"
+ #include "commit-graph.h"
  
  #define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
  
@@@ -52,8 -51,7 +53,8 @@@ static int fetch_prune_tags_config = -1
  static int prune_tags = -1; /* unspecified */
  #define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by default? */
  
 -static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative;
 +static int all, append, dry_run, force, keep, multiple, update_head_ok;
 +static int verbosity, deepen_relative, set_upstream;
  static int progress = -1;
  static int enable_auto_gc = 1;
  static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
@@@ -126,8 -124,6 +127,8 @@@ static struct option builtin_fetch_opti
        OPT__VERBOSITY(&verbosity),
        OPT_BOOL(0, "all", &all,
                 N_("fetch from all remotes")),
 +      OPT_BOOL(0, "set-upstream", &set_upstream,
 +               N_("set upstream for git pull/fetch")),
        OPT_BOOL('a', "append", &append,
                 N_("append to .git/FETCH_HEAD instead of overwriting")),
        OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
@@@ -855,15 -851,6 +856,15 @@@ static int iterate_ref_map(void *cb_dat
        return 0;
  }
  
 +static const char warn_show_forced_updates[] =
 +N_("Fetch normally indicates which branches had a forced update,\n"
 +   "but that check has been disabled. To re-enable, use '--show-forced-updates'\n"
 +   "flag or run 'git config fetch.showForcedUpdates true'.");
 +static const char warn_time_show_forced_updates[] =
 +N_("It took %.2f seconds to check forced updates. You can use\n"
 +   "'--no-show-forced-updates' or run 'git config fetch.showForcedUpdates false'\n"
 +   " to avoid this check.\n");
 +
  static int store_updated_refs(const char *raw_url, const char *remote_name,
                              int connectivity_checked, struct ref *ref_map)
  {
  
        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'."));
 +                      warning(_(warn_show_forced_updates));
                } 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"),
 +                      warning(_(warn_time_show_forced_updates),
                                forced_updates_ms / 1000.0);
 -                      warning(_("or run 'git config fetch.showForcedUpdates false' to avoid this check.\n"));
                }
        }
  
@@@ -1243,10 -1232,13 +1244,10 @@@ static struct transport *prepare_transp
        if (update_shallow)
                set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes");
        if (filter_options.choice) {
 -              struct strbuf expanded_filter_spec = STRBUF_INIT;
 -              expand_list_objects_filter_spec(&filter_options,
 -                                              &expanded_filter_spec);
 -              set_option(transport, TRANS_OPT_LIST_OBJECTS_FILTER,
 -                         expanded_filter_spec.buf);
 +              const char *spec =
 +                      expand_list_objects_filter_spec(&filter_options);
 +              set_option(transport, TRANS_OPT_LIST_OBJECTS_FILTER, spec);
                set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
 -              strbuf_release(&expanded_filter_spec);
        }
        if (negotiation_tip.nr) {
                if (transport->smart_options)
@@@ -1369,51 -1361,6 +1370,51 @@@ static int do_fetch(struct transport *t
                retcode = 1;
                goto cleanup;
        }
 +
 +      if (set_upstream) {
 +              struct branch *branch = branch_get("HEAD");
 +              struct ref *rm;
 +              struct ref *source_ref = NULL;
 +
 +              /*
 +               * We're setting the upstream configuration for the
 +               * current branch. The relevent upstream is the
 +               * fetched branch that is meant to be merged with the
 +               * current one, i.e. the one fetched to FETCH_HEAD.
 +               *
 +               * When there are several such branches, consider the
 +               * request ambiguous and err on the safe side by doing
 +               * nothing and just emit a warning.
 +               */
 +              for (rm = ref_map; rm; rm = rm->next) {
 +                      if (!rm->peer_ref) {
 +                              if (source_ref) {
 +                                      warning(_("multiple branch detected, incompatible with --set-upstream"));
 +                                      goto skip;
 +                              } else {
 +                                      source_ref = rm;
 +                              }
 +                      }
 +              }
 +              if (source_ref) {
 +                      if (!strcmp(source_ref->name, "HEAD") ||
 +                          starts_with(source_ref->name, "refs/heads/"))
 +                              install_branch_config(0,
 +                                                    branch->name,
 +                                                    transport->remote->name,
 +                                                    source_ref->name);
 +                      else if (starts_with(source_ref->name, "refs/remotes/"))
 +                              warning(_("not setting upstream for a remote remote-tracking branch"));
 +                      else if (starts_with(source_ref->name, "refs/tags/"))
 +                              warning(_("not setting upstream for a remote tag"));
 +                      else
 +                              warning(_("unknown branch type"));
 +              } else {
 +                      warning(_("no source branch found.\n"
 +                              "you need to specify exactly one branch with the --set-upstream option."));
 +              }
 +      }
 + skip:
        free_refs(ref_map);
  
        /* if neither --no-tags nor --tags was specified, do automated tag
@@@ -1557,27 -1504,37 +1558,27 @@@ static inline void fetch_one_setup_part
         * If no prior partial clone/fetch and the current fetch DID NOT
         * request a partial-fetch, do a normal fetch.
         */
 -      if (!repository_format_partial_clone && !filter_options.choice)
 +      if (!has_promisor_remote() && !filter_options.choice)
                return;
  
        /*
 -       * If this is the FIRST partial-fetch request, we enable partial
 -       * on this repo and remember the given filter-spec as the default
 -       * for subsequent fetches to this remote.
 +       * If this is a partial-fetch request, we enable partial on
 +       * this repo if not already enabled and remember the given
 +       * 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);
                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
         * explicitly given filter-spec or inherit the filter-spec from
         * the config.
         */
        if (!filter_options.choice)
 -              partial_clone_get_default_filter_spec(&filter_options);
 +              partial_clone_get_default_filter_spec(&filter_options, remote->name);
        return;
  }
  
@@@ -1698,7 -1655,7 +1699,7 @@@ int cmd_fetch(int argc, const char **ar
        if (depth || deepen_since || deepen_not.nr)
                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");
  
        if (all) {
        }
  
        if (remote) {
 -              if (filter_options.choice || repository_format_partial_clone)
 +              if (filter_options.choice || has_promisor_remote())
                        fetch_one_setup_partial(remote);
                result = fetch_one(remote, argc, argv, prune_tags_ok);
        } else {
  
        string_list_clear(&list, 0);
  
 -              int commit_graph_flags = COMMIT_GRAPH_SPLIT;
+       prepare_repo_settings(the_repository);
+       if (the_repository->settings.fetch_write_commit_graph) {
 -                      commit_graph_flags |= COMMIT_GRAPH_PROGRESS;
++              int commit_graph_flags = COMMIT_GRAPH_WRITE_SPLIT;
+               struct split_commit_graph_opts split_opts;
+               memset(&split_opts, 0, sizeof(struct split_commit_graph_opts));
+               if (progress)
++                      commit_graph_flags |= COMMIT_GRAPH_WRITE_PROGRESS;
+               write_commit_graph_reachable(get_object_directory(),
+                                            commit_graph_flags,
+                                            &split_opts);
+       }
        close_object_store(the_repository->objects);
  
        if (enable_auto_gc) {
diff --combined t/t5510-fetch.sh
index 34b486f1a48b08f483d36c6421e47323977db9d0,91ede622f033c7cced55bd397c55cc2f554225ff..ecabbe1616d8a5c597fc32a354b053bc38a40334
@@@ -570,6 -570,19 +570,19 @@@ test_expect_success 'LHS of refspec fol
        )
  '
  
+ test_expect_success 'fetch.writeCommitGraph' '
+       git clone three write &&
+       (
+               cd three &&
+               test_commit new
+       ) &&
+       (
+               cd write &&
+               git -c fetch.writeCommitGraph fetch origin &&
+               test_path_is_file .git/objects/info/commit-graphs/commit-graph-chain
+       )
+ '
  # configured prune tests
  
  set_config_tristate () {
@@@ -902,29 -915,6 +915,29 @@@ test_expect_success C_LOCALE_OUTPUT 'fe
        test_cmp expect actual
  '
  
 +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
 +      )
 +'
 +
  setup_negotiation_tip () {
        SERVER="$1"
        URL="$2"
@@@ -1001,7 -991,27 +1014,7 @@@ test_expect_success '--negotiation-tip 
        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
 -      )
 -'
 +# DO NOT add non-httpd-specific tests here, because the last part of this
 +# test script is only executed when httpd is available and enabled.
  
  test_done