static int store_stash(int argc, const char **argv, const char *prefix) { int quiet = 0; const char *stash_msg = NULL; struct object_id obj; struct object_context dummy; struct option options[] = { OPT__QUIET(&quiet, N_("be quiet")), OPT_STRING('m', "message", &stash_msg, "message", N_("stash message")), OPT_END() }; argc = parse_options(argc, argv, prefix, options, git_stash_store_usage, PARSE_OPT_KEEP_UNKNOWN); if (argc != 1) { if (!quiet) fprintf_ln(stderr, _("\"git stash store\" requires one " "<commit> argument")); return -1; } if (get_oid_with_context(the_repository, argv[0], quiet ? GET_OID_QUIETLY : 0, &obj, &dummy)) { if (!quiet) fprintf_ln(stderr, _("Cannot update %s with %s"), ref_stash, argv[0]); return -1; } return do_store_stash(&obj, stash_msg, quiet); }
static int stash_patch(struct stash_info *info, struct pathspec ps, struct strbuf *out_patch, int quiet) { int ret = 0; struct child_process cp_read_tree = CHILD_PROCESS_INIT; struct child_process cp_add_i = CHILD_PROCESS_INIT; struct child_process cp_diff_tree = CHILD_PROCESS_INIT; struct index_state istate = { NULL }; remove_path(stash_index_path.buf); cp_read_tree.git_cmd = 1; argv_array_pushl(&cp_read_tree.args, "read-tree", "HEAD", NULL); argv_array_pushf(&cp_read_tree.env_array, "GIT_INDEX_FILE=%s", stash_index_path.buf); if (run_command(&cp_read_tree)) { ret = -1; goto done; } /* Find out what the user wants. */ cp_add_i.git_cmd = 1; argv_array_pushl(&cp_add_i.args, "add--interactive", "--patch=stash", "--", NULL); add_pathspecs(&cp_add_i.args, ps); argv_array_pushf(&cp_add_i.env_array, "GIT_INDEX_FILE=%s", stash_index_path.buf); if (run_command(&cp_add_i)) { ret = -1; goto done; } /* State of the working tree. */ if (write_index_as_tree(&info->w_tree, &istate, stash_index_path.buf, 0, NULL)) { ret = -1; goto done; } cp_diff_tree.git_cmd = 1; argv_array_pushl(&cp_diff_tree.args, "diff-tree", "-p", "HEAD", oid_to_hex(&info->w_tree), "--", NULL); if (pipe_command(&cp_diff_tree, NULL, 0, out_patch, 0, NULL, 0)) { ret = -1; goto done; } if (!out_patch->len) { if (!quiet) fprintf_ln(stderr, _("No changes selected")); ret = 1; } done: discard_index(&istate); remove_path(stash_index_path.buf); return ret; }
void help_unknown_ref(const char *ref, const char *cmd, const char *error) { int i; struct string_list suggested_refs = guess_refs(ref); fprintf_ln(stderr, _("%s: %s - %s"), cmd, ref, error); if (suggested_refs.nr > 0) { fprintf_ln(stderr, Q_("\nDid you mean this?", "\nDid you mean one of these?", suggested_refs.nr)); for (i = 0; i < suggested_refs.nr; i++) fprintf(stderr, "\t%s\n", suggested_refs.items[i].string); } string_list_clear(&suggested_refs, 0); exit(1); }
static void update_paths(struct string_list *update) { struct lock_file index_lock = LOCK_INIT; int i; hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR); for (i = 0; i < update->nr; i++) { struct string_list_item *item = &update->items[i]; if (add_file_to_cache(item->string, 0)) exit(128); fprintf_ln(stderr, _("Staged '%s' using previous resolution."), item->string); } if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK | SKIP_IF_UNCHANGED)) die(_("unable to write new index file")); }
static int do_store_stash(const struct object_id *w_commit, const char *stash_msg, int quiet) { if (!stash_msg) stash_msg = "Created via \"git stash store\"."; if (update_ref(stash_msg, ref_stash, w_commit, NULL, REF_FORCE_CREATE_REFLOG, quiet ? UPDATE_REFS_QUIET_ON_ERR : UPDATE_REFS_MSG_ON_ERR)) { if (!quiet) { fprintf_ln(stderr, _("Cannot update %s with %s"), ref_stash, oid_to_hex(w_commit)); } return -1; } return 0; }
static int branch_stash(int argc, const char **argv, const char *prefix) { int ret; const char *branch = NULL; struct stash_info info; struct child_process cp = CHILD_PROCESS_INIT; struct option options[] = { OPT_END() }; argc = parse_options(argc, argv, prefix, options, git_stash_branch_usage, 0); if (!argc) { fprintf_ln(stderr, _("No branch name specified")); return -1; } branch = argv[0]; if (get_stash_info(&info, argc - 1, argv + 1)) return -1; cp.git_cmd = 1; argv_array_pushl(&cp.args, "checkout", "-b", NULL); argv_array_push(&cp.args, branch); argv_array_push(&cp.args, oid_to_hex(&info.b_commit)); ret = run_command(&cp); if (!ret) ret = do_apply_stash(prefix, &info, 1, 0); if (!ret && info.is_stash_ref) ret = do_drop_stash(prefix, &info, 0); free_stash_info(&info); return ret; }
/** * Dies with the appropriate reason for why there are no merge candidates: * * 1. We fetched from a specific remote, and a refspec was given, but it ended * up not fetching anything. This is usually because the user provided a * wildcard refspec which had no matches on the remote end. * * 2. We fetched from a non-default remote, but didn't specify a branch to * merge. We can't use the configured one because it applies to the default * remote, thus the user must specify the branches to merge. * * 3. We fetched from the branch's or repo's default remote, but: * * a. We are not on a branch, so there will never be a configured branch to * merge with. * * b. We are on a branch, but there is no configured branch to merge with. * * 4. We fetched from the branch's or repo's default remote, but the configured * branch to merge didn't get fetched. (Either it doesn't exist, or wasn't * part of the configured fetch refspec.) */ static void NORETURN die_no_merge_candidates(const char *repo, const char **refspecs) { struct branch *curr_branch = branch_get("HEAD"); const char *remote = curr_branch ? curr_branch->remote_name : NULL; if (*refspecs) { if (opt_rebase) fprintf_ln(stderr, _("There is no candidate for rebasing against among the refs that you just fetched.")); else fprintf_ln(stderr, _("There are no candidates for merging among the refs that you just fetched.")); fprintf_ln(stderr, _("Generally this means that you provided a wildcard refspec which had no\n" "matches on the remote end.")); } else if (repo && curr_branch && (!remote || strcmp(repo, remote))) { fprintf_ln(stderr, _("You asked to pull from the remote '%s', but did not specify\n" "a branch. Because this is not the default configured remote\n" "for your current branch, you must specify a branch on the command line."), repo); } else if (!curr_branch) { fprintf_ln(stderr, _("You are not currently on a branch.")); if (opt_rebase) fprintf_ln(stderr, _("Please specify which branch you want to rebase against.")); else fprintf_ln(stderr, _("Please specify which branch you want to merge with.")); fprintf_ln(stderr, _("See git-pull(1) for details.")); fprintf(stderr, "\n"); fprintf_ln(stderr, " git pull %s %s", _("<remote>"), _("<branch>")); fprintf(stderr, "\n"); } else if (!curr_branch->merge_nr) { const char *remote_name = NULL; if (for_each_remote(get_only_remote, &remote_name) || !remote_name) remote_name = _("<remote>"); fprintf_ln(stderr, _("There is no tracking information for the current branch.")); if (opt_rebase) fprintf_ln(stderr, _("Please specify which branch you want to rebase against.")); else fprintf_ln(stderr, _("Please specify which branch you want to merge with.")); fprintf_ln(stderr, _("See git-pull(1) for details.")); fprintf(stderr, "\n"); fprintf_ln(stderr, " git pull %s %s", _("<remote>"), _("<branch>")); fprintf(stderr, "\n"); fprintf_ln(stderr, _("If you wish to set tracking information for this branch you can do so with:")); fprintf(stderr, "\n"); fprintf_ln(stderr, " git branch --set-upstream-to=%s/%s %s\n", remote_name, _("<branch>"), curr_branch->name); } else fprintf_ln(stderr, _("Your configuration specifies to merge with the ref '%s'\n" "from the remote, but no such ref was fetched."), *curr_branch->merge_name); exit(1); }
const char *help_unknown_cmd(const char *cmd) { int i, n, best_similarity = 0; struct cmdnames main_cmds, other_cmds; memset(&main_cmds, 0, sizeof(main_cmds)); memset(&other_cmds, 0, sizeof(other_cmds)); memset(&aliases, 0, sizeof(aliases)); git_config(git_unknown_cmd_config, NULL); load_command_list("git-", &main_cmds, &other_cmds); add_cmd_list(&main_cmds, &aliases); add_cmd_list(&main_cmds, &other_cmds); qsort(main_cmds.names, main_cmds.cnt, sizeof(*main_cmds.names), cmdname_compare); uniq(&main_cmds); /* This abuses cmdname->len for levenshtein distance */ for (i = 0, n = 0; i < main_cmds.cnt; i++) { int cmp = 0; /* avoid compiler stupidity */ const char *candidate = main_cmds.names[i]->name; /* * An exact match means we have the command, but * for some reason exec'ing it gave us ENOENT; probably * it's a bad interpreter in the #! line. */ if (!strcmp(candidate, cmd)) die(_(bad_interpreter_advice), cmd, cmd); /* Does the candidate appear in common_cmds list? */ while (n < ARRAY_SIZE(common_cmds) && (cmp = strcmp(common_cmds[n].name, candidate)) < 0) n++; if ((n < ARRAY_SIZE(common_cmds)) && !cmp) { /* Yes, this is one of the common commands */ n++; /* use the entry from common_cmds[] */ if (starts_with(candidate, cmd)) { /* Give prefix match a very good score */ main_cmds.names[i]->len = 0; continue; } } main_cmds.names[i]->len = levenshtein(cmd, candidate, 0, 2, 1, 3) + 1; } qsort(main_cmds.names, main_cmds.cnt, sizeof(*main_cmds.names), levenshtein_compare); if (!main_cmds.cnt) die(_("Uh oh. Your system reports no Git commands at all.")); /* skip and count prefix matches */ for (n = 0; n < main_cmds.cnt && !main_cmds.names[n]->len; n++) ; /* still counting */ if (main_cmds.cnt <= n) { /* prefix matches with everything? that is too ambiguous */ best_similarity = SIMILARITY_FLOOR + 1; } else { /* count all the most similar ones */ for (best_similarity = main_cmds.names[n++]->len; (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len); n++) ; /* still counting */ } if (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) { const char *assumed = main_cmds.names[0]->name; main_cmds.names[0] = NULL; clean_cmdnames(&main_cmds); fprintf_ln(stderr, _("WARNING: You called a Git command named '%s', " "which does not exist.\n" "Continuing under the assumption that you meant '%s'"), cmd, assumed); if (autocorrect > 0) { fprintf_ln(stderr, _("in %0.1f seconds automatically..."), (float)autocorrect/10.0); poll(NULL, 0, autocorrect * 100); } return assumed; } fprintf_ln(stderr, _("git: '%s' is not a git command. See 'git --help'."), cmd); if (SIMILAR_ENOUGH(best_similarity)) { fprintf_ln(stderr, Q_("\nDid you mean this?", "\nDid you mean one of these?", n)); for (i = 0; i < n; i++) fprintf(stderr, "\t%s\n", main_cmds.names[i]->name); } exit(1); }
/* * Returns a connected socket() fd, or else die()s. */ static int git_tcp_connect_sock(char *host, int flags) { struct strbuf error_message = STRBUF_INIT; int sockfd = -1; const char *port = STR(DEFAULT_GIT_PORT); char *ep; struct hostent *he; struct sockaddr_in sa; char **ap; unsigned int nport; int cnt; get_host_and_port(&host, &port); if (flags & CONNECT_VERBOSE) fprintf(stderr, _("Looking up %s ... "), host); he = gethostbyname(host); if (!he) die(_("unable to look up %s (%s)"), host, hstrerror(h_errno)); nport = strtoul(port, &ep, 10); if ( ep == port || *ep ) { /* Not numeric */ struct servent *se = getservbyname(port,"tcp"); if ( !se ) die(_("unknown port %s"), port); nport = se->s_port; } if (flags & CONNECT_VERBOSE) /* TRANSLATORS: this is the end of "Looking up %s ... " */ fprintf(stderr, _("done.\nConnecting to %s (port %s) ... "), host, port); for (cnt = 0, ap = he->h_addr_list; *ap; ap++, cnt++) { memset(&sa, 0, sizeof sa); sa.sin_family = he->h_addrtype; sa.sin_port = htons(nport); memcpy(&sa.sin_addr, *ap, he->h_length); sockfd = socket(he->h_addrtype, SOCK_STREAM, 0); if ((sockfd < 0) || connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) { strbuf_addf(&error_message, "%s[%d: %s]: errno=%s\n", host, cnt, inet_ntoa(*(struct in_addr *)&sa.sin_addr), strerror(errno)); if (0 <= sockfd) close(sockfd); sockfd = -1; continue; } if (flags & CONNECT_VERBOSE) fprintf(stderr, "%s ", inet_ntoa(*(struct in_addr *)&sa.sin_addr)); break; } if (sockfd < 0) die(_("unable to connect to %s:\n%s"), host, error_message.buf); enable_keepalive(sockfd); if (flags & CONNECT_VERBOSE) /* TRANSLATORS: this is the end of "Connecting to %s (port %s) ... " */ fprintf_ln(stderr, _("done.")); return sockfd; }
/* * The path indicated by rr_item may still have conflict for which we * have a recorded resolution, in which case replay it and optionally * update it. Or it may have been resolved by the user and we may * only have the preimage for that conflict, in which case the result * needs to be recorded as a resolution in a postimage file. */ static void do_rerere_one_path(struct string_list_item *rr_item, struct string_list *update) { const char *path = rr_item->string; struct rerere_id *id = rr_item->util; struct rerere_dir *rr_dir = id->collection; int variant; variant = id->variant; /* Has the user resolved it already? */ if (variant >= 0) { if (!handle_file(path, NULL, NULL)) { copy_file(rerere_path(id, "postimage"), path, 0666); id->collection->status[variant] |= RR_HAS_POSTIMAGE; fprintf_ln(stderr, _("Recorded resolution for '%s'."), path); free_rerere_id(rr_item); rr_item->util = NULL; return; } /* * There may be other variants that can cleanly * replay. Try them and update the variant number for * this one. */ } /* Does any existing resolution apply cleanly? */ for (variant = 0; variant < rr_dir->status_nr; variant++) { const int both = RR_HAS_PREIMAGE | RR_HAS_POSTIMAGE; struct rerere_id vid = *id; if ((rr_dir->status[variant] & both) != both) continue; vid.variant = variant; if (merge(&vid, path)) continue; /* failed to replay */ /* * If there already is a different variant that applies * cleanly, there is no point maintaining our own variant. */ if (0 <= id->variant && id->variant != variant) remove_variant(id); if (rerere_autoupdate) string_list_insert(update, path); else fprintf_ln(stderr, _("Resolved '%s' using previous resolution."), path); free_rerere_id(rr_item); rr_item->util = NULL; return; } /* None of the existing one applies; we need a new variant */ assign_variant(id); variant = id->variant; handle_file(path, NULL, rerere_path(id, "preimage")); if (id->collection->status[variant] & RR_HAS_POSTIMAGE) { const char *path = rerere_path(id, "postimage"); if (unlink(path)) die_errno(_("cannot unlink stray '%s'"), path); id->collection->status[variant] &= ~RR_HAS_POSTIMAGE; } id->collection->status[variant] |= RR_HAS_PREIMAGE; fprintf_ln(stderr, _("Recorded preimage for '%s'"), path); }
static int add_worktree(const char *path, const char *refname, const struct add_opts *opts) { struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT; struct strbuf sb = STRBUF_INIT; const char *name; struct stat st; struct child_process cp = CHILD_PROCESS_INIT; struct argv_array child_env = ARGV_ARRAY_INIT; int counter = 0, len, ret; struct strbuf symref = STRBUF_INIT; struct commit *commit = NULL; int is_branch = 0; if (file_exists(path) && !is_empty_dir(path)) die(_("'%s' already exists"), path); /* is 'refname' a branch or commit? */ if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) && ref_exists(symref.buf)) { is_branch = 1; if (!opts->force) die_if_checked_out(symref.buf, 0); } commit = lookup_commit_reference_by_name(refname); if (!commit) die(_("invalid reference: %s"), refname); name = worktree_basename(path, &len); git_path_buf(&sb_repo, "worktrees/%.*s", (int)(path + len - name), name); len = sb_repo.len; if (safe_create_leading_directories_const(sb_repo.buf)) die_errno(_("could not create leading directories of '%s'"), sb_repo.buf); while (!stat(sb_repo.buf, &st)) { counter++; strbuf_setlen(&sb_repo, len); strbuf_addf(&sb_repo, "%d", counter); } name = strrchr(sb_repo.buf, '/') + 1; junk_pid = getpid(); atexit(remove_junk); sigchain_push_common(remove_junk_on_signal); if (mkdir(sb_repo.buf, 0777)) die_errno(_("could not create directory of '%s'"), sb_repo.buf); junk_git_dir = xstrdup(sb_repo.buf); is_junk = 1; /* * lock the incomplete repo so prune won't delete it, unlock * after the preparation is over. */ strbuf_addf(&sb, "%s/locked", sb_repo.buf); if (!opts->keep_locked) write_file(sb.buf, "initializing"); else write_file(sb.buf, "added with --lock"); strbuf_addf(&sb_git, "%s/.git", path); if (safe_create_leading_directories_const(sb_git.buf)) die_errno(_("could not create leading directories of '%s'"), sb_git.buf); junk_work_tree = xstrdup(path); strbuf_reset(&sb); strbuf_addf(&sb, "%s/gitdir", sb_repo.buf); write_file(sb.buf, "%s", real_path(sb_git.buf)); write_file(sb_git.buf, "gitdir: %s/worktrees/%s", real_path(get_git_common_dir()), name); /* * This is to keep resolve_ref() happy. We need a valid HEAD * or is_git_directory() will reject the directory. Any value which * looks like an object ID will do since it will be immediately * replaced by the symbolic-ref or update-ref invocation in the new * worktree. */ strbuf_reset(&sb); strbuf_addf(&sb, "%s/HEAD", sb_repo.buf); write_file(sb.buf, "%s", sha1_to_hex(null_sha1)); strbuf_reset(&sb); strbuf_addf(&sb, "%s/commondir", sb_repo.buf); write_file(sb.buf, "../.."); fprintf_ln(stderr, _("Preparing %s (identifier %s)"), path, name); argv_array_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf); argv_array_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path); cp.git_cmd = 1; if (!is_branch) argv_array_pushl(&cp.args, "update-ref", "HEAD", oid_to_hex(&commit->object.oid), NULL); else argv_array_pushl(&cp.args, "symbolic-ref", "HEAD", symref.buf, NULL); cp.env = child_env.argv; ret = run_command(&cp); if (ret) goto done; if (opts->checkout) { cp.argv = NULL; argv_array_clear(&cp.args); argv_array_pushl(&cp.args, "reset", "--hard", NULL); cp.env = child_env.argv; ret = run_command(&cp); if (ret) goto done; } is_junk = 0; FREE_AND_NULL(junk_work_tree); FREE_AND_NULL(junk_git_dir); done: if (ret || !opts->keep_locked) { strbuf_reset(&sb); strbuf_addf(&sb, "%s/locked", sb_repo.buf); unlink_or_warn(sb.buf); } /* * Hook failure does not warrant worktree deletion, so run hook after * is_junk is cleared, but do return appropriate code when hook fails. */ if (!ret && opts->checkout) { const char *hook = find_hook("post-checkout"); if (hook) { const char *env[] = { "GIT_DIR", "GIT_WORK_TREE", NULL }; cp.git_cmd = 0; cp.no_stdin = 1; cp.stdout_to_stderr = 1; cp.dir = path; cp.env = env; cp.argv = NULL; argv_array_pushl(&cp.args, absolute_path(hook), oid_to_hex(&null_oid), oid_to_hex(&commit->object.oid), "1", NULL); ret = run_command(&cp); } } argv_array_clear(&child_env); strbuf_release(&sb); strbuf_release(&symref); strbuf_release(&sb_repo); strbuf_release(&sb_git); return ret; }
static int rerere_forget_one_path(const char *path, struct string_list *rr) { const char *filename; struct rerere_id *id; unsigned char sha1[20]; int ret; struct string_list_item *item; /* * Recreate the original conflict from the stages in the * index and compute the conflict ID */ ret = handle_cache(path, sha1, NULL); if (ret < 1) return error(_("could not parse conflict hunks in '%s'"), path); /* Nuke the recorded resolution for the conflict */ id = new_rerere_id(sha1); for (id->variant = 0; id->variant < id->collection->status_nr; id->variant++) { mmfile_t cur = { NULL, 0 }; mmbuffer_t result = {NULL, 0}; int cleanly_resolved; if (!has_rerere_resolution(id)) continue; handle_cache(path, sha1, rerere_path(id, "thisimage")); if (read_mmfile(&cur, rerere_path(id, "thisimage"))) { free(cur.ptr); error(_("failed to update conflicted state in '%s'"), path); goto fail_exit; } cleanly_resolved = !try_merge(id, path, &cur, &result); free(result.ptr); free(cur.ptr); if (cleanly_resolved) break; } if (id->collection->status_nr <= id->variant) { error(_("no remembered resolution for '%s'"), path); goto fail_exit; } filename = rerere_path(id, "postimage"); if (unlink(filename)) { if (errno == ENOENT) error(_("no remembered resolution for '%s'"), path); else error_errno(_("cannot unlink '%s'"), filename); goto fail_exit; } /* * Update the preimage so that the user can resolve the * conflict in the working tree, run us again to record * the postimage. */ handle_cache(path, sha1, rerere_path(id, "preimage")); fprintf_ln(stderr, _("Updated preimage for '%s'"), path); /* * And remember that we can record resolution for this * conflict when the user is done. */ item = string_list_insert(rr, path); free_rerere_id(item); item->util = id; fprintf(stderr, _("Forgot resolution for '%s'\n"), path); return 0; fail_exit: free(id); return -1; }
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; }
static int test_if_untracked_cache_is_supported(void) { struct stat st; struct stat_data base; int fd, ret = 0; char *cwd; strbuf_addstr(&mtime_dir, "mtime-test-XXXXXX"); if (!mkdtemp(mtime_dir.buf)) die_errno("Could not make temporary directory"); cwd = xgetcwd(); fprintf(stderr, _("Testing mtime in '%s' "), cwd); free(cwd); atexit(remove_test_directory); xstat_mtime_dir(&st); fill_stat_data(&base, &st); fputc('.', stderr); avoid_racy(); fd = create_file("newfile"); xstat_mtime_dir(&st); if (!match_stat_data(&base, &st)) { close(fd); fputc('\n', stderr); fprintf_ln(stderr,_("directory stat info does not " "change after adding a new file")); goto done; } fill_stat_data(&base, &st); fputc('.', stderr); avoid_racy(); xmkdir("new-dir"); xstat_mtime_dir(&st); if (!match_stat_data(&base, &st)) { close(fd); fputc('\n', stderr); fprintf_ln(stderr, _("directory stat info does not change " "after adding a new directory")); goto done; } fill_stat_data(&base, &st); fputc('.', stderr); avoid_racy(); write_or_die(fd, "data", 4); close(fd); xstat_mtime_dir(&st); if (match_stat_data(&base, &st)) { fputc('\n', stderr); fprintf_ln(stderr, _("directory stat info changes " "after updating a file")); goto done; } fputc('.', stderr); avoid_racy(); close(create_file("new-dir/new")); xstat_mtime_dir(&st); if (match_stat_data(&base, &st)) { fputc('\n', stderr); fprintf_ln(stderr, _("directory stat info changes after " "adding a file inside subdirectory")); goto done; } fputc('.', stderr); avoid_racy(); xunlink("newfile"); xstat_mtime_dir(&st); if (!match_stat_data(&base, &st)) { fputc('\n', stderr); fprintf_ln(stderr, _("directory stat info does not " "change after deleting a file")); goto done; } fill_stat_data(&base, &st); fputc('.', stderr); avoid_racy(); xunlink("new-dir/new"); xrmdir("new-dir"); xstat_mtime_dir(&st); if (!match_stat_data(&base, &st)) { fputc('\n', stderr); fprintf_ln(stderr, _("directory stat info does not " "change after deleting a directory")); goto done; } if (rmdir(mtime_dir.buf)) die_errno(_("failed to delete directory %s"), mtime_dir.buf); fprintf_ln(stderr, _(" OK")); ret = 1; done: strbuf_release(&mtime_dir); return ret; }
/* * Returns a connected socket() fd, or else die()s. */ static int git_tcp_connect_sock(char *host, int flags) { struct strbuf error_message = STRBUF_INIT; int sockfd = -1; const char *port = STR(DEFAULT_GIT_PORT); struct addrinfo hints, *ai0, *ai; int gai; int cnt = 0; get_host_and_port(&host, &port); if (!*port) port = "<none>"; memset(&hints, 0, sizeof(hints)); if (flags & CONNECT_IPV4) hints.ai_family = AF_INET; else if (flags & CONNECT_IPV6) hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if (flags & CONNECT_VERBOSE) fprintf(stderr, _("Looking up %s ... "), host); gai = getaddrinfo(host, port, &hints, &ai); if (gai) die(_("unable to look up %s (port %s) (%s)"), host, port, gai_strerror(gai)); if (flags & CONNECT_VERBOSE) /* TRANSLATORS: this is the end of "Looking up %s ... " */ fprintf(stderr, _("done.\nConnecting to %s (port %s) ... "), host, port); for (ai0 = ai; ai; ai = ai->ai_next, cnt++) { sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if ((sockfd < 0) || (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0)) { strbuf_addf(&error_message, "%s[%d: %s]: errno=%s\n", host, cnt, ai_name(ai), strerror(errno)); if (0 <= sockfd) close(sockfd); sockfd = -1; continue; } if (flags & CONNECT_VERBOSE) fprintf(stderr, "%s ", ai_name(ai)); break; } freeaddrinfo(ai0); if (sockfd < 0) die(_("unable to connect to %s:\n%s"), host, error_message.buf); enable_keepalive(sockfd); if (flags & CONNECT_VERBOSE) /* TRANSLATORS: this is the end of "Connecting to %s (port %s) ... " */ fprintf_ln(stderr, _("done.")); strbuf_release(&error_message); return sockfd; }
static int do_create_stash(struct pathspec ps, struct strbuf *stash_msg_buf, int include_untracked, int patch_mode, struct stash_info *info, struct strbuf *patch, int quiet) { int ret = 0; int flags = 0; int untracked_commit_option = 0; const char *head_short_sha1 = NULL; const char *branch_ref = NULL; const char *branch_name = "(no branch)"; struct commit *head_commit = NULL; struct commit_list *parents = NULL; struct strbuf msg = STRBUF_INIT; struct strbuf commit_tree_label = STRBUF_INIT; struct strbuf untracked_files = STRBUF_INIT; prepare_fallback_ident("git stash", "git@stash"); read_cache_preload(NULL); refresh_cache(REFRESH_QUIET); if (get_oid("HEAD", &info->b_commit)) { if (!quiet) fprintf_ln(stderr, _("You do not have " "the initial commit yet")); ret = -1; goto done; } else { head_commit = lookup_commit(the_repository, &info->b_commit); } if (!check_changes(ps, include_untracked, &untracked_files)) { ret = 1; goto done; } branch_ref = resolve_ref_unsafe("HEAD", 0, NULL, &flags); if (flags & REF_ISSYMREF) branch_name = strrchr(branch_ref, '/') + 1; head_short_sha1 = find_unique_abbrev(&head_commit->object.oid, DEFAULT_ABBREV); strbuf_addf(&msg, "%s: %s ", branch_name, head_short_sha1); pp_commit_easy(CMIT_FMT_ONELINE, head_commit, &msg); strbuf_addf(&commit_tree_label, "index on %s\n", msg.buf); commit_list_insert(head_commit, &parents); if (write_cache_as_tree(&info->i_tree, 0, NULL) || commit_tree(commit_tree_label.buf, commit_tree_label.len, &info->i_tree, parents, &info->i_commit, NULL, NULL)) { if (!quiet) fprintf_ln(stderr, _("Cannot save the current " "index state")); ret = -1; goto done; } if (include_untracked) { if (save_untracked_files(info, &msg, untracked_files)) { if (!quiet) fprintf_ln(stderr, _("Cannot save " "the untracked files")); ret = -1; goto done; } untracked_commit_option = 1; } if (patch_mode) { ret = stash_patch(info, ps, patch, quiet); if (ret < 0) { if (!quiet) fprintf_ln(stderr, _("Cannot save the current " "worktree state")); goto done; } else if (ret > 0) { goto done; } } else { if (stash_working_tree(info, ps)) { if (!quiet) fprintf_ln(stderr, _("Cannot save the current " "worktree state")); ret = -1; goto done; } } if (!stash_msg_buf->len) strbuf_addf(stash_msg_buf, "WIP on %s", msg.buf); else strbuf_insertf(stash_msg_buf, 0, "On %s: ", branch_name); /* * `parents` will be empty after calling `commit_tree()`, so there is * no need to call `free_commit_list()` */ parents = NULL; if (untracked_commit_option) commit_list_insert(lookup_commit(the_repository, &info->u_commit), &parents); commit_list_insert(lookup_commit(the_repository, &info->i_commit), &parents); commit_list_insert(head_commit, &parents); if (commit_tree(stash_msg_buf->buf, stash_msg_buf->len, &info->w_tree, parents, &info->w_commit, NULL, NULL)) { if (!quiet) fprintf_ln(stderr, _("Cannot record " "working tree state")); ret = -1; goto done; } done: strbuf_release(&commit_tree_label); strbuf_release(&msg); strbuf_release(&untracked_files); return ret; }
static int do_apply_stash(const char *prefix, struct stash_info *info, int index, int quiet) { int ret; int has_index = index; struct merge_options o; struct object_id c_tree; struct object_id index_tree; struct commit *result; const struct object_id *bases[1]; read_cache_preload(NULL); if (refresh_cache(REFRESH_QUIET)) return -1; if (write_cache_as_tree(&c_tree, 0, NULL)) return error(_("cannot apply a stash in the middle of a merge")); if (index) { if (oideq(&info->b_tree, &info->i_tree) || oideq(&c_tree, &info->i_tree)) { has_index = 0; } else { struct strbuf out = STRBUF_INIT; if (diff_tree_binary(&out, &info->w_commit)) { strbuf_release(&out); return error(_("could not generate diff %s^!."), oid_to_hex(&info->w_commit)); } ret = apply_cached(&out); strbuf_release(&out); if (ret) return error(_("conflicts in index." "Try without --index.")); discard_cache(); read_cache(); if (write_cache_as_tree(&index_tree, 0, NULL)) return error(_("could not save index tree")); reset_head(); } } if (info->has_u && restore_untracked(&info->u_tree)) return error(_("could not restore untracked files from stash")); init_merge_options(&o, the_repository); o.branch1 = "Updated upstream"; o.branch2 = "Stashed changes"; if (oideq(&info->b_tree, &c_tree)) o.branch1 = "Version stash was based on"; if (quiet) o.verbosity = 0; if (o.verbosity >= 3) printf_ln(_("Merging %s with %s"), o.branch1, o.branch2); bases[0] = &info->b_tree; ret = merge_recursive_generic(&o, &c_tree, &info->w_tree, 1, bases, &result); if (ret) { rerere(0); if (index) fprintf_ln(stderr, _("Index was not unstashed.")); return ret; } if (has_index) { if (reset_tree(&index_tree, 0, 0)) return -1; } else { struct strbuf out = STRBUF_INIT; if (get_newly_staged(&out, &c_tree)) { strbuf_release(&out); return -1; } if (reset_tree(&c_tree, 0, 1)) { strbuf_release(&out); return -1; } ret = update_index(&out); strbuf_release(&out); if (ret) return -1; discard_cache(); } if (quiet) { if (refresh_cache(REFRESH_QUIET)) warning("could not refresh index"); } else { struct child_process cp = CHILD_PROCESS_INIT; /* * Status is quite simple and could be replaced with calls to * wt_status in the future, but it adds complexities which may * require more tests. */ cp.git_cmd = 1; cp.dir = prefix; argv_array_push(&cp.args, "status"); run_command(&cp); } return 0; }
static int get_stash_info(struct stash_info *info, int argc, const char **argv) { int ret; char *end_of_rev; char *expanded_ref; const char *revision; const char *commit = NULL; struct object_id dummy; struct strbuf symbolic = STRBUF_INIT; if (argc > 1) { int i; struct strbuf refs_msg = STRBUF_INIT; for (i = 0; i < argc; i++) strbuf_addf(&refs_msg, " '%s'", argv[i]); fprintf_ln(stderr, _("Too many revisions specified:%s"), refs_msg.buf); strbuf_release(&refs_msg); return -1; } if (argc == 1) commit = argv[0]; strbuf_init(&info->revision, 0); if (!commit) { if (!ref_exists(ref_stash)) { free_stash_info(info); fprintf_ln(stderr, _("No stash entries found.")); return -1; } strbuf_addf(&info->revision, "%s@{0}", ref_stash); } else if (strspn(commit, "0123456789") == strlen(commit)) { strbuf_addf(&info->revision, "%s@{%s}", ref_stash, commit); } else { strbuf_addstr(&info->revision, commit); } revision = info->revision.buf; if (get_oid(revision, &info->w_commit)) { error(_("%s is not a valid reference"), revision); free_stash_info(info); return -1; } assert_stash_like(info, revision); info->has_u = !get_oidf(&info->u_tree, "%s^3:", revision); end_of_rev = strchrnul(revision, '@'); strbuf_add(&symbolic, revision, end_of_rev - revision); ret = dwim_ref(symbolic.buf, symbolic.len, &dummy, &expanded_ref); strbuf_release(&symbolic); switch (ret) { case 0: /* Not found, but valid ref */ info->is_stash_ref = 0; break; case 1: info->is_stash_ref = !strcmp(expanded_ref, ref_stash); break; default: /* Invalid or ambiguous */ free_stash_info(info); } free(expanded_ref); return !(ret == 0 || ret == 1); }
static int do_push_stash(struct pathspec ps, const char *stash_msg, int quiet, int keep_index, int patch_mode, int include_untracked) { int ret = 0; struct stash_info info; struct strbuf patch = STRBUF_INIT; struct strbuf stash_msg_buf = STRBUF_INIT; struct strbuf untracked_files = STRBUF_INIT; if (patch_mode && keep_index == -1) keep_index = 1; if (patch_mode && include_untracked) { fprintf_ln(stderr, _("Can't use --patch and --include-untracked" " or --all at the same time")); ret = -1; goto done; } read_cache_preload(NULL); if (!include_untracked && ps.nr) { int i; char *ps_matched = xcalloc(ps.nr, 1); for (i = 0; i < active_nr; i++) ce_path_match(&the_index, active_cache[i], &ps, ps_matched); if (report_path_error(ps_matched, &ps, NULL)) { fprintf_ln(stderr, _("Did you forget to 'git add'?")); ret = -1; free(ps_matched); goto done; } free(ps_matched); } if (refresh_cache(REFRESH_QUIET)) { ret = -1; goto done; } if (!check_changes(ps, include_untracked, &untracked_files)) { if (!quiet) printf_ln(_("No local changes to save")); goto done; } if (!reflog_exists(ref_stash) && do_clear_stash()) { ret = -1; if (!quiet) fprintf_ln(stderr, _("Cannot initialize stash")); goto done; } if (stash_msg) strbuf_addstr(&stash_msg_buf, stash_msg); if (do_create_stash(ps, &stash_msg_buf, include_untracked, patch_mode, &info, &patch, quiet)) { ret = -1; goto done; } if (do_store_stash(&info.w_commit, stash_msg_buf.buf, 1)) { ret = -1; if (!quiet) fprintf_ln(stderr, _("Cannot save the current status")); goto done; } if (!quiet) printf_ln(_("Saved working directory and index state %s"), stash_msg_buf.buf); if (!patch_mode) { if (include_untracked && !ps.nr) { struct child_process cp = CHILD_PROCESS_INIT; cp.git_cmd = 1; argv_array_pushl(&cp.args, "clean", "--force", "--quiet", "-d", NULL); if (include_untracked == INCLUDE_ALL_FILES) argv_array_push(&cp.args, "-x"); if (run_command(&cp)) { ret = -1; goto done; } } discard_cache(); if (ps.nr) { struct child_process cp_add = CHILD_PROCESS_INIT; struct child_process cp_diff = CHILD_PROCESS_INIT; struct child_process cp_apply = CHILD_PROCESS_INIT; struct strbuf out = STRBUF_INIT; cp_add.git_cmd = 1; argv_array_push(&cp_add.args, "add"); if (!include_untracked) argv_array_push(&cp_add.args, "-u"); if (include_untracked == INCLUDE_ALL_FILES) argv_array_push(&cp_add.args, "--force"); argv_array_push(&cp_add.args, "--"); add_pathspecs(&cp_add.args, ps); if (run_command(&cp_add)) { ret = -1; goto done; } cp_diff.git_cmd = 1; argv_array_pushl(&cp_diff.args, "diff-index", "-p", "--cached", "--binary", "HEAD", "--", NULL); add_pathspecs(&cp_diff.args, ps); if (pipe_command(&cp_diff, NULL, 0, &out, 0, NULL, 0)) { ret = -1; goto done; } cp_apply.git_cmd = 1; argv_array_pushl(&cp_apply.args, "apply", "--index", "-R", NULL); if (pipe_command(&cp_apply, out.buf, out.len, NULL, 0, NULL, 0)) { ret = -1; goto done; } } else { struct child_process cp = CHILD_PROCESS_INIT; cp.git_cmd = 1; argv_array_pushl(&cp.args, "reset", "--hard", "-q", NULL); if (run_command(&cp)) { ret = -1; goto done; } } if (keep_index == 1 && !is_null_oid(&info.i_tree)) { struct child_process cp_ls = CHILD_PROCESS_INIT; struct child_process cp_checkout = CHILD_PROCESS_INIT; struct strbuf out = STRBUF_INIT; if (reset_tree(&info.i_tree, 0, 1)) { ret = -1; goto done; } cp_ls.git_cmd = 1; argv_array_pushl(&cp_ls.args, "ls-files", "-z", "--modified", "--", NULL); add_pathspecs(&cp_ls.args, ps); if (pipe_command(&cp_ls, NULL, 0, &out, 0, NULL, 0)) { ret = -1; goto done; } cp_checkout.git_cmd = 1; argv_array_pushl(&cp_checkout.args, "checkout-index", "-z", "--force", "--stdin", NULL); if (pipe_command(&cp_checkout, out.buf, out.len, NULL, 0, NULL, 0)) { ret = -1; goto done; } } goto done; } else { struct child_process cp = CHILD_PROCESS_INIT; cp.git_cmd = 1; argv_array_pushl(&cp.args, "apply", "-R", NULL); if (pipe_command(&cp, patch.buf, patch.len, NULL, 0, NULL, 0)) { if (!quiet) fprintf_ln(stderr, _("Cannot remove " "worktree changes")); ret = -1; goto done; } if (keep_index < 1) { struct child_process cp = CHILD_PROCESS_INIT; discard_cache(); cp.git_cmd = 1; argv_array_pushl(&cp.args, "reset", "-q", "--", NULL); add_pathspecs(&cp.args, ps); if (run_command(&cp)) { ret = -1; goto done; } } goto done; } done: strbuf_release(&stash_msg_buf); return ret; }
static int usage_with_options_internal(struct parse_opt_ctx_t *ctx, const char * const *usagestr, const struct option *opts, int full, int err) { FILE *outfile = err ? stderr : stdout; if (!usagestr) return PARSE_OPT_HELP; if (!err && ctx && ctx->flags & PARSE_OPT_SHELL_EVAL) fprintf(outfile, "cat <<\\EOF\n"); fprintf_ln(outfile, _("usage: %s"), _(*usagestr++)); while (*usagestr && **usagestr) /* TRANSLATORS: the colon here should align with the one in "usage: %s" translation */ fprintf_ln(outfile, _(" or: %s"), _(*usagestr++)); while (*usagestr) { if (**usagestr) fprintf_ln(outfile, _(" %s"), _(*usagestr)); else putchar('\n'); usagestr++; } if (opts->type != OPTION_GROUP) fputc('\n', outfile); for (; opts->type != OPTION_END; opts++) { size_t pos; int pad; if (opts->type == OPTION_GROUP) { fputc('\n', outfile); if (*opts->help) fprintf(outfile, "%s\n", _(opts->help)); continue; } if (!full && (opts->flags & PARSE_OPT_HIDDEN)) continue; pos = fprintf(outfile, " "); if (opts->short_name) { if (opts->flags & PARSE_OPT_NODASH) pos += fprintf(outfile, "%c", opts->short_name); else pos += fprintf(outfile, "-%c", opts->short_name); } if (opts->long_name && opts->short_name) pos += fprintf(outfile, ", "); if (opts->long_name) pos += fprintf(outfile, "--%s", opts->long_name); if (opts->type == OPTION_NUMBER) pos += utf8_fprintf(outfile, _("-NUM")); if ((opts->flags & PARSE_OPT_LITERAL_ARGHELP) || !(opts->flags & PARSE_OPT_NOARG)) pos += usage_argh(opts, outfile); if (pos <= USAGE_OPTS_WIDTH) pad = USAGE_OPTS_WIDTH - pos; else { fputc('\n', outfile); pad = USAGE_OPTS_WIDTH; } fprintf(outfile, "%*s%s\n", pad + USAGE_GAP, "", _(opts->help)); } fputc('\n', outfile); if (!err && ctx && ctx->flags & PARSE_OPT_SHELL_EVAL) fputs("EOF\n", outfile); return PARSE_OPT_HELP; }
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; 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(&the_index, 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, &nr_checkouts); continue; } if (opts->writeout_stage) errs |= checkout_stage(opts->writeout_stage, ce, pos, &state, &nr_checkouts); else if (opts->merge) errs |= checkout_merged(pos, &state, &nr_checkouts); pos = skip_same_name(ce, pos) - 1; } } errs |= finish_delayed_checkout(&state, &nr_checkouts); if (opts->count_checkout_paths) { if (opts->source_tree) fprintf_ln(stderr, Q_("Checked out %d path out of %s", "Checked out %d paths out of %s", nr_checkouts), nr_checkouts, find_unique_abbrev(&opts->source_tree->object.oid, DEFAULT_ABBREV)); else fprintf_ln(stderr, Q_("Checked out %d path out of the index", "Checked out %d paths out of 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; }