diff options
Diffstat (limited to 'builtin/pull.c')
-rw-r--r-- | builtin/pull.c | 298 |
1 files changed, 165 insertions, 133 deletions
diff --git a/builtin/pull.c b/builtin/pull.c index 398aae16c0..1876271af9 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -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,8 +16,11 @@ #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" enum rebase_type { REBASE_INVALID = -1, @@ -35,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; @@ -76,11 +80,13 @@ 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; static char *opt_diffstat; static char *opt_log; +static char *opt_signoff; static char *opt_squash; static char *opt_commit; static char *opt_edit; @@ -100,7 +106,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; @@ -108,6 +113,8 @@ static char *opt_depth; static char *opt_unshallow; static char *opt_update_shallow; static char *opt_refmap; +static char *opt_ipv4; +static char *opt_ipv6; static struct option pull_options[] = { /* Shared options */ @@ -115,6 +122,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")), @@ -134,6 +145,9 @@ static struct option pull_options[] = { OPT_PASSTHRU(0, "log", &opt_log, N_("n"), N_("add (at most <n>) entries from shortlog to merge commit message"), PARSE_OPT_OPTARG), + OPT_PASSTHRU(0, "signoff", &opt_signoff, NULL, + N_("add Signed-off-by:"), + PARSE_OPT_OPTARG), OPT_PASSTHRU(0, "squash", &opt_squash, NULL, N_("create a single commit instead of doing a merge"), PARSE_OPT_NOARG), @@ -186,10 +200,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), @@ -210,6 +220,12 @@ static struct option pull_options[] = { OPT_PASSTHRU(0, "refmap", &opt_refmap, N_("refmap"), N_("specify fetch refmap"), PARSE_OPT_NONEG), + OPT_PASSTHRU('4', "ipv4", &opt_ipv4, NULL, + N_("use IPv4 addresses only"), + PARSE_OPT_NOARG), + OPT_PASSTHRU('6', "ipv6", &opt_ipv6, NULL, + N_("use IPv6 addresses only"), + PARSE_OPT_NOARG), OPT_END() }; @@ -270,7 +286,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: @@ -321,96 +337,32 @@ 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; - } - return git_default_config(var, value, cb); -} - -/** - * Returns 1 if there are unstaged changes, 0 otherwise. - */ -static int has_unstaged_changes(const char *prefix) -{ - struct rev_info rev_info; - int result; - - init_revisions(&rev_info, prefix); - DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES); - DIFF_OPT_SET(&rev_info.diffopt, QUICK); - diff_setup_done(&rev_info.diffopt); - result = run_diff_files(&rev_info, 0); - return diff_result_code(&rev_info.diffopt, result); -} - -/** - * Returns 1 if there are uncommitted changes, 0 otherwise. - */ -static int has_uncommitted_changes(const char *prefix) -{ - struct rev_info rev_info; - int result; - - if (is_cache_unborn()) + } else if (!strcmp(var, "submodule.recurse")) { + recurse_submodules = git_config_bool(var, value) ? + RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF; return 0; - - init_revisions(&rev_info, prefix); - DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES); - DIFF_OPT_SET(&rev_info.diffopt, QUICK); - add_head_to_pending(&rev_info); - diff_setup_done(&rev_info.diffopt); - result = run_diff_index(&rev_info, 1); - return diff_result_code(&rev_info.diffopt, result); -} - -/** - * If the work tree has unstaged or uncommitted changes, dies with the - * appropriate message. - */ -static void die_on_unclean_work_tree(const char *prefix) -{ - struct lock_file *lock_file = xcalloc(1, sizeof(*lock_file)); - int do_die = 0; - - hold_locked_index(lock_file, 0); - refresh_cache(REFRESH_QUIET); - update_index_if_able(&the_index, lock_file); - rollback_lock_file(lock_file); - - if (has_unstaged_changes(prefix)) { - error(_("Cannot pull with rebase: You have unstaged changes.")); - do_die = 1; } - - if (has_uncommitted_changes(prefix)) { - if (do_die) - error(_("Additionally, your index contains uncommitted changes.")); - else - error(_("Cannot pull with rebase: Your index contains uncommitted changes.")); - do_die = 1; - } - - if (do_die) - exit(1); + return git_default_config(var, value, cb); } /** * Appends merge candidates from FETCH_HEAD that are not marked not-for-merge * into merge_heads. */ -static void get_merge_heads(struct sha1_array *merge_heads) +static void get_merge_heads(struct oid_array *merge_heads) { - const char *filename = git_path("FETCH_HEAD"); + const char *filename = git_path_fetch_head(); FILE *fp; struct strbuf sb = STRBUF_INIT; - unsigned char sha1[GIT_SHA1_RAWSZ]; + 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_sha1_hex(sb.buf, sha1)) + if (get_oid_hex(sb.buf, &oid)) continue; /* invalid line: does not start with SHA1 */ if (starts_with(sb.buf + GIT_SHA1_HEXSZ, "\tnot-for-merge\t")) continue; /* ref is not-for-merge */ - sha1_array_append(merge_heads, sha1); + oid_array_append(merge_heads, &oid); } fclose(fp); strbuf_release(&sb); @@ -550,8 +502,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) @@ -566,6 +530,10 @@ static int run_fetch(const char *repo, const char **refspecs) argv_array_push(&args, opt_update_shallow); if (opt_refmap) argv_array_push(&args, opt_refmap); + if (opt_ipv4) + argv_array_push(&args, opt_ipv4); + if (opt_ipv6) + argv_array_push(&args, opt_ipv6); if (repo) { argv_array_push(&args, repo); @@ -580,8 +548,8 @@ static int run_fetch(const char *repo, const char **refspecs) /** * "Pulls into void" by branching off merge_head. */ -static int pull_into_void(const unsigned char *merge_head, - const unsigned char *curr_head) +static int pull_into_void(const struct object_id *merge_head, + const struct object_id *curr_head) { /* * Two-way merge: we treat the index as based on an empty tree, @@ -589,7 +557,7 @@ static int pull_into_void(const unsigned char *merge_head, * index/worktree changes that the user already made on the unborn * branch. */ - if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head, 0)) + if (checkout_fast_forward(the_hash_algo->empty_tree, merge_head, 0)) return 1; if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR)) @@ -598,6 +566,32 @@ static int pull_into_void(const unsigned char *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); + argv_push_verbosity(&cp.args); + + 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); + argv_push_verbosity(&cp.args); + + return run_command(&cp); +} + /** * Runs git-merge, returning its exit status. */ @@ -618,6 +612,8 @@ static int run_merge(void) argv_array_push(&args, opt_diffstat); if (opt_log) argv_array_push(&args, opt_log); + if (opt_signoff) + argv_array_push(&args, opt_signoff); if (opt_squash) argv_array_push(&args, opt_squash); if (opt_commit) @@ -713,7 +709,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec) * current branch forked from its remote tracking branch. Returns 0 on success, * -1 on failure. */ -static int get_rebase_fork_point(unsigned char *fork_point, const char *repo, +static int get_rebase_fork_point(struct object_id *fork_point, const char *repo, const char *refspec) { int ret; @@ -744,7 +740,7 @@ static int get_rebase_fork_point(unsigned char *fork_point, const char *repo, if (ret) goto cleanup; - ret = get_sha1_hex(sb.buf, fork_point); + ret = get_oid_hex(sb.buf, fork_point); if (ret) goto cleanup; @@ -757,24 +753,27 @@ cleanup: * Sets merge_base to the octopus merge base of curr_head, merge_head and * fork_point. Returns 0 if a merge base is found, 1 otherwise. */ -static int get_octopus_merge_base(unsigned char *merge_base, - const unsigned char *curr_head, - const unsigned char *merge_head, - const unsigned char *fork_point) +static int get_octopus_merge_base(struct object_id *merge_base, + const struct object_id *curr_head, + const struct object_id *merge_head, + const struct object_id *fork_point) { struct commit_list *revs = NULL, *result; commit_list_insert(lookup_commit_reference(curr_head), &revs); commit_list_insert(lookup_commit_reference(merge_head), &revs); - if (!is_null_sha1(fork_point)) + if (!is_null_oid(fork_point)) 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; - hashcpy(merge_base, result->item->object.oid.hash); + oidcpy(merge_base, &result->item->object.oid); + free_commit_list(result); return 0; } @@ -783,16 +782,16 @@ static int get_octopus_merge_base(unsigned char *merge_base, * fork point calculated by get_rebase_fork_point(), runs git-rebase with the * appropriate arguments and returns its exit status. */ -static int run_rebase(const unsigned char *curr_head, - const unsigned char *merge_head, - const unsigned char *fork_point) +static int run_rebase(const struct object_id *curr_head, + const struct object_id *merge_head, + const struct object_id *fork_point) { int ret; - unsigned char oct_merge_base[GIT_SHA1_RAWSZ]; + struct object_id oct_merge_base; struct argv_array args = ARGV_ARRAY_INIT; - if (!get_octopus_merge_base(oct_merge_base, curr_head, merge_head, fork_point)) - if (!is_null_sha1(fork_point) && !hashcmp(oct_merge_base, fork_point)) + if (!get_octopus_merge_base(&oct_merge_base, curr_head, merge_head, fork_point)) + if (!is_null_oid(fork_point) && !oidcmp(&oct_merge_base, fork_point)) fork_point = NULL; argv_array_push(&args, "rebase"); @@ -820,12 +819,12 @@ static int run_rebase(const unsigned char *curr_head, warning(_("ignoring --verify-signatures for rebase")); argv_array_push(&args, "--onto"); - argv_array_push(&args, sha1_to_hex(merge_head)); + argv_array_push(&args, oid_to_hex(merge_head)); - if (fork_point && !is_null_sha1(fork_point)) - argv_array_push(&args, sha1_to_hex(fork_point)); + if (fork_point && !is_null_oid(fork_point)) + argv_array_push(&args, oid_to_hex(fork_point)); else - argv_array_push(&args, sha1_to_hex(merge_head)); + argv_array_push(&args, oid_to_hex(merge_head)); ret = run_command_v_opt(args.argv, RUN_GIT_CMD); argv_array_clear(&args); @@ -835,13 +834,16 @@ static int run_rebase(const unsigned char *curr_head, int cmd_pull(int argc, const char **argv, const char *prefix) { const char *repo, **refspecs; - struct sha1_array merge_heads = SHA1_ARRAY_INIT; - unsigned char orig_head[GIT_SHA1_RAWSZ], curr_head[GIT_SHA1_RAWSZ]; - unsigned char rebase_fork_point[GIT_SHA1_RAWSZ]; + struct oid_array merge_heads = OID_ARRAY_INIT; + struct object_id orig_head, curr_head; + struct object_id rebase_fork_point; + int autostash; 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); @@ -852,33 +854,32 @@ 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"); - if (file_exists(git_path("MERGE_HEAD"))) + if (file_exists(git_path_merge_head())) die_conclude_merge(); - if (get_sha1("HEAD", orig_head)) - hashclr(orig_head); + if (get_oid("HEAD", &orig_head)) + oidclr(&orig_head); if (!opt_rebase && opt_autostash != -1) die(_("--[no-]autostash option is only valid with --rebase.")); + autostash = config_autostash; if (opt_rebase) { - int autostash = config_autostash; if (opt_autostash != -1) autostash = opt_autostash; - if (is_null_sha1(orig_head) && !is_cache_unborn()) + if (is_null_oid(&orig_head) && !is_cache_unborn()) die(_("Updating an unborn branch with changes added to the index.")); if (!autostash) - die_on_unclean_work_tree(prefix); + require_clean_work_tree(N_("pull with rebase"), + _("please commit or stash them."), 1, 0); - if (get_rebase_fork_point(rebase_fork_point, repo, *refspecs)) - hashclr(rebase_fork_point); + if (get_rebase_fork_point(&rebase_fork_point, repo, *refspecs)) + oidclr(&rebase_fork_point); } if (run_fetch(repo, refspecs)) @@ -887,11 +888,11 @@ int cmd_pull(int argc, const char **argv, const char *prefix) if (opt_dry_run) return 0; - if (get_sha1("HEAD", curr_head)) - hashclr(curr_head); + if (get_oid("HEAD", &curr_head)) + oidclr(&curr_head); - if (!is_null_sha1(orig_head) && !is_null_sha1(curr_head) && - hashcmp(orig_head, curr_head)) { + if (!is_null_oid(&orig_head) && !is_null_oid(&curr_head) && + oidcmp(&orig_head, &curr_head)) { /* * The fetch involved updating the current branch. * @@ -902,15 +903,15 @@ int cmd_pull(int argc, const char **argv, const char *prefix) warning(_("fetch updated the current branch head.\n" "fast-forwarding your working tree from\n" - "commit %s."), sha1_to_hex(orig_head)); + "commit %s."), oid_to_hex(&orig_head)); - if (checkout_fast_forward(orig_head, curr_head, 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" "output, run\n" "$ git reset --hard\n" - "to recover."), sha1_to_hex(orig_head)); + "to recover."), oid_to_hex(&orig_head)); } get_merge_heads(&merge_heads); @@ -918,14 +919,45 @@ int cmd_pull(int argc, const char **argv, const char *prefix) if (!merge_heads.nr) die_no_merge_candidates(repo, refspecs); - if (is_null_sha1(orig_head)) { + if (is_null_oid(&orig_head)) { if (merge_heads.nr > 1) die(_("Cannot merge multiple branches into empty head.")); - return pull_into_void(*merge_heads.sha1, curr_head); - } else if (opt_rebase) { - if (merge_heads.nr > 1) - die(_("Cannot rebase onto multiple branches.")); - return run_rebase(curr_head, *merge_heads.sha1, rebase_fork_point); - } else - return run_merge(); + return pull_into_void(merge_heads.oid, &curr_head); + } + if (opt_rebase && merge_heads.nr > 1) + 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); + commit_list_insert(head, &list); + 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"; + ret = run_merge(); + } + } + 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 { + int ret = run_merge(); + if (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON || + recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)) + ret = update_submodules(); + return ret; + } } |