static struct commit *is_old_style_invocation(int argc, const char **argv, const unsigned char *head) { struct commit *second_token = NULL; if (argc > 2) { unsigned char second_sha1[20]; if (get_sha1(argv[1], second_sha1)) return NULL; second_token = lookup_commit_reference_gently(second_sha1, 0); if (!second_token) die(_("'%s' is not a commit"), argv[1]); if (hashcmp(second_token->object.oid.hash, head)) return NULL; } return second_token; }
static void show_detached(struct ref_list *ref_list) { struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1); if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) { struct ref_item item; item.name = xstrdup(_("(no branch)")); item.len = strlen(item.name); item.kind = REF_LOCAL_BRANCH; item.dest = NULL; item.commit = head_commit; if (item.len > ref_list->maxwidth) ref_list->maxwidth = item.len; print_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, ""); free(item.name); } }
static void show_detached(struct ref_list *ref_list) { struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1); if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) { struct ref_item item; item.name = get_head_description(); item.width = utf8_strwidth(item.name); item.kind = REF_LOCAL_BRANCH; item.dest = NULL; item.commit = head_commit; item.ignore = 0; if (item.width > ref_list->maxwidth) ref_list->maxwidth = item.width; print_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, ""); free(item.name); } }
static void print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit) { int i; struct ref_list ref_list; memset(&ref_list, 0, sizeof(ref_list)); ref_list.kinds = kinds; ref_list.verbose = verbose; ref_list.abbrev = abbrev; ref_list.with_commit = with_commit; if (merge_filter != NO_FILTER) init_revisions(&ref_list.revs, NULL); for_each_rawref(append_ref, &ref_list); if (merge_filter != NO_FILTER) { struct commit *filter; filter = lookup_commit_reference_gently(merge_filter_ref, 0); filter->object.flags |= UNINTERESTING; add_pending_object(&ref_list.revs, (struct object *) filter, ""); ref_list.revs.limited = 1; prepare_revision_walk(&ref_list.revs); if (verbose) ref_list.maxwidth = calc_maxwidth(&ref_list); } qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp); detached = (detached && (kinds & REF_LOCAL_BRANCH)); if (detached) show_detached(&ref_list); for (i = 0; i < ref_list.index; i++) { int current = !detached && (ref_list.list[i].kind == REF_LOCAL_BRANCH) && !strcmp(ref_list.list[i].name, head); char *prefix = (kinds != REF_REMOTE_BRANCH && ref_list.list[i].kind == REF_REMOTE_BRANCH) ? "remotes/" : ""; print_ref_item(&ref_list.list[i], ref_list.maxwidth, verbose, abbrev, current, prefix); } free_ref_list(&ref_list); }
int sequencer_pick_revisions(struct replay_opts *opts) { struct commit_list *todo_list = NULL; unsigned char sha1[20]; int i; if (opts->subcommand == REPLAY_NONE) assert(opts->revs); read_and_refresh_cache(opts); /* * Decide what to do depending on the arguments; a fresh * cherry-pick should be handled differently from an existing * one that is being continued */ if (opts->subcommand == REPLAY_REMOVE_STATE) { remove_sequencer_state(); return 0; } if (opts->subcommand == REPLAY_ROLLBACK) return sequencer_rollback(opts); if (opts->subcommand == REPLAY_CONTINUE) return sequencer_continue(opts, 0); if (opts->subcommand == REPLAY_SKIP) return sequencer_skip(opts); for (i = 0; i < opts->revs->pending.nr; i++) { unsigned char sha1[20]; const char *name = opts->revs->pending.objects[i].name; /* This happens when using --stdin. */ if (!strlen(name)) continue; if (!get_sha1(name, sha1)) { if (!lookup_commit_reference_gently(sha1, 1)) { enum object_type type = sha1_object_info(sha1, NULL); die(_("%s: can't cherry-pick a %s"), name, typename(type)); } } else die(_("%s: bad revision"), name); }
static void parse_treeish_arg(const char **argv, struct archiver_args *ar_args, const char *prefix) { const char *name = argv[0]; const unsigned char *commit_sha1; time_t archive_time; struct tree *tree; const struct commit *commit; unsigned char sha1[20]; if (get_sha1(name, sha1)) die("Not a valid object name"); commit = lookup_commit_reference_gently(sha1, 1); if (commit) { commit_sha1 = commit->object.sha1; archive_time = commit->date; } else { commit_sha1 = NULL; archive_time = time(NULL); } tree = parse_tree_indirect(sha1); if (tree == NULL) die("not a tree object"); if (prefix) { unsigned char tree_sha1[20]; unsigned int mode; int err; err = get_tree_entry(tree->object.sha1, prefix, tree_sha1, &mode); if (err || !S_ISDIR(mode)) die("current working directory is untracked"); tree = parse_tree_indirect(tree_sha1); } ar_args->tree = tree; ar_args->commit_sha1 = commit_sha1; ar_args->commit = commit; ar_args->time = archive_time; }
static int switch_branches(const struct checkout_opts *opts, struct branch_info *new_branch_info) { int ret = 0; struct branch_info old_branch_info; void *path_to_free; struct object_id rev; int flag, writeout_error = 0; memset(&old_branch_info, 0, sizeof(old_branch_info)); old_branch_info.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag); if (old_branch_info.path) old_branch_info.commit = lookup_commit_reference_gently(&rev, 1); if (!(flag & REF_ISSYMREF)) old_branch_info.path = NULL; if (old_branch_info.path) skip_prefix(old_branch_info.path, "refs/heads/", &old_branch_info.name); if (!new_branch_info->name) { new_branch_info->name = "HEAD"; new_branch_info->commit = old_branch_info.commit; if (!new_branch_info->commit) die(_("You are on a branch yet to be born")); parse_commit_or_die(new_branch_info->commit); } ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error); if (ret) { free(path_to_free); return ret; } if (!opts->quiet && !old_branch_info.path && old_branch_info.commit && new_branch_info->commit != old_branch_info.commit) orphaned_commit_warning(old_branch_info.commit, new_branch_info->commit); update_refs_for_switch(opts, &old_branch_info, new_branch_info); ret = post_checkout_hook(old_branch_info.commit, new_branch_info->commit, 1); free(path_to_free); return ret || writeout_error; }
static int keep_entry(struct commit **it, struct object_id *oid) { struct commit *commit; if (is_null_oid(oid)) return 1; commit = lookup_commit_reference_gently(the_repository, oid, 1); if (!commit) return 0; /* * Make sure everything in this commit exists. * * We have walked all the objects reachable from the refs * and cache earlier. The commits reachable by this commit * must meet SEEN commits -- and then we should mark them as * SEEN as well. */ if (!commit_is_complete(commit)) return 0; *it = commit; return 1; }
static void reflog_expiry_prepare(const char *refname, const struct object_id *oid, void *cb_data) { struct expire_reflog_policy_cb *cb = cb_data; if (!cb->cmd.expire_unreachable || is_head(refname)) { cb->tip_commit = NULL; cb->unreachable_expire_kind = UE_HEAD; } else { cb->tip_commit = lookup_commit_reference_gently(the_repository, oid, 1); if (!cb->tip_commit) cb->unreachable_expire_kind = UE_ALWAYS; else cb->unreachable_expire_kind = UE_NORMAL; } if (cb->cmd.expire_unreachable <= cb->cmd.expire_total) cb->unreachable_expire_kind = UE_ALWAYS; cb->mark_list = NULL; cb->tips = NULL; if (cb->unreachable_expire_kind != UE_ALWAYS) { if (cb->unreachable_expire_kind == UE_HEAD) { struct commit_list *elem; for_each_ref(push_tip_to_list, &cb->tips); for (elem = cb->tips; elem; elem = elem->next) commit_list_insert(elem->item, &cb->mark_list); } else { commit_list_insert(cb->tip_commit, &cb->mark_list); } cb->mark_limit = cb->cmd.expire_total; mark_reachable(cb); } }
static void wt_status_get_detached_from(struct wt_status_state *state) { struct grab_1st_switch_cbdata cb; struct commit *commit; unsigned char sha1[20]; char *ref = NULL; strbuf_init(&cb.buf, 0); if (for_each_reflog_ent_reverse("HEAD", grab_1st_switch, &cb) <= 0) { strbuf_release(&cb.buf); return; } if (dwim_ref(cb.buf.buf, cb.buf.len, sha1, &ref) == 1 && /* sha1 is a commit? match without further lookup */ (!hashcmp(cb.nsha1, sha1) || /* perhaps sha1 is a tag, try to dereference to a commit */ ((commit = lookup_commit_reference_gently(sha1, 1)) != NULL && !hashcmp(cb.nsha1, commit->object.sha1)))) { int ofs; if (starts_with(ref, "refs/tags/")) ofs = strlen("refs/tags/"); else if (starts_with(ref, "refs/remotes/")) ofs = strlen("refs/remotes/"); else ofs = 0; state->detached_from = xstrdup(ref + ofs); } else state->detached_from = xstrdup(find_unique_abbrev(cb.nsha1, DEFAULT_ABBREV)); hashcpy(state->detached_sha1, cb.nsha1); state->detached_at = !get_sha1("HEAD", sha1) && !hashcmp(sha1, state->detached_sha1); free(ref); strbuf_release(&cb.buf); }
static int notes_cache_match_validity(const char *ref, const char *validity) { struct object_id oid; struct commit *commit; struct pretty_print_context pretty_ctx; struct strbuf msg = STRBUF_INIT; int ret; if (read_ref(ref, &oid) < 0) return 0; commit = lookup_commit_reference_gently(&oid, 1); if (!commit) return 0; memset(&pretty_ctx, 0, sizeof(pretty_ctx)); format_commit_message(commit, "%s", &msg, &pretty_ctx); strbuf_trim(&msg); ret = !strcmp(msg.buf, validity); strbuf_release(&msg); return ret; }
static struct commit *dwim_reverse_initial(struct rev_info *revs, const char **name_p) { /* * DWIM "git blame --reverse ONE -- PATH" as * "git blame --reverse ONE..HEAD -- PATH" but only do so * when it makes sense. */ struct object *obj; struct commit *head_commit; struct object_id head_oid; if (revs->pending.nr != 1) return NULL; /* Is that sole rev a committish? */ obj = revs->pending.objects[0].item; obj = deref_tag(obj, NULL, 0); if (obj->type != OBJ_COMMIT) return NULL; /* Do we have HEAD? */ if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL)) return NULL; head_commit = lookup_commit_reference_gently(&head_oid, 1); if (!head_commit) return NULL; /* Turn "ONE" into "ONE..HEAD" then */ obj->flags |= UNINTERESTING; add_pending_object(revs, &head_commit->object, "HEAD"); if (name_p) *name_p = revs->pending.objects[0].name; return (struct commit *)obj; }
static int append_ref(const char *refname, const unsigned char *sha1, int allow_dups) { struct commit *commit = lookup_commit_reference_gently(sha1, 1); int i; if (!commit) return 0; if (!allow_dups) { /* Avoid adding the same thing twice */ for (i = 0; i < ref_name_cnt; i++) if (!strcmp(refname, ref_name[i])) return 0; } if (MAX_REVS <= ref_name_cnt) { warning("ignoring %s; cannot handle more than %d refs", refname, MAX_REVS); return 0; } ref_name[ref_name_cnt++] = xstrdup(refname); ref_name[ref_name_cnt] = NULL; return 0; }
static int store_updated_refs(const char *url, struct ref *ref_map) { FILE *fp; struct commit *commit; int url_len, i, note_len, shown_url = 0; char note[1024]; const char *what, *kind; struct ref *rm; char *filename = git_path("FETCH_HEAD"); fp = fopen(filename, "a"); if (!fp) return error("cannot open %s: %s\n", filename, strerror(errno)); for (rm = ref_map; rm; rm = rm->next) { struct ref *ref = NULL; if (rm->peer_ref) { ref = xcalloc(1, sizeof(*ref) + strlen(rm->peer_ref->name) + 1); strcpy(ref->name, rm->peer_ref->name); hashcpy(ref->old_sha1, rm->peer_ref->old_sha1); hashcpy(ref->new_sha1, rm->old_sha1); ref->force = rm->peer_ref->force; } commit = lookup_commit_reference_gently(rm->old_sha1, 1); if (!commit) rm->merge = 0; if (!strcmp(rm->name, "HEAD")) { kind = ""; what = ""; } else if (!prefixcmp(rm->name, "refs/heads/")) { kind = "branch"; what = rm->name + 11; } else if (!prefixcmp(rm->name, "refs/tags/")) { kind = "tag"; what = rm->name + 10; } else if (!prefixcmp(rm->name, "refs/remotes/")) { kind = "remote branch"; what = rm->name + 13; } else { kind = ""; what = rm->name; } url_len = strlen(url); for (i = url_len - 1; url[i] == '/' && 0 <= i; i--) ; url_len = i + 1; if (4 < i && !strncmp(".git", url + i - 3, 4)) url_len = i - 3; note_len = 0; if (*what) { if (*kind) note_len += sprintf(note + note_len, "%s ", kind); note_len += sprintf(note + note_len, "'%s' of ", what); } note_len += sprintf(note + note_len, "%.*s", url_len, url); fprintf(fp, "%s\t%s\t%s\n", sha1_to_hex(commit ? commit->object.sha1 : rm->old_sha1), rm->merge ? "" : "not-for-merge", note); if (ref) update_local_ref(ref, what, verbose, note); else sprintf(note, "* %-*s %-*s -> FETCH_HEAD", SUMMARY_WIDTH, *kind ? kind : "branch", REFCOL_WIDTH, *what ? what : "HEAD"); if (*note) { if (!shown_url) { fprintf(stderr, "From %.*s\n", url_len, url); shown_url = 1; } fprintf(stderr, " %s\n", note); } } fclose(fp); return 0; }
static int print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit, const char **pattern) { int i; struct append_ref_cb cb; struct ref_list ref_list; memset(&ref_list, 0, sizeof(ref_list)); ref_list.kinds = kinds; ref_list.verbose = verbose; ref_list.abbrev = abbrev; ref_list.with_commit = with_commit; if (merge_filter != NO_FILTER) init_revisions(&ref_list.revs, NULL); cb.ref_list = &ref_list; cb.pattern = pattern; cb.ret = 0; for_each_rawref(append_ref, &cb); if (merge_filter != NO_FILTER) { struct commit *filter; filter = lookup_commit_reference_gently(merge_filter_ref, 0); if (!filter) die(_("object '%s' does not point to a commit"), sha1_to_hex(merge_filter_ref)); filter->object.flags |= UNINTERESTING; add_pending_object(&ref_list.revs, (struct object *) filter, ""); ref_list.revs.limited = 1; if (prepare_revision_walk(&ref_list.revs)) die(_("revision walk setup failed")); for (i = 0; i < ref_list.index; i++) { struct ref_item *item = &ref_list.list[i]; struct commit *commit = item->commit; int is_merged = !!(commit->object.flags & UNINTERESTING); item->ignore = is_merged != (merge_filter == SHOW_MERGED); } for (i = 0; i < ref_list.index; i++) { struct ref_item *item = &ref_list.list[i]; clear_commit_marks(item->commit, ALL_REV_FLAGS); } clear_commit_marks(filter, ALL_REV_FLAGS); if (verbose) ref_list.maxwidth = calc_maxwidth(&ref_list); } qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp); detached = (detached && (kinds & REF_LOCAL_BRANCH)); if (detached && match_patterns(pattern, "HEAD")) show_detached(&ref_list); for (i = 0; i < ref_list.index; i++) { int current = !detached && (ref_list.list[i].kind == REF_LOCAL_BRANCH) && !strcmp(ref_list.list[i].name, head); char *prefix = (kinds != REF_REMOTE_BRANCH && ref_list.list[i].kind == REF_REMOTE_BRANCH) ? "remotes/" : ""; print_ref_item(&ref_list.list[i], ref_list.maxwidth, verbose, abbrev, current, prefix); } free_ref_list(&ref_list); if (cb.ret) error(_("some refs could not be read")); return cb.ret; }
static void describe(const char *arg, int last_one) { unsigned char sha1[20]; struct commit *cmit, *gave_up_on = NULL; struct commit_list *list; struct commit_name *n; struct possible_tag all_matches[MAX_TAGS]; unsigned int match_cnt = 0, annotated_cnt = 0, cur_match; unsigned long seen_commits = 0; unsigned int unannotated_cnt = 0; if (get_sha1(arg, sha1)) die(_("Not a valid object name %s"), arg); cmit = lookup_commit_reference(sha1); if (!cmit) die(_("%s is not a valid '%s' object"), arg, commit_type); n = find_commit_name(cmit->object.oid.hash); if (n && (tags || all || n->prio == 2)) { /* * Exact match to an existing ref. */ display_name(n); if (longformat) show_suffix(0, n->tag ? n->tag->tagged->oid.hash : sha1); if (dirty) printf("%s", dirty); printf("\n"); return; } if (!max_candidates) die(_("no tag exactly matches '%s'"), oid_to_hex(&cmit->object.oid)); if (debug) fprintf(stderr, _("searching to describe %s\n"), arg); if (!have_util) { struct hashmap_iter iter; struct commit *c; struct commit_name *n = hashmap_iter_first(&names, &iter); for (; n; n = hashmap_iter_next(&iter)) { c = lookup_commit_reference_gently(n->peeled, 1); if (c) c->util = n; } have_util = 1; } list = NULL; cmit->object.flags = SEEN; commit_list_insert(cmit, &list); while (list) { struct commit *c = pop_commit(&list); struct commit_list *parents = c->parents; seen_commits++; n = c->util; if (n) { if (!tags && !all && n->prio < 2) { unannotated_cnt++; } else if (match_cnt < max_candidates) { struct possible_tag *t = &all_matches[match_cnt++]; t->name = n; t->depth = seen_commits - 1; t->flag_within = 1u << match_cnt; t->found_order = match_cnt; c->object.flags |= t->flag_within; if (n->prio == 2) annotated_cnt++; } else { gave_up_on = c; break; } } for (cur_match = 0; cur_match < match_cnt; cur_match++) { struct possible_tag *t = &all_matches[cur_match]; if (!(c->object.flags & t->flag_within)) t->depth++; } if (annotated_cnt && !list) { if (debug) fprintf(stderr, _("finished search at %s\n"), oid_to_hex(&c->object.oid)); break; } while (parents) { struct commit *p = parents->item; parse_commit(p); if (!(p->object.flags & SEEN)) commit_list_insert_by_date(p, &list); p->object.flags |= c->object.flags; parents = parents->next; if (first_parent) break; } } if (!match_cnt) { struct object_id *oid = &cmit->object.oid; if (always) { printf("%s", find_unique_abbrev(oid->hash, abbrev)); if (dirty) printf("%s", dirty); printf("\n"); return; } if (unannotated_cnt) die(_("No annotated tags can describe '%s'.\n" "However, there were unannotated tags: try --tags."), oid_to_hex(oid)); else die(_("No tags can describe '%s'.\n" "Try --always, or create some tags."), oid_to_hex(oid)); } QSORT(all_matches, match_cnt, compare_pt); if (gave_up_on) { commit_list_insert_by_date(gave_up_on, &list); seen_commits--; } seen_commits += finish_depth_computation(&list, &all_matches[0]); free_commit_list(list); if (debug) { for (cur_match = 0; cur_match < match_cnt; cur_match++) { struct possible_tag *t = &all_matches[cur_match]; fprintf(stderr, " %-11s %8d %s\n", prio_names[t->name->prio], t->depth, t->name->path); } fprintf(stderr, _("traversed %lu commits\n"), seen_commits); if (gave_up_on) { fprintf(stderr, _("more than %i tags found; listed %i most recent\n" "gave up search at %s\n"), max_candidates, max_candidates, oid_to_hex(&gave_up_on->object.oid)); } } display_name(all_matches[0].name); if (abbrev) show_suffix(all_matches[0].depth, cmit->object.oid.hash); if (dirty) printf("%s", dirty); printf("\n"); if (!last_one) clear_commit_marks(cmit, -1); }
static void parse_treeish_arg(const char **argv, struct archiver_args *ar_args, const char *prefix, int remote) { const char *name = argv[0]; const unsigned char *commit_sha1; time_t archive_time; struct tree *tree; const struct commit *commit; unsigned char sha1[20]; /* Remotes are only allowed to fetch actual refs */ if (remote) { char *ref = NULL; const char *refname, *colon = NULL; colon = strchr(name, ':'); if (colon) refname = xstrndup(name, colon - name); else refname = name; if (!dwim_ref(refname, strlen(refname), sha1, &ref)) die("no such ref: %s", refname); if (refname != name) free((void *)refname); free(ref); } if (get_sha1(name, sha1)) die("Not a valid object name"); commit = lookup_commit_reference_gently(sha1, 1); if (commit) { commit_sha1 = commit->object.sha1; archive_time = commit->date; } else { commit_sha1 = NULL; archive_time = time(NULL); } tree = parse_tree_indirect(sha1); if (tree == NULL) die("not a tree object"); if (prefix) { unsigned char tree_sha1[20]; unsigned int mode; int err; err = get_tree_entry(tree->object.sha1, prefix, tree_sha1, &mode); if (err || !S_ISDIR(mode)) die("current working directory is untracked"); tree = parse_tree_indirect(tree_sha1); } ar_args->tree = tree; ar_args->commit_sha1 = commit_sha1; ar_args->commit = commit; ar_args->time = archive_time; }
static int parse_branchname_arg(int argc, const char **argv, int dwim_new_local_branch_ok, struct branch_info *new_branch_info, struct checkout_opts *opts, struct object_id *rev, int *dwim_remotes_matched) { struct tree **source_tree = &opts->source_tree; const char **new_branch = &opts->new_branch; int argcount = 0; struct object_id branch_rev; const char *arg; int dash_dash_pos; int has_dash_dash = 0; int i; /* * case 1: git checkout <ref> -- [<paths>] * * <ref> must be a valid tree, everything after the '--' must be * a path. * * case 2: git checkout -- [<paths>] * * everything after the '--' must be paths. * * case 3: git checkout <something> [--] * * (a) If <something> is a commit, that is to * switch to the branch or detach HEAD at it. As a special case, * if <something> is A...B (missing A or B means HEAD but you can * omit at most one side), and if there is a unique merge base * between A and B, A...B names that merge base. * * (b) If <something> is _not_ a commit, either "--" is present * or <something> is not a path, no -t or -b was given, and * and there is a tracking branch whose name is <something> * in one and only one remote (or if the branch exists on the * remote named in checkout.defaultRemote), then this is a * short-hand to fork local <something> from that * remote-tracking branch. * * (c) Otherwise, if "--" is present, treat it like case (1). * * (d) Otherwise : * - if it's a reference, treat it like case (1) * - else if it's a path, treat it like case (2) * - else: fail. * * case 4: git checkout <something> <paths> * * The first argument must not be ambiguous. * - If it's *only* a reference, treat it like case (1). * - If it's only a path, treat it like case (2). * - else: fail. * */ if (!argc) return 0; arg = argv[0]; dash_dash_pos = -1; for (i = 0; i < argc; i++) { if (!strcmp(argv[i], "--")) { dash_dash_pos = i; break; } } if (dash_dash_pos == 0) return 1; /* case (2) */ else if (dash_dash_pos == 1) has_dash_dash = 1; /* case (3) or (1) */ else if (dash_dash_pos >= 2) die(_("only one reference expected, %d given."), dash_dash_pos); opts->count_checkout_paths = !opts->quiet && !has_dash_dash; if (!strcmp(arg, "-")) arg = "@{-1}"; if (get_oid_mb(arg, rev)) { /* * Either case (3) or (4), with <something> not being * a commit, or an attempt to use case (1) with an * invalid ref. * * It's likely an error, but we need to find out if * we should auto-create the branch, case (3).(b). */ int recover_with_dwim = dwim_new_local_branch_ok; int could_be_checkout_paths = !has_dash_dash && check_filename(opts->prefix, arg); if (!has_dash_dash && !no_wildcard(arg)) recover_with_dwim = 0; /* * Accept "git checkout foo" and "git checkout foo --" * as candidates for dwim. */ if (!(argc == 1 && !has_dash_dash) && !(argc == 2 && has_dash_dash)) recover_with_dwim = 0; if (recover_with_dwim) { const char *remote = unique_tracking_name(arg, rev, dwim_remotes_matched); if (remote) { if (could_be_checkout_paths) die(_("'%s' could be both a local file and a tracking branch.\n" "Please use -- (and optionally --no-guess) to disambiguate"), arg); *new_branch = arg; arg = remote; /* DWIMmed to create local branch, case (3).(b) */ } else { recover_with_dwim = 0; } } if (!recover_with_dwim) { if (has_dash_dash) die(_("invalid reference: %s"), arg); return argcount; } } /* we can't end up being in (2) anymore, eat the argument */ argcount++; argv++; argc--; new_branch_info->name = arg; setup_branch_path(new_branch_info); if (!check_refname_format(new_branch_info->path, 0) && !read_ref(new_branch_info->path, &branch_rev)) oidcpy(rev, &branch_rev); else new_branch_info->path = NULL; /* not an existing branch */ new_branch_info->commit = lookup_commit_reference_gently(the_repository, rev, 1); if (!new_branch_info->commit) { /* not a commit */ *source_tree = parse_tree_indirect(rev); } else { parse_commit_or_die(new_branch_info->commit); *source_tree = get_commit_tree(new_branch_info->commit); } if (!*source_tree) /* case (1): want a tree */ die(_("reference is not a tree: %s"), arg); if (!has_dash_dash) { /* case (3).(d) -> (1) */ /* * Do not complain the most common case * git checkout branch * even if there happen to be a file called 'branch'; * it would be extremely annoying. */ if (argc) verify_non_filename(opts->prefix, arg); } else { argcount++; argv++; argc--; } return argcount; }
static int checkout_paths(const struct checkout_opts *opts, const char *revision) { int pos; struct checkout state = CHECKOUT_INIT; static char *ps_matched; struct object_id rev; struct commit *head; int errs = 0; struct lock_file lock_file = LOCK_INIT; int nr_checkouts = 0, nr_unmerged = 0; trace2_cmd_mode(opts->patch_mode ? "patch" : "path"); if (opts->track != BRANCH_TRACK_UNSPECIFIED) die(_("'%s' cannot be used with updating paths"), "--track"); if (opts->new_branch_log) die(_("'%s' cannot be used with updating paths"), "-l"); if (opts->force && opts->patch_mode) die(_("'%s' cannot be used with updating paths"), "-f"); if (opts->force_detach) die(_("'%s' cannot be used with updating paths"), "--detach"); if (opts->merge && opts->patch_mode) die(_("'%s' cannot be used with %s"), "--merge", "--patch"); if (opts->force && opts->merge) die(_("'%s' cannot be used with %s"), "-f", "-m"); if (opts->new_branch) die(_("Cannot update paths and switch to branch '%s' at the same time."), opts->new_branch); if (opts->patch_mode) return run_add_interactive(revision, "--patch=checkout", &opts->pathspec); repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR); if (read_cache_preload(&opts->pathspec) < 0) return error(_("index file corrupt")); if (opts->source_tree) read_tree_some(opts->source_tree, &opts->pathspec); ps_matched = xcalloc(opts->pathspec.nr, 1); /* * Make sure all pathspecs participated in locating the paths * to be checked out. */ for (pos = 0; pos < active_nr; pos++) if (opts->overlay_mode) mark_ce_for_checkout_overlay(active_cache[pos], ps_matched, opts); else mark_ce_for_checkout_no_overlay(active_cache[pos], ps_matched, opts); if (report_path_error(ps_matched, &opts->pathspec, opts->prefix)) { free(ps_matched); return 1; } free(ps_matched); /* "checkout -m path" to recreate conflicted state */ if (opts->merge) unmerge_marked_index(&the_index); /* Any unmerged paths? */ for (pos = 0; pos < active_nr; pos++) { const struct cache_entry *ce = active_cache[pos]; if (ce->ce_flags & CE_MATCHED) { if (!ce_stage(ce)) continue; if (opts->force) { warning(_("path '%s' is unmerged"), ce->name); } else if (opts->writeout_stage) { errs |= check_stage(opts->writeout_stage, ce, pos, opts->overlay_mode); } else if (opts->merge) { errs |= check_stages((1<<2) | (1<<3), ce, pos); } else { errs = 1; error(_("path '%s' is unmerged"), ce->name); } pos = skip_same_name(ce, pos) - 1; } } if (errs) return 1; /* Now we are committed to check them out */ state.force = 1; state.refresh_cache = 1; state.istate = &the_index; enable_delayed_checkout(&state); for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; if (ce->ce_flags & CE_MATCHED) { if (!ce_stage(ce)) { errs |= checkout_entry(ce, &state, NULL, &nr_checkouts); continue; } if (opts->writeout_stage) errs |= checkout_stage(opts->writeout_stage, ce, pos, &state, &nr_checkouts, opts->overlay_mode); else if (opts->merge) errs |= checkout_merged(pos, &state, &nr_unmerged); pos = skip_same_name(ce, pos) - 1; } } remove_marked_cache_entries(&the_index, 1); remove_scheduled_dirs(); errs |= finish_delayed_checkout(&state, &nr_checkouts); if (opts->count_checkout_paths) { if (nr_unmerged) fprintf_ln(stderr, Q_("Recreated %d merge conflict", "Recreated %d merge conflicts", nr_unmerged), nr_unmerged); if (opts->source_tree) fprintf_ln(stderr, Q_("Updated %d path from %s", "Updated %d paths from %s", nr_checkouts), nr_checkouts, find_unique_abbrev(&opts->source_tree->object.oid, DEFAULT_ABBREV)); else if (!nr_unmerged || nr_checkouts) fprintf_ln(stderr, Q_("Updated %d path from the index", "Updated %d paths from the index", nr_checkouts), nr_checkouts); } if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); read_ref_full("HEAD", 0, &rev, NULL); head = lookup_commit_reference_gently(the_repository, &rev, 1); errs |= post_checkout_hook(head, head, 0); return errs; }
struct commit *lookup_commit_reference(const unsigned char *sha1) { return lookup_commit_reference_gently(sha1, 0); }
static int checkout_paths(const struct checkout_opts *opts, const char *revision) { int pos; struct checkout state = CHECKOUT_INIT; static char *ps_matched; struct object_id rev; struct commit *head; int errs = 0; struct lock_file lock_file = LOCK_INIT; if (opts->track != BRANCH_TRACK_UNSPECIFIED) die(_("'%s' cannot be used with updating paths"), "--track"); if (opts->new_branch_log) die(_("'%s' cannot be used with updating paths"), "-l"); if (opts->force && opts->patch_mode) die(_("'%s' cannot be used with updating paths"), "-f"); if (opts->force_detach) die(_("'%s' cannot be used with updating paths"), "--detach"); if (opts->merge && opts->patch_mode) die(_("'%s' cannot be used with %s"), "--merge", "--patch"); if (opts->force && opts->merge) die(_("'%s' cannot be used with %s"), "-f", "-m"); if (opts->new_branch) die(_("Cannot update paths and switch to branch '%s' at the same time."), opts->new_branch); if (opts->patch_mode) return run_add_interactive(revision, "--patch=checkout", &opts->pathspec); hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); if (read_cache_preload(&opts->pathspec) < 0) return error(_("index file corrupt")); if (opts->source_tree) read_tree_some(opts->source_tree, &opts->pathspec); ps_matched = xcalloc(opts->pathspec.nr, 1); /* * Make sure all pathspecs participated in locating the paths * to be checked out. */ for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; ce->ce_flags &= ~CE_MATCHED; if (!opts->ignore_skipworktree && ce_skip_worktree(ce)) continue; if (opts->source_tree && !(ce->ce_flags & CE_UPDATE)) /* * "git checkout tree-ish -- path", but this entry * is in the original index; it will not be checked * out to the working tree and it does not matter * if pathspec matched this entry. We will not do * anything to this entry at all. */ continue; /* * Either this entry came from the tree-ish we are * checking the paths out of, or we are checking out * of the index. * * If it comes from the tree-ish, we already know it * matches the pathspec and could just stamp * CE_MATCHED to it from update_some(). But we still * need ps_matched and read_tree_recursive (and * eventually tree_entry_interesting) cannot fill * ps_matched yet. Once it can, we can avoid calling * match_pathspec() for _all_ entries when * opts->source_tree != NULL. */ if (ce_path_match(ce, &opts->pathspec, ps_matched)) ce->ce_flags |= CE_MATCHED; } if (report_path_error(ps_matched, &opts->pathspec, opts->prefix)) { free(ps_matched); return 1; } free(ps_matched); /* "checkout -m path" to recreate conflicted state */ if (opts->merge) unmerge_marked_index(&the_index); /* Any unmerged paths? */ for (pos = 0; pos < active_nr; pos++) { const struct cache_entry *ce = active_cache[pos]; if (ce->ce_flags & CE_MATCHED) { if (!ce_stage(ce)) continue; if (opts->force) { warning(_("path '%s' is unmerged"), ce->name); } else if (opts->writeout_stage) { errs |= check_stage(opts->writeout_stage, ce, pos); } else if (opts->merge) { errs |= check_stages((1<<2) | (1<<3), ce, pos); } else { errs = 1; error(_("path '%s' is unmerged"), ce->name); } pos = skip_same_name(ce, pos) - 1; } } if (errs) return 1; /* Now we are committed to check them out */ state.force = 1; state.refresh_cache = 1; state.istate = &the_index; enable_delayed_checkout(&state); for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; if (ce->ce_flags & CE_MATCHED) { if (!ce_stage(ce)) { errs |= checkout_entry(ce, &state, NULL); continue; } if (opts->writeout_stage) errs |= checkout_stage(opts->writeout_stage, ce, pos, &state); else if (opts->merge) errs |= checkout_merged(pos, &state); pos = skip_same_name(ce, pos) - 1; } } errs |= finish_delayed_checkout(&state); if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); read_ref_full("HEAD", 0, &rev, NULL); head = lookup_commit_reference_gently(&rev, 1); errs |= post_checkout_hook(head, head, 0); return errs; }
static int store_updated_refs(const char *raw_url, const char *remote_name, struct ref *ref_map) { FILE *fp; struct commit *commit; int url_len, i, note_len, shown_url = 0, rc = 0; char note[1024]; const char *what, *kind; struct ref *rm; char *url, *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD"); fp = fopen(filename, "a"); if (!fp) return error("cannot open %s: %s\n", filename, strerror(errno)); if (raw_url) url = transport_anonymize_url(raw_url); else url = xstrdup("foreign"); for (rm = ref_map; rm; rm = rm->next) { struct ref *ref = NULL; if (rm->peer_ref) { ref = xcalloc(1, sizeof(*ref) + strlen(rm->peer_ref->name) + 1); strcpy(ref->name, rm->peer_ref->name); hashcpy(ref->old_sha1, rm->peer_ref->old_sha1); hashcpy(ref->new_sha1, rm->old_sha1); ref->force = rm->peer_ref->force; } commit = lookup_commit_reference_gently(rm->old_sha1, 1); if (!commit) rm->merge = 0; if (!strcmp(rm->name, "HEAD")) { kind = ""; what = ""; } else if (!prefixcmp(rm->name, "refs/heads/")) { kind = "branch"; what = rm->name + 11; } else if (!prefixcmp(rm->name, "refs/tags/")) { kind = "tag"; what = rm->name + 10; } else if (!prefixcmp(rm->name, "refs/remotes/")) { kind = "remote branch"; what = rm->name + 13; } else { kind = ""; what = rm->name; } url_len = strlen(url); for (i = url_len - 1; url[i] == '/' && 0 <= i; i--) ; url_len = i + 1; if (4 < i && !strncmp(".git", url + i - 3, 4)) url_len = i - 3; note_len = 0; if (*what) { if (*kind) note_len += sprintf(note + note_len, "%s ", kind); note_len += sprintf(note + note_len, "'%s' of ", what); } note[note_len] = '\0'; fprintf(fp, "%s\t%s\t%s", sha1_to_hex(commit ? commit->object.sha1 : rm->old_sha1), rm->merge ? "" : "not-for-merge", note); for (i = 0; i < url_len; ++i) if ('\n' == url[i]) fputs("\\n", fp); else fputc(url[i], fp); fputc('\n', fp); if (ref) { rc |= update_local_ref(ref, what, note); free(ref); } else sprintf(note, "* %-*s %-*s -> FETCH_HEAD", TRANSPORT_SUMMARY_WIDTH, *kind ? kind : "branch", REFCOL_WIDTH, *what ? what : "HEAD"); if (*note) { if (verbosity >= 0 && !shown_url) { fprintf(stderr, "From %.*s\n", url_len, url); shown_url = 1; } if (verbosity >= 0) fprintf(stderr, " %s\n", note); } } free(url); fclose(fp); if (rc & STORE_REF_ERROR_DF_CONFLICT) error("some local refs could not be updated; try running\n" " 'git remote prune %s' to remove any old, conflicting " "branches", remote_name); return rc; }
static int update_local_ref(struct ref *ref, const char *remote, char *display) { struct commit *current = NULL, *updated; enum object_type type; struct branch *current_branch = branch_get(NULL); const char *pretty_ref = prettify_refname(ref->name); *display = 0; type = sha1_object_info(ref->new_sha1, NULL); if (type < 0) die("object %s not found", sha1_to_hex(ref->new_sha1)); if (!hashcmp(ref->old_sha1, ref->new_sha1)) { if (verbosity > 0) sprintf(display, "= %-*s %-*s -> %s", TRANSPORT_SUMMARY_WIDTH, "[up to date]", REFCOL_WIDTH, remote, pretty_ref); return 0; } if (current_branch && !strcmp(ref->name, current_branch->name) && !(update_head_ok || is_bare_repository()) && !is_null_sha1(ref->old_sha1)) { /* * If this is the head, and it's not okay to update * the head, and the old value of the head isn't empty... */ sprintf(display, "! %-*s %-*s -> %s (can't fetch in current branch)", TRANSPORT_SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote, pretty_ref); return 1; } if (!is_null_sha1(ref->old_sha1) && !prefixcmp(ref->name, "refs/tags/")) { int r; r = s_update_ref("updating tag", ref, 0); sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '-', TRANSPORT_SUMMARY_WIDTH, "[tag update]", REFCOL_WIDTH, remote, pretty_ref, r ? " (unable to update local ref)" : ""); return r; } current = lookup_commit_reference_gently(ref->old_sha1, 1); updated = lookup_commit_reference_gently(ref->new_sha1, 1); if (!current || !updated) { const char *msg; const char *what; int r; if (!strncmp(ref->name, "refs/tags/", 10)) { msg = "storing tag"; what = "[new tag]"; } else { msg = "storing head"; what = "[new branch]"; } r = s_update_ref(msg, ref, 0); sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*', TRANSPORT_SUMMARY_WIDTH, what, REFCOL_WIDTH, remote, pretty_ref, r ? " (unable to update local ref)" : ""); return r; } if (in_merge_bases(current, &updated, 1)) { char quickref[83]; int r; strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); strcat(quickref, ".."); strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); r = s_update_ref("fast-forward", ref, 1); sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : ' ', TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, pretty_ref, r ? " (unable to update local ref)" : ""); return r; } else if (force || ref->force) { char quickref[84]; int r; strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); strcat(quickref, "..."); strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); r = s_update_ref("forced-update", ref, 1); sprintf(display, "%c %-*s %-*s -> %s (%s)", r ? '!' : '+', TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, pretty_ref, r ? "unable to update local ref" : "forced update"); return r; } else { sprintf(display, "! %-*s %-*s -> %s (non-fast-forward)", TRANSPORT_SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote, pretty_ref); return 1; } }
static int append_ref(const char *refname, const unsigned char *sha1, int flags, void *cb_data) { struct append_ref_cb *cb = (struct append_ref_cb *)(cb_data); struct ref_list *ref_list = cb->ref_list; struct ref_item *newitem; struct commit *commit; int kind, i; const char *prefix, *orig_refname = refname; static struct { int kind; const char *prefix; int pfxlen; } ref_kind[] = { { REF_LOCAL_BRANCH, "refs/heads/", 11 }, { REF_REMOTE_BRANCH, "refs/remotes/", 13 }, }; /* Detect kind */ for (i = 0; i < ARRAY_SIZE(ref_kind); i++) { prefix = ref_kind[i].prefix; if (strncmp(refname, prefix, ref_kind[i].pfxlen)) continue; kind = ref_kind[i].kind; refname += ref_kind[i].pfxlen; break; } if (ARRAY_SIZE(ref_kind) <= i) return 0; /* Don't add types the caller doesn't want */ if ((kind & ref_list->kinds) == 0) return 0; if (!match_patterns(cb->pattern, refname)) return 0; commit = NULL; if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) { commit = lookup_commit_reference_gently(sha1, 1); if (!commit) { cb->ret = error(_("branch '%s' does not point at a commit"), refname); return 0; } /* Filter with with_commit if specified */ if (!is_descendant_of(commit, ref_list->with_commit)) return 0; if (merge_filter != NO_FILTER) add_pending_object(&ref_list->revs, (struct object *)commit, refname); } ALLOC_GROW(ref_list->list, ref_list->index + 1, ref_list->alloc); /* Record the new item */ newitem = &(ref_list->list[ref_list->index++]); newitem->name = xstrdup(refname); newitem->kind = kind; newitem->commit = commit; newitem->width = utf8_strwidth(refname); newitem->dest = resolve_symref(orig_refname, prefix); /* adjust for "remotes/" */ if (newitem->kind == REF_REMOTE_BRANCH && ref_list->kinds != REF_REMOTE_BRANCH) newitem->width += 8; if (newitem->width > ref_list->maxwidth) ref_list->maxwidth = newitem->width; return 0; }