]> git.ipfire.org Git - thirdparty/git.git/blobdiff - builtin/pull.c
Merge branch 'js/retire-preserve-merges'
[thirdparty/git.git] / builtin / pull.c
index bda5c32ab6fbfa0f88dbefbe3bdc50ecdb75f959..ae9f5bd7ccde012abb9412f99f5e96cb98253150 100644 (file)
@@ -26,6 +26,7 @@
 #include "wt-status.h"
 #include "commit-reach.h"
 #include "sequencer.h"
+#include "packfile.h"
 
 /**
  * Parses the value of --rebase. If value is a false value, returns
@@ -576,7 +577,7 @@ static int run_fetch(const char *repo, const char **refspecs)
                strvec_pushv(&args, refspecs);
        } else if (*refspecs)
                BUG("refspecs without repo?");
-       ret = run_command_v_opt(args.v, RUN_GIT_CMD);
+       ret = run_command_v_opt(args.v, RUN_GIT_CMD | RUN_CLOSE_OBJECT_STORE);
        strvec_clear(&args);
        return ret;
 }
@@ -890,6 +891,8 @@ static int run_rebase(const struct object_id *newbase,
        strvec_pushv(&args, opt_strategy_opts.v);
        if (opt_gpg_sign)
                strvec_push(&args, opt_gpg_sign);
+       if (opt_signoff)
+               strvec_push(&args, opt_signoff);
        if (opt_autostash == 0)
                strvec_push(&args, "--no-autostash");
        else if (opt_autostash == 1)
@@ -908,12 +911,18 @@ static int run_rebase(const struct object_id *newbase,
        return ret;
 }
 
-static int get_can_ff(struct object_id *orig_head, struct object_id *orig_merge_head)
+static int get_can_ff(struct object_id *orig_head,
+                     struct oid_array *merge_heads)
 {
        int ret;
        struct commit_list *list = NULL;
        struct commit *merge_head, *head;
+       struct object_id *orig_merge_head;
 
+       if (merge_heads->nr > 1)
+               return 0;
+
+       orig_merge_head = &merge_heads->oid[0];
        head = lookup_commit_reference(the_repository, orig_head);
        commit_list_insert(head, &list);
        merge_head = lookup_commit_reference(the_repository, orig_merge_head);
@@ -924,9 +933,9 @@ static int get_can_ff(struct object_id *orig_head, struct object_id *orig_merge_
 
 static void show_advice_pull_non_ff(void)
 {
-       advise(_("Pulling without specifying how to reconcile divergent branches is\n"
-                "discouraged. You can squelch this message by running one of the following\n"
-                "commands sometime before your next pull:\n"
+       advise(_("You have divergent branches and need to specify how to reconcile them.\n"
+                "You can do so by running one of the following commands sometime before\n"
+                "your next pull:\n"
                 "\n"
                 "  git config pull.rebase false  # merge (the default strategy)\n"
                 "  git config pull.rebase true   # rebase\n"
@@ -963,8 +972,22 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 
        parse_repo_refspecs(argc, argv, &repo, &refspecs);
 
-       if (!opt_ff)
+       if (!opt_ff) {
                opt_ff = xstrdup_or_null(config_get_ff());
+               /*
+                * A subtle point: opt_ff was set on the line above via
+                * reading from config.  opt_rebase, in contrast, is set
+                * before this point via command line options.  The setting
+                * of opt_rebase via reading from config (using
+                * config_get_rebase()) does not happen until later.  We
+                * are relying on the next if-condition happening before
+                * the config_get_rebase() call so that an explicit
+                * "--rebase" can override a config setting of
+                * pull.ff=only.
+                */
+               if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only"))
+                       opt_ff = "--ff";
+       }
 
        if (opt_rebase < 0)
                opt_rebase = config_get_rebase(&rebase_unspecified);
@@ -1038,14 +1061,25 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
                        die(_("Cannot merge multiple branches into empty head."));
                return pull_into_void(merge_heads.oid, &curr_head);
        }
-       if (opt_rebase && merge_heads.nr > 1)
-               die(_("Cannot rebase onto multiple branches."));
+       if (merge_heads.nr > 1) {
+               if (opt_rebase)
+                       die(_("Cannot rebase onto multiple branches."));
+               if (opt_ff && !strcmp(opt_ff, "--ff-only"))
+                       die(_("Cannot fast-forward to multiple branches."));
+       }
 
-       can_ff = get_can_ff(&orig_head, &merge_heads.oid[0]);
+       can_ff = get_can_ff(&orig_head, &merge_heads);
 
-       if (rebase_unspecified && !opt_ff && !can_ff) {
-               if (opt_verbosity >= 0)
-                       show_advice_pull_non_ff();
+       /* ff-only takes precedence over rebase */
+       if (opt_ff && !strcmp(opt_ff, "--ff-only")) {
+               if (!can_ff)
+                       die_ff_impossible();
+               opt_rebase = REBASE_FALSE;
+       }
+       /* If no action specified and we can't fast forward, then warn. */
+       if (!opt_ff && rebase_unspecified && !can_ff) {
+               show_advice_pull_non_ff();
+               die(_("Need to specify how to reconcile divergent branches."));
        }
 
        if (opt_rebase) {