static int reset_refs(const char *rev, const unsigned char *sha1) { int update_ref_status; struct strbuf msg = STRBUF_INIT; struct strbuf err = STRBUF_INIT; unsigned char *orig = NULL, sha1_orig[20], *old_orig = NULL, sha1_old_orig[20]; if (!get_sha1("ORIG_HEAD", sha1_old_orig)) old_orig = sha1_old_orig; if (!get_sha1("HEAD", sha1_orig)) { orig = sha1_orig; set_reflog_message(&msg, "updating ORIG_HEAD", NULL); if (update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0, &err)) error("%s", err.buf); strbuf_release(&err); } else if (old_orig) delete_ref("ORIG_HEAD", old_orig, 0); set_reflog_message(&msg, "updating HEAD", rev); update_ref_status = update_ref(msg.buf, "HEAD", sha1, orig, 0, &err); if (update_ref_status) error("%s", err.buf); strbuf_release(&err); strbuf_release(&msg); return update_ref_status; }
static int reset_refs(const char *rev, const struct object_id *oid) { int update_ref_status; struct strbuf msg = STRBUF_INIT; struct object_id *orig = NULL, oid_orig, *old_orig = NULL, oid_old_orig; if (!get_oid("ORIG_HEAD", &oid_old_orig)) old_orig = &oid_old_orig; if (!get_oid("HEAD", &oid_orig)) { orig = &oid_orig; set_reflog_message(&msg, "updating ORIG_HEAD", NULL); update_ref_oid(msg.buf, "ORIG_HEAD", orig, old_orig, 0, UPDATE_REFS_MSG_ON_ERR); } else if (old_orig) delete_ref("ORIG_HEAD", old_orig->hash, 0); set_reflog_message(&msg, "updating HEAD", rev); update_ref_status = update_ref_oid(msg.buf, "HEAD", oid, orig, 0, UPDATE_REFS_MSG_ON_ERR); strbuf_release(&msg); return update_ref_status; }
int cmd_pull(int argc, const char **argv, const char *prefix) { const char *repo, **refspecs; 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); if (!opt_ff) opt_ff = xstrdup_or_null(config_get_ff()); if (opt_rebase < 0) opt_rebase = config_get_rebase(); if (read_cache_unmerged()) die_resolve_conflict("pull"); if (file_exists(git_path_merge_head(the_repository))) die_conclude_merge(); 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) { if (opt_autostash != -1) autostash = opt_autostash; if (is_null_oid(&orig_head) && !is_cache_unborn()) die(_("Updating an unborn branch with changes added to the index.")); if (!autostash) 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)) oidclr(&rebase_fork_point); } if (run_fetch(repo, refspecs)) return 1; if (opt_dry_run) return 0; if (get_oid("HEAD", &curr_head)) oidclr(&curr_head); if (!is_null_oid(&orig_head) && !is_null_oid(&curr_head) && !oideq(&orig_head, &curr_head)) { /* * The fetch involved updating the current branch. * * The working tree and the index file are still based on * orig_head commit, but we are merging into curr_head. * Update the working tree to match curr_head. */ warning(_("fetch updated the current branch head.\n" "fast-forwarding your working tree from\n" "commit %s."), oid_to_hex(&orig_head)); 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."), oid_to_hex(&orig_head)); } get_merge_heads(&merge_heads); if (!merge_heads.nr) die_no_merge_candidates(repo, refspecs); 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.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(the_repository, &orig_head); commit_list_insert(head, &list); merge_head = lookup_commit_reference(the_repository, &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; } }
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]; if (!getenv("GIT_REFLOG_ACTION")) set_reflog_message(argc, argv); argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0); parse_repo_refspecs(argc, argv, &repo, &refspecs); if (!opt_ff) opt_ff = xstrdup_or_null(config_get_ff()); 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"))) die_conclude_merge(); if (get_sha1("HEAD", orig_head)) hashclr(orig_head); if (!opt_rebase && opt_autostash != -1) die(_("--[no-]autostash option is only valid with --rebase.")); if (opt_rebase) { int autostash = config_autostash; if (opt_autostash != -1) autostash = opt_autostash; if (is_null_sha1(orig_head) && !is_cache_unborn()) die(_("Updating an unborn branch with changes added to the index.")); if (!autostash) die_on_unclean_work_tree(prefix); if (get_rebase_fork_point(rebase_fork_point, repo, *refspecs)) hashclr(rebase_fork_point); } if (run_fetch(repo, refspecs)) return 1; if (opt_dry_run) return 0; if (get_sha1("HEAD", curr_head)) hashclr(curr_head); if (!is_null_sha1(orig_head) && !is_null_sha1(curr_head) && hashcmp(orig_head, curr_head)) { /* * The fetch involved updating the current branch. * * The working tree and the index file are still based on * orig_head commit, but we are merging into curr_head. * Update the working tree to match curr_head. */ warning(_("fetch updated the current branch head.\n" "fast-forwarding your working tree from\n" "commit %s."), sha1_to_hex(orig_head)); 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)); } get_merge_heads(&merge_heads); if (!merge_heads.nr) die_no_merge_candidates(repo, refspecs); if (is_null_sha1(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(); }
int cmd_reset(int argc, const char **argv, const char *prefix) { int i = 0, reset_type = NONE, update_ref_status = 0, quiet = 0; int patch_mode = 0; const char *rev = "HEAD"; unsigned char sha1[20], *orig = NULL, sha1_orig[20], *old_orig = NULL, sha1_old_orig[20]; struct commit *commit; struct strbuf msg = STRBUF_INIT; const struct option options[] = { OPT__QUIET(&quiet, "be quiet, only report errors"), OPT_SET_INT(0, "mixed", &reset_type, "reset HEAD and index", MIXED), OPT_SET_INT(0, "soft", &reset_type, "reset only HEAD", SOFT), OPT_SET_INT(0, "hard", &reset_type, "reset HEAD, index and working tree", HARD), OPT_SET_INT(0, "merge", &reset_type, "reset HEAD, index and working tree", MERGE), OPT_SET_INT(0, "keep", &reset_type, "reset HEAD but keep local changes", KEEP), OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"), OPT_END() }; git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, options, git_reset_usage, PARSE_OPT_KEEP_DASHDASH); /* * Possible arguments are: * * git reset [-opts] <rev> <paths>... * git reset [-opts] <rev> -- <paths>... * git reset [-opts] -- <paths>... * git reset [-opts] <paths>... * * At this point, argv[i] points immediately after [-opts]. */ if (i < argc) { if (!strcmp(argv[i], "--")) { i++; /* reset to HEAD, possibly with paths */ } else if (i + 1 < argc && !strcmp(argv[i+1], "--")) { rev = argv[i]; i += 2; } /* * Otherwise, argv[i] could be either <rev> or <paths> and * has to be unambiguous. */ else if (!get_sha1(argv[i], sha1)) { /* * Ok, argv[i] looks like a rev; it should not * be a filename. */ verify_non_filename(prefix, argv[i]); rev = argv[i++]; } else { /* Otherwise we treat this as a filename */ verify_filename(prefix, argv[i]); } } if (get_sha1(rev, sha1)) die(_("Failed to resolve '%s' as a valid ref."), rev); commit = lookup_commit_reference(sha1); if (!commit) die(_("Could not parse object '%s'."), rev); hashcpy(sha1, commit->object.sha1); if (patch_mode) { if (reset_type != NONE) die(_("--patch is incompatible with --{hard,mixed,soft}")); return interactive_reset(rev, argv + i, prefix); } /* git reset tree [--] paths... can be used to * load chosen paths from the tree into the index without * affecting the working tree nor HEAD. */ if (i < argc) { if (reset_type == MIXED) warning(_("--mixed with paths is deprecated; use 'git reset -- <paths>' instead.")); else if (reset_type != NONE) die(_("Cannot do %s reset with paths."), _(reset_type_names[reset_type])); return read_from_tree(prefix, argv + i, sha1, quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN); } if (reset_type == NONE) reset_type = MIXED; /* by default */ if (reset_type != SOFT && reset_type != MIXED) setup_work_tree(); if (reset_type == MIXED && is_bare_repository()) die(_("%s reset is not allowed in a bare repository"), _(reset_type_names[reset_type])); /* Soft reset does not touch the index file nor the working tree * at all, but requires them in a good order. Other resets reset * the index file to the tree object we are switching to. */ if (reset_type == SOFT) die_if_unmerged_cache(reset_type); else { int err; if (reset_type == KEEP) die_if_unmerged_cache(reset_type); err = reset_index_file(sha1, reset_type, quiet); if (reset_type == KEEP) err = err || reset_index_file(sha1, MIXED, quiet); if (err) die(_("Could not reset index file to revision '%s'."), rev); } /* Any resets update HEAD to the head being switched to, * saving the previous head in ORIG_HEAD before. */ if (!get_sha1("ORIG_HEAD", sha1_old_orig)) old_orig = sha1_old_orig; if (!get_sha1("HEAD", sha1_orig)) { orig = sha1_orig; set_reflog_message(&msg, "updating ORIG_HEAD", NULL); update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0, MSG_ON_ERR); } else if (old_orig) delete_ref("ORIG_HEAD", old_orig, 0); set_reflog_message(&msg, "updating HEAD", rev); update_ref_status = update_ref(msg.buf, "HEAD", sha1, orig, 0, MSG_ON_ERR); switch (reset_type) { case HARD: if (!update_ref_status && !quiet) print_new_head_line(commit); break; case SOFT: /* Nothing else to do. */ break; case MIXED: /* Report what has not been updated. */ update_index_refresh(0, NULL, quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN); break; } remove_branch_state(); strbuf_release(&msg); return update_ref_status; }