Merge branch 'sw/pull-ipv46-passthru' into maint
[git/git.git] / builtin / pull.c
index ef22659..1b4d9cd 100644 (file)
@@ -6,6 +6,7 @@
  * Fetch one or more remote refs and merge it/them into the current HEAD.
  */
 #include "cache.h"
+#include "config.h"
 #include "builtin.h"
 #include "parse-options.h"
 #include "exec_cmd.h"
@@ -15,6 +16,8 @@
 #include "dir.h"
 #include "refs.h"
 #include "revision.h"
+#include "submodule.h"
+#include "submodule-config.h"
 #include "tempfile.h"
 #include "lockfile.h"
 #include "wt-status.h"
@@ -36,7 +39,7 @@ enum rebase_type {
 static enum rebase_type parse_config_rebase(const char *key, const char *value,
                int fatal)
 {
-       int v = git_config_maybe_bool("pull.rebase", value);
+       int v = git_parse_maybe_bool(value);
 
        if (!v)
                return REBASE_FALSE;
@@ -77,6 +80,7 @@ static const char * const pull_usage[] = {
 /* Shared options */
 static int opt_verbosity;
 static char *opt_progress;
+static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 
 /* Options passed to git-merge or git-rebase */
 static enum rebase_type opt_rebase = -1;
@@ -101,7 +105,6 @@ static char *opt_upload_pack;
 static int opt_force;
 static char *opt_tags;
 static char *opt_prune;
-static char *opt_recurse_submodules;
 static char *max_children;
 static int opt_dry_run;
 static char *opt_keep;
@@ -118,6 +121,10 @@ static struct option pull_options[] = {
        OPT_PASSTHRU(0, "progress", &opt_progress, NULL,
                N_("force progress reporting"),
                PARSE_OPT_NOARG),
+       { OPTION_CALLBACK, 0, "recurse-submodules",
+                  &recurse_submodules, N_("on-demand"),
+                  N_("control for recursive fetching of submodules"),
+                  PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules },
 
        /* Options passed to git-merge or git-rebase */
        OPT_GROUP(N_("Options related to merging")),
@@ -189,10 +196,6 @@ static struct option pull_options[] = {
        OPT_PASSTHRU('p', "prune", &opt_prune, NULL,
                N_("prune remote-tracking branches no longer on remote"),
                PARSE_OPT_NOARG),
-       OPT_PASSTHRU(0, "recurse-submodules", &opt_recurse_submodules,
-               N_("on-demand"),
-               N_("control recursive fetching of submodules"),
-               PARSE_OPT_OPTARG),
        OPT_PASSTHRU('j', "jobs", &max_children, N_("n"),
                N_("number of submodules pulled in parallel"),
                PARSE_OPT_OPTARG),
@@ -279,7 +282,7 @@ static const char *config_get_ff(void)
        if (git_config_get_value("pull.ff", &value))
                return NULL;
 
-       switch (git_config_maybe_bool("pull.ff", value)) {
+       switch (git_parse_maybe_bool(value)) {
        case 0:
                return "--no-ff";
        case 1:
@@ -330,6 +333,10 @@ static int git_pull_config(const char *var, const char *value, void *cb)
        if (!strcmp(var, "rebase.autostash")) {
                config_autostash = git_config_bool(var, value);
                return 0;
+       } else if (!strcmp(var, "submodule.recurse")) {
+               recurse_submodules = git_config_bool(var, value) ?
+                       RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
+               return 0;
        }
        return git_default_config(var, value, cb);
 }
@@ -345,8 +352,7 @@ static void get_merge_heads(struct oid_array *merge_heads)
        struct strbuf sb = STRBUF_INIT;
        struct object_id oid;
 
-       if (!(fp = fopen(filename, "r")))
-               die_errno(_("could not open '%s' for reading"), filename);
+       fp = xfopen(filename, "r");
        while (strbuf_getline_lf(&sb, fp) != EOF) {
                if (get_oid_hex(sb.buf, &oid))
                        continue;  /* invalid line: does not start with SHA1 */
@@ -492,8 +498,20 @@ static int run_fetch(const char *repo, const char **refspecs)
                argv_array_push(&args, opt_tags);
        if (opt_prune)
                argv_array_push(&args, opt_prune);
-       if (opt_recurse_submodules)
-               argv_array_push(&args, opt_recurse_submodules);
+       if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT)
+               switch (recurse_submodules) {
+               case RECURSE_SUBMODULES_ON:
+                       argv_array_push(&args, "--recurse-submodules=on");
+                       break;
+               case RECURSE_SUBMODULES_OFF:
+                       argv_array_push(&args, "--recurse-submodules=no");
+                       break;
+               case RECURSE_SUBMODULES_ON_DEMAND:
+                       argv_array_push(&args, "--recurse-submodules=on-demand");
+                       break;
+               default:
+                       BUG("submodule recursion option not understood");
+               }
        if (max_children)
                argv_array_push(&args, max_children);
        if (opt_dry_run)
@@ -535,7 +553,7 @@ static int pull_into_void(const struct object_id *merge_head,
         * index/worktree changes that the user already made on the unborn
         * branch.
         */
-       if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head->hash, 0))
+       if (checkout_fast_forward(&empty_tree_oid, merge_head, 0))
                return 1;
 
        if (update_ref("initial pull", "HEAD", merge_head->hash, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR))
@@ -544,6 +562,30 @@ static int pull_into_void(const struct object_id *merge_head,
        return 0;
 }
 
+static int rebase_submodules(void)
+{
+       struct child_process cp = CHILD_PROCESS_INIT;
+
+       cp.git_cmd = 1;
+       cp.no_stdin = 1;
+       argv_array_pushl(&cp.args, "submodule", "update",
+                                  "--recursive", "--rebase", NULL);
+
+       return run_command(&cp);
+}
+
+static int update_submodules(void)
+{
+       struct child_process cp = CHILD_PROCESS_INIT;
+
+       cp.git_cmd = 1;
+       cp.no_stdin = 1;
+       argv_array_pushl(&cp.args, "submodule", "update",
+                                  "--recursive", "--checkout", NULL);
+
+       return run_command(&cp);
+}
+
 /**
  * Runs git-merge, returning its exit status.
  */
@@ -710,17 +752,20 @@ static int get_octopus_merge_base(struct object_id *merge_base,
 {
        struct commit_list *revs = NULL, *result;
 
-       commit_list_insert(lookup_commit_reference(curr_head->hash), &revs);
-       commit_list_insert(lookup_commit_reference(merge_head->hash), &revs);
+       commit_list_insert(lookup_commit_reference(curr_head), &revs);
+       commit_list_insert(lookup_commit_reference(merge_head), &revs);
        if (!is_null_oid(fork_point))
-               commit_list_insert(lookup_commit_reference(fork_point->hash), &revs);
+               commit_list_insert(lookup_commit_reference(fork_point), &revs);
 
-       result = reduce_heads(get_octopus_merge_bases(revs));
+       result = get_octopus_merge_bases(revs);
        free_commit_list(revs);
+       reduce_heads_replace(&result);
+
        if (!result)
                return 1;
 
        oidcpy(merge_base, &result->item->object.oid);
+       free_commit_list(result);
        return 0;
 }
 
@@ -789,6 +834,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
        if (!getenv("GIT_REFLOG_ACTION"))
                set_reflog_message(argc, argv);
 
+       git_config(git_pull_config, NULL);
+
        argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
 
        parse_repo_refspecs(argc, argv, &repo, &refspecs);
@@ -799,8 +846,6 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
        if (opt_rebase < 0)
                opt_rebase = config_get_rebase();
 
-       git_config(git_pull_config, NULL);
-
        if (read_cache_unmerged())
                die_resolve_conflict("pull");
 
@@ -852,7 +897,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
                        "fast-forwarding your working tree from\n"
                        "commit %s."), oid_to_hex(&orig_head));
 
-               if (checkout_fast_forward(orig_head.hash, curr_head.hash, 0))
+               if (checkout_fast_forward(&orig_head, &curr_head, 0))
                        die(_("Cannot fast-forward your working tree.\n"
                                "After making sure that you saved anything precious from\n"
                                "$ git diff %s\n"
@@ -875,21 +920,36 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
                die(_("Cannot rebase onto multiple branches."));
 
        if (opt_rebase) {
+               int ret = 0;
+               if ((recurse_submodules == RECURSE_SUBMODULES_ON ||
+                    recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) &&
+                   submodule_touches_in_range(&rebase_fork_point, &curr_head))
+                       die(_("cannot rebase with locally recorded submodule modifications"));
                if (!autostash) {
                        struct commit_list *list = NULL;
                        struct commit *merge_head, *head;
 
-                       head = lookup_commit_reference(orig_head.hash);
+                       head = lookup_commit_reference(&orig_head);
                        commit_list_insert(head, &list);
-                       merge_head = lookup_commit_reference(merge_heads.oid[0].hash);
+                       merge_head = lookup_commit_reference(&merge_heads.oid[0]);
                        if (is_descendant_of(merge_head, list)) {
                                /* we can fast-forward this without invoking rebase */
                                opt_ff = "--ff-only";
-                               return run_merge();
+                               ret = run_merge();
                        }
                }
-               return run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
+               ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
+
+               if (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON ||
+                            recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND))
+                       ret = rebase_submodules();
+
+               return ret;
        } else {
-               return run_merge();
+               int ret = run_merge();
+               if (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON ||
+                            recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND))
+                       ret = update_submodules();
+               return ret;
        }
 }