static int try_merge_strategy(const char *strategy, struct commit_list *common, const char *head_arg) { int index_fd; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); index_fd = hold_locked_index(lock, 1); refresh_cache(REFRESH_QUIET); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) return error(_("Unable to write index.")); rollback_lock_file(lock); if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) { int clean, x; struct commit *result; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); int index_fd; struct commit_list *reversed = NULL; struct merge_options o; struct commit_list *j; if (remoteheads->next) { error(_("Not handling anything other than two heads merge.")); return 2; } init_merge_options(&o); if (!strcmp(strategy, "subtree")) o.subtree_shift = ""; o.renormalize = option_renormalize; o.show_rename_progress = show_progress == -1 ? isatty(2) : show_progress; for (x = 0; x < xopts_nr; x++) if (parse_merge_opt(&o, xopts[x])) die(_("Unknown option for merge-recursive: -X%s"), xopts[x]); o.branch1 = head_arg; o.branch2 = remoteheads->item->util; for (j = common; j; j = j->next) commit_list_insert(j->item, &reversed); index_fd = hold_locked_index(lock, 1); clean = merge_recursive(&o, lookup_commit(head), remoteheads->item, reversed, &result); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) die (_("unable to write %s"), get_index_file()); rollback_lock_file(lock); return clean ? 0 : 1; } else { return try_merge_command(strategy, xopts_nr, xopts, common, head_arg, remoteheads); } }
int merge_recursive_generic(struct merge_options *o, const unsigned char *head, const unsigned char *merge, int num_base_list, const unsigned char **base_list, struct commit **result) { int clean, index_fd; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); struct commit *head_commit = get_ref(head, o->branch1); struct commit *next_commit = get_ref(merge, o->branch2); struct commit_list *ca = NULL; if (base_list) { int i; for (i = 0; i < num_base_list; ++i) { struct commit *base; if (!(base = get_ref(base_list[i], sha1_to_hex(base_list[i])))) return error("Could not parse object '%s'", sha1_to_hex(base_list[i])); commit_list_insert(base, &ca); } } index_fd = hold_locked_index(lock, 1); clean = merge_recursive(o, head_commit, next_commit, ca, result); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) return error("Unable to write index."); return clean ? 0 : 1; }
static int checkout(void) { unsigned char sha1[20]; char *head; struct lock_file *lock_file; struct unpack_trees_options opts; struct tree *tree; struct tree_desc t; int err = 0, fd; if (option_no_checkout) return 0; head = resolve_refdup("HEAD", sha1, 1, NULL); if (!head) { warning(_("remote HEAD refers to nonexistent ref, " "unable to checkout.\n")); return 0; } if (!strcmp(head, "HEAD")) { if (advice_detached_head) detach_advice(sha1_to_hex(sha1)); } else { if (prefixcmp(head, "refs/heads/")) die(_("HEAD not found below refs/heads!")); } free(head); /* We need to be in the new work tree for the checkout */ setup_work_tree(); lock_file = xcalloc(1, sizeof(struct lock_file)); fd = hold_locked_index(lock_file, 1); memset(&opts, 0, sizeof opts); opts.update = 1; opts.merge = 1; opts.fn = oneway_merge; opts.verbose_update = (option_verbosity >= 0); opts.src_index = &the_index; opts.dst_index = &the_index; tree = parse_tree_indirect(sha1); parse_tree(tree); init_tree_desc(&t, tree->buffer, tree->size); if (unpack_trees(1, &t, &opts) < 0) die(_("unable to checkout working tree")); if (write_cache(fd, active_cache, active_nr) || commit_locked_index(lock_file)) die(_("unable to write new index file")); err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1), sha1_to_hex(sha1), "1", NULL); if (!err && option_recursive) err = run_command_v_opt(argv_submodule, RUN_GIT_CMD); return err; }
static int do_recursive_merge(struct commit *base, struct commit *next, const char *base_label, const char *next_label, unsigned char *head, struct strbuf *msgbuf, struct replay_opts *opts) { struct merge_options o; struct tree *result, *next_tree, *base_tree, *head_tree; int clean, index_fd; const char **xopt; static struct lock_file index_lock; index_fd = hold_locked_index(&index_lock, 1); read_cache(); init_merge_options(&o); o.ancestor = base ? base_label : "(empty tree)"; o.branch1 = "HEAD"; o.branch2 = next ? next_label : "(empty tree)"; head_tree = parse_tree_indirect(head); next_tree = next ? next->tree : empty_tree(); base_tree = base ? base->tree : empty_tree(); for (xopt = opts->xopts; xopt != opts->xopts + opts->xopts_nr; xopt++) parse_merge_opt(&o, *xopt); clean = merge_trees(&o, head_tree, next_tree, base_tree, &result); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(&index_lock))) /* TRANSLATORS: %s will be "revert" or "cherry-pick" */ die(_("%s: Unable to write new index file"), action_name(opts)); rollback_lock_file(&index_lock); if (opts->signoff) append_signoff(msgbuf, 0, 0); if (!clean) { int i; strbuf_addstr(msgbuf, "\nConflicts:\n"); for (i = 0; i < active_nr;) { const struct cache_entry *ce = active_cache[i++]; if (ce_stage(ce)) { strbuf_addch(msgbuf, '\t'); strbuf_addstr(msgbuf, ce->name); strbuf_addch(msgbuf, '\n'); while (i < active_nr && !strcmp(ce->name, active_cache[i]->name)) i++; } } } return !clean; }
static void do_recursive_merge(struct commit *base, struct commit *next, const char *base_label, const char *next_label, unsigned char *head, struct strbuf *msgbuf, char *defmsg) { struct merge_options o; struct tree *result, *next_tree, *base_tree, *head_tree; int clean, index_fd; static struct lock_file index_lock; index_fd = hold_locked_index(&index_lock, 1); read_cache(); init_merge_options(&o); o.ancestor = base ? base_label : "(empty tree)"; o.branch1 = "HEAD"; o.branch2 = next ? next_label : "(empty tree)"; head_tree = parse_tree_indirect(head); next_tree = next ? next->tree : empty_tree(); base_tree = base ? base->tree : empty_tree(); clean = merge_trees(&o, head_tree, next_tree, base_tree, &result); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(&index_lock))) die("%s: Unable to write new index file", me); rollback_lock_file(&index_lock); if (!clean) { int i; strbuf_addstr(msgbuf, "\nConflicts:\n\n"); for (i = 0; i < active_nr;) { struct cache_entry *ce = active_cache[i++]; if (ce_stage(ce)) { strbuf_addch(msgbuf, '\t'); strbuf_addstr(msgbuf, ce->name); strbuf_addch(msgbuf, '\n'); while (i < active_nr && !strcmp(ce->name, active_cache[i]->name)) i++; } } write_message(msgbuf, defmsg); fprintf(stderr, "Automatic %s failed.%s\n", me, help_msg()); rerere(allow_rerere_auto); exit(1); } write_message(msgbuf, defmsg); fprintf(stderr, "Finished one %s.\n", me); }
static int reset_index_file(const unsigned char *sha1, int reset_type, int quiet) { int nr = 1; int newfd; struct tree_desc desc[2]; struct unpack_trees_options opts; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); memset(&opts, 0, sizeof(opts)); opts.head_idx = 1; opts.src_index = &the_index; opts.dst_index = &the_index; opts.fn = oneway_merge; opts.merge = 1; if (!quiet) opts.verbose_update = 1; switch (reset_type) { case KEEP: case MERGE: opts.update = 1; break; case HARD: opts.update = 1; /* fallthrough */ default: opts.reset = 1; } newfd = hold_locked_index(lock, 1); read_cache_unmerged(); if (reset_type == KEEP) { unsigned char head_sha1[20]; if (get_sha1("HEAD", head_sha1)) return error(_("You do not have a valid HEAD.")); if (!fill_tree_descriptor(desc, head_sha1)) return error(_("Failed to find tree of HEAD.")); nr++; opts.fn = twoway_merge; } if (!fill_tree_descriptor(desc + nr - 1, sha1)) return error(_("Failed to find tree of %s."), sha1_to_hex(sha1)); if (unpack_trees(nr, desc, &opts)) return -1; if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(lock)) return error(_("Could not write new index file.")); return 0; }
static void read_and_refresh_cache(struct replay_opts *opts) { static struct lock_file index_lock; int index_fd = hold_locked_index(&index_lock, 0); if (read_index_preload(&the_index, NULL) < 0) die(_("git %s: failed to read the index"), action_name(opts)); refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL); if (the_index.cache_changed) { if (write_index(&the_index, index_fd) || commit_locked_index(&index_lock)) die(_("git %s: failed to refresh the index"), action_name(opts)); } rollback_lock_file(&index_lock); }
static void read_and_refresh_cache(const char *me) { static struct lock_file index_lock; int index_fd = hold_locked_index(&index_lock, 0); if (read_index_preload(&the_index, NULL) < 0) die("git %s: failed to read the index", me); refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL); if (the_index.cache_changed) { if (write_index(&the_index, index_fd) || commit_locked_index(&index_lock)) die("git %s: failed to refresh the index", me); } rollback_lock_file(&index_lock); }
int checkout_fast_forward(const unsigned char *head, const unsigned char *remote) { struct tree *trees[MAX_UNPACK_TREES]; struct unpack_trees_options opts; struct tree_desc t[MAX_UNPACK_TREES]; int i, fd, nr_trees = 0; struct dir_struct dir; struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); refresh_cache(REFRESH_QUIET); fd = hold_locked_index(lock_file, 1); memset(&trees, 0, sizeof(trees)); memset(&opts, 0, sizeof(opts)); memset(&t, 0, sizeof(t)); if (overwrite_ignore) { memset(&dir, 0, sizeof(dir)); dir.flags |= DIR_SHOW_IGNORED; setup_standard_excludes(&dir); opts.dir = &dir; } opts.head_idx = 1; opts.src_index = &the_index; opts.dst_index = &the_index; opts.update = 1; opts.verbose_update = 1; opts.merge = 1; opts.fn = twoway_merge; setup_unpack_trees_porcelain(&opts, "merge"); trees[nr_trees] = parse_tree_indirect(head); if (!trees[nr_trees++]) return -1; trees[nr_trees] = parse_tree_indirect(remote); if (!trees[nr_trees++]) return -1; for (i = 0; i < nr_trees; i++) { parse_tree(trees[i]); init_tree_desc(t+i, trees[i]->buffer, trees[i]->size); } if (unpack_trees(nr_trees, t, &opts)) return -1; if (write_cache(fd, active_cache, active_nr) || commit_locked_index(lock_file)) die(_("unable to write new index file")); return 0; }
static int checkout_fast_forward(unsigned char *head, unsigned char *remote) { struct tree *trees[MAX_UNPACK_TREES]; struct unpack_trees_options opts; struct tree_desc t[MAX_UNPACK_TREES]; int i, fd, nr_trees = 0; struct dir_struct dir; struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); if (read_cache_unmerged()) die("you need to resolve your current index first"); fd = hold_locked_index(lock_file, 1); memset(&trees, 0, sizeof(trees)); memset(&opts, 0, sizeof(opts)); memset(&t, 0, sizeof(t)); dir.show_ignored = 1; dir.exclude_per_dir = ".gitignore"; opts.dir = &dir; opts.head_idx = 1; opts.src_index = &the_index; opts.dst_index = &the_index; opts.update = 1; opts.verbose_update = 1; opts.merge = 1; opts.fn = twoway_merge; trees[nr_trees] = parse_tree_indirect(head); if (!trees[nr_trees++]) return -1; trees[nr_trees] = parse_tree_indirect(remote); if (!trees[nr_trees++]) return -1; for (i = 0; i < nr_trees; i++) { parse_tree(trees[i]); init_tree_desc(t+i, trees[i]->buffer, trees[i]->size); } if (unpack_trees(nr_trees, t, &opts)) return -1; if (write_cache(fd, active_cache, active_nr) || commit_locked_index(lock_file)) die("unable to write new index file"); return 0; }
static int update_index_refresh(int fd, struct lock_file *index_lock, int flags) { int result; if (!index_lock) { index_lock = xcalloc(1, sizeof(struct lock_file)); fd = hold_locked_index(index_lock, 1); } if (read_cache() < 0) return error("Could not read index"); result = refresh_cache(flags) ? 1 : 0; if (write_cache(fd, active_cache, active_nr) || commit_locked_index(index_lock)) return error ("Could not refresh index"); return result; }
static void refresh_index_quietly(void) { struct lock_file *lock_file; int fd; lock_file = xcalloc(1, sizeof(struct lock_file)); fd = hold_locked_index(lock_file, 0); if (fd < 0) return; discard_cache(); read_cache(); refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED); if (active_cache_changed && !write_cache(fd, active_cache, active_nr)) commit_locked_index(lock_file); rollback_lock_file(lock_file); }
static int update_paths(struct string_list *update) { int i; int fd = hold_locked_index(&index_lock, 0); int status = 0; if (fd < 0) return -1; for (i = 0; i < update->nr; i++) { struct string_list_item *item = &update->items[i]; if (add_file_to_cache(item->string, ADD_CACHE_IGNORE_ERRORS)) status = -1; } if (!status && active_cache_changed) { if (write_cache(fd, active_cache, active_nr) || commit_locked_index(&index_lock)) die("Unable to write new index file"); } else if (fd >= 0) rollback_lock_file(&index_lock); return status; }
int cmd_merge_recursive(int argc, const char **argv, const char *prefix) { static const char *bases[20]; static unsigned bases_count = 0; int i, clean; const char *branch1, *branch2; struct commit *result, *h1, *h2; struct commit_list *ca = NULL; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); int index_fd; if (argv[0]) { int namelen = strlen(argv[0]); if (8 < namelen && !strcmp(argv[0] + namelen - 8, "-subtree")) subtree_merge = 1; } git_config(merge_config, NULL); if (getenv("GIT_MERGE_VERBOSITY")) verbosity = strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10); if (argc < 4) die("Usage: %s <base>... -- <head> <remote> ...\n", argv[0]); for (i = 1; i < argc; ++i) { if (!strcmp(argv[i], "--")) break; if (bases_count < sizeof(bases)/sizeof(*bases)) bases[bases_count++] = argv[i]; } if (argc - i != 3) /* "--" "<head>" "<remote>" */ die("Not handling anything other than two heads merge."); if (verbosity >= 5) buffer_output = 0; branch1 = argv[++i]; branch2 = argv[++i]; h1 = get_ref(branch1); h2 = get_ref(branch2); branch1 = better_branch_name(branch1); branch2 = better_branch_name(branch2); if (show(3)) printf("Merging %s with %s\n", branch1, branch2); index_fd = hold_locked_index(lock, 1); for (i = 0; i < bases_count; i++) { struct commit *ancestor = get_ref(bases[i]); ca = commit_list_insert(ancestor, &ca); } clean = merge_recursive(h1, h2, branch1, branch2, ca, &result); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) die ("unable to write %s", get_index_file()); return clean ? 0: 1; }
int cmd_rm(int argc, const char **argv, const char *prefix) { int i, newfd; const char **pathspec; char *seen; git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, builtin_rm_options, builtin_rm_usage, 0); if (!argc) usage_with_options(builtin_rm_usage, builtin_rm_options); if (!index_only) setup_work_tree(); newfd = hold_locked_index(&lock_file, 1); if (read_cache() < 0) die(_("index file corrupt")); /* * Drop trailing directory separators from directories so we'll find * submodules in the index. */ for (i = 0; i < argc; i++) { size_t pathlen = strlen(argv[i]); if (pathlen && is_dir_sep(argv[i][pathlen - 1]) && is_directory(argv[i])) { do { pathlen--; } while (pathlen && is_dir_sep(argv[i][pathlen - 1])); argv[i] = xmemdupz(argv[i], pathlen); } } pathspec = get_pathspec(prefix, argv); refresh_index(&the_index, REFRESH_QUIET, pathspec, NULL, NULL); seen = NULL; for (i = 0; pathspec[i] ; i++) /* nothing */; seen = xcalloc(i, 1); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen)) continue; ALLOC_GROW(list.entry, list.nr + 1, list.alloc); list.entry[list.nr].name = ce->name; list.entry[list.nr++].is_submodule = S_ISGITLINK(ce->ce_mode); } if (pathspec) { const char *match; int seen_any = 0; for (i = 0; (match = pathspec[i]) != NULL ; i++) { if (!seen[i]) { if (!ignore_unmatch) { die(_("pathspec '%s' did not match any files"), match); } } else { seen_any = 1; } if (!recursive && seen[i] == MATCHED_RECURSIVELY) die(_("not removing '%s' recursively without -r"), *match ? match : "."); } if (! seen_any) exit(0); } /* * If not forced, the file, the index and the HEAD (if exists) * must match; but the file can already been removed, since * this sequence is a natural "novice" way: * * rm F; git rm F * * Further, if HEAD commit exists, "diff-index --cached" must * report no changes unless forced. */ if (!force) { unsigned char sha1[20]; if (get_sha1("HEAD", sha1)) hashclr(sha1); if (check_local_mod(sha1, index_only)) exit(1); } else if (!index_only) { if (check_submodules_use_gitfiles()) exit(1); } /* * First remove the names from the index: we won't commit * the index unless all of them succeed. */ for (i = 0; i < list.nr; i++) { const char *path = list.entry[i].name; if (!quiet) printf("rm '%s'\n", path); if (remove_file_from_cache(path)) die(_("git rm: unable to remove %s"), path); } if (show_only) return 0; /* * Then, unless we used "--cached", remove the filenames from * the workspace. If we fail to remove the first one, we * abort the "git rm" (but once we've successfully removed * any file at all, we'll go ahead and commit to it all: * by then we've already committed ourselves and can't fail * in the middle) */ if (!index_only) { int removed = 0; for (i = 0; i < list.nr; i++) { const char *path = list.entry[i].name; if (list.entry[i].is_submodule) { if (is_empty_dir(path)) { if (!rmdir(path)) { removed = 1; continue; } } else { struct strbuf buf = STRBUF_INIT; strbuf_addstr(&buf, path); if (!remove_dir_recursively(&buf, 0)) { removed = 1; strbuf_release(&buf); continue; } strbuf_release(&buf); /* Fallthrough and let remove_path() fail. */ } } if (!remove_path(path)) { removed = 1; continue; } if (!removed) die_errno("git rm: '%s'", path); } } if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) die(_("Unable to write new index file")); } return 0; }
int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) { int i, newfd, stage = 0; unsigned char sha1[20]; struct tree_desc t[MAX_UNPACK_TREES]; struct unpack_trees_options opts; int prefix_set = 0; const struct option read_tree_options[] = { { OPTION_CALLBACK, 0, "index-output", NULL, N_("file"), N_("write resulting index to <file>"), PARSE_OPT_NONEG, index_output_cb }, OPT_SET_INT(0, "empty", &read_empty, N_("only empty the index"), 1), OPT__VERBOSE(&opts.verbose_update, N_("be verbose")), OPT_GROUP(N_("Merging")), OPT_SET_INT('m', NULL, &opts.merge, N_("perform a merge in addition to a read"), 1), OPT_SET_INT(0, "trivial", &opts.trivial_merges_only, N_("3-way merge if no file level merging required"), 1), OPT_SET_INT(0, "aggressive", &opts.aggressive, N_("3-way merge in presence of adds and removes"), 1), OPT_SET_INT(0, "reset", &opts.reset, N_("same as -m, but discard unmerged entries"), 1), { OPTION_STRING, 0, "prefix", &opts.prefix, N_("<subdirectory>/"), N_("read the tree into the index under <subdirectory>/"), PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP }, OPT_SET_INT('u', NULL, &opts.update, N_("update working tree with merge result"), 1), { OPTION_CALLBACK, 0, "exclude-per-directory", &opts, N_("gitignore"), N_("allow explicitly ignored files to be overwritten"), PARSE_OPT_NONEG, exclude_per_directory_cb }, OPT_SET_INT('i', NULL, &opts.index_only, N_("don't check the working tree after merging"), 1), OPT__DRY_RUN(&opts.dry_run, N_("don't update the index or the work tree")), OPT_SET_INT(0, "no-sparse-checkout", &opts.skip_sparse_checkout, N_("skip applying sparse checkout filter"), 1), OPT_SET_INT(0, "debug-unpack", &opts.debug_unpack, N_("debug unpack-trees"), 1), OPT_END() }; memset(&opts, 0, sizeof(opts)); opts.head_idx = -1; opts.src_index = &the_index; opts.dst_index = &the_index; git_config(git_default_config, NULL); argc = parse_options(argc, argv, unused_prefix, read_tree_options, read_tree_usage, 0); newfd = hold_locked_index(&lock_file, 1); prefix_set = opts.prefix ? 1 : 0; if (1 < opts.merge + opts.reset + prefix_set) die("Which one? -m, --reset, or --prefix?"); if (opts.reset || opts.merge || opts.prefix) { if (read_cache_unmerged() && (opts.prefix || opts.merge)) die("You need to resolve your current index first"); stage = opts.merge = 1; } resolve_undo_clear(); for (i = 0; i < argc; i++) { const char *arg = argv[i]; if (get_sha1(arg, sha1)) die("Not a valid object name %s", arg); if (list_tree(sha1) < 0) die("failed to unpack tree object %s", arg); stage++; } if (nr_trees == 0 && !read_empty) warning("read-tree: emptying the index with no arguments is deprecated; use --empty"); else if (nr_trees > 0 && read_empty) die("passing trees as arguments contradicts --empty"); if (1 < opts.index_only + opts.update) die("-u and -i at the same time makes no sense"); if ((opts.update||opts.index_only) && !opts.merge) die("%s is meaningless without -m, --reset, or --prefix", opts.update ? "-u" : "-i"); if ((opts.dir && !opts.update)) die("--exclude-per-directory is meaningless unless -u"); if (opts.merge && !opts.index_only) setup_work_tree(); if (opts.merge) { if (stage < 2) die("just how do you expect me to merge %d trees?", stage-1); switch (stage - 1) { case 1: opts.fn = opts.prefix ? bind_merge : oneway_merge; break; case 2: opts.fn = twoway_merge; opts.initial_checkout = is_cache_unborn(); break; case 3: default: opts.fn = threeway_merge; break; } if (stage - 1 >= 3) opts.head_idx = stage - 2; else opts.head_idx = 1; } if (opts.debug_unpack) opts.fn = debug_merge; cache_tree_free(&active_cache_tree); for (i = 0; i < nr_trees; i++) { struct tree *tree = trees[i]; parse_tree(tree); init_tree_desc(t+i, tree->buffer, tree->size); } if (unpack_trees(nr_trees, t, &opts)) return 128; if (opts.debug_unpack || opts.dry_run) return 0; /* do not write the index out */ /* * When reading only one tree (either the most basic form, * "-m ent" or "--reset ent" form), we can obtain a fully * valid cache-tree because the index must match exactly * what came from the tree. */ if (nr_trees == 1 && !opts.prefix) prime_cache_tree(&active_cache_tree, trees[0]); if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) die("unable to write new index file"); return 0; }
int cmd_add(int argc, const char **argv, const char *prefix) { int exit_status = 0; int newfd; const char **pathspec; struct dir_struct dir; int flags; int add_new_files; int require_pathspec; char *seen = NULL; git_config(add_config, NULL); argc = parse_options(argc, argv, prefix, builtin_add_options, builtin_add_usage, PARSE_OPT_KEEP_ARGV0); if (patch_interactive) add_interactive = 1; if (add_interactive) exit(interactive_add(argc - 1, argv + 1, prefix)); if (edit_interactive) return(edit_patch(argc, argv, prefix)); argc--; argv++; if (addremove && take_worktree_changes) die("-A and -u are mutually incompatible"); if (!show_only && ignore_missing) die("Option --ignore-missing can only be used together with --dry-run"); if ((addremove || take_worktree_changes) && !argc) { static const char *here[2] = { ".", NULL }; argc = 1; argv = here; } add_new_files = !take_worktree_changes && !refresh_only; require_pathspec = !take_worktree_changes; newfd = hold_locked_index(&lock_file, 1); flags = ((verbose ? ADD_CACHE_VERBOSE : 0) | (show_only ? ADD_CACHE_PRETEND : 0) | (intent_to_add ? ADD_CACHE_INTENT : 0) | (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) | (!(addremove || take_worktree_changes) ? ADD_CACHE_IGNORE_REMOVAL : 0)); if (require_pathspec && argc == 0) { fprintf(stderr, "Nothing specified, nothing added.\n"); fprintf(stderr, "Maybe you wanted to say 'git add .'?\n"); return 0; } pathspec = validate_pathspec(argc, argv, prefix); if (read_cache() < 0) die("index file corrupt"); treat_gitlinks(pathspec); if (add_new_files) { int baselen; /* Set up the default git porcelain excludes */ memset(&dir, 0, sizeof(dir)); if (!ignored_too) { dir.flags |= DIR_COLLECT_IGNORED; setup_standard_excludes(&dir); } /* This picks up the paths that are not tracked */ baselen = fill_directory(&dir, pathspec); if (pathspec) seen = prune_directory(&dir, pathspec, baselen); } if (refresh_only) { refresh(verbose, pathspec); goto finish; } if (pathspec) { int i; if (!seen) seen = find_used_pathspec(pathspec); for (i = 0; pathspec[i]; i++) { if (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i])) { if (ignore_missing) { if (excluded(&dir, pathspec[i], DT_UNKNOWN)) dir_add_ignored(&dir, pathspec[i], strlen(pathspec[i])); } else die("pathspec '%s' did not match any files", pathspec[i]); } } free(seen); } exit_status |= add_files_to_cache(prefix, pathspec, flags); if (add_new_files) exit_status |= add_files(&dir, flags); finish: if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) die("Unable to write new index file"); } return exit_status; }
int cmd_mv(int argc, const char **argv, const char *prefix) { int i, newfd, gitmodules_modified = 0; int verbose = 0, show_only = 0, force = 0, ignore_errors = 0; struct option builtin_mv_options[] = { OPT__VERBOSE(&verbose, N_("be verbose")), OPT__DRY_RUN(&show_only, N_("dry run")), OPT__FORCE(&force, N_("force move/rename even if target exists")), OPT_BOOL('k', NULL, &ignore_errors, N_("skip move/rename errors")), OPT_END(), }; const char **source, **destination, **dest_path, **submodule_gitfile; enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes; struct stat st; struct string_list src_for_dst = STRING_LIST_INIT_NODUP; gitmodules_config(); git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, builtin_mv_options, builtin_mv_usage, 0); if (--argc < 1) usage_with_options(builtin_mv_usage, builtin_mv_options); newfd = hold_locked_index(&lock_file, 1); if (read_cache() < 0) die(_("index file corrupt")); source = internal_copy_pathspec(prefix, argv, argc, 0); modes = xcalloc(argc, sizeof(enum update_mode)); /* * Keep trailing slash, needed to let * "git mv file no-such-dir/" error out. */ dest_path = internal_copy_pathspec(prefix, argv + argc, 1, KEEP_TRAILING_SLASH); submodule_gitfile = xcalloc(argc, sizeof(char *)); if (dest_path[0][0] == '\0') /* special case: "." was normalized to "" */ destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME); else if (!lstat(dest_path[0], &st) && S_ISDIR(st.st_mode)) { dest_path[0] = add_slash(dest_path[0]); destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME); } else { if (argc != 1) die("destination '%s' is not a directory", dest_path[0]); destination = dest_path; } /* Checking */ for (i = 0; i < argc; i++) { const char *src = source[i], *dst = destination[i]; int length, src_is_dir; const char *bad = NULL; if (show_only) printf(_("Checking rename of '%s' to '%s'\n"), src, dst); length = strlen(src); if (lstat(src, &st) < 0) bad = _("bad source"); else if (!strncmp(src, dst, length) && (dst[length] == 0 || dst[length] == '/')) { bad = _("can not move directory into itself"); } else if ((src_is_dir = S_ISDIR(st.st_mode)) && lstat(dst, &st) == 0) bad = _("cannot move directory over file"); else if (src_is_dir) { int first = cache_name_pos(src, length); if (first >= 0) { struct strbuf submodule_dotgit = STRBUF_INIT; if (!S_ISGITLINK(active_cache[first]->ce_mode)) die (_("Huh? Directory %s is in index and no submodule?"), src); if (!is_staging_gitmodules_ok()) die (_("Please, stage your changes to .gitmodules or stash them to proceed")); strbuf_addf(&submodule_dotgit, "%s/.git", src); submodule_gitfile[i] = read_gitfile(submodule_dotgit.buf); if (submodule_gitfile[i]) submodule_gitfile[i] = xstrdup(submodule_gitfile[i]); else submodule_gitfile[i] = SUBMODULE_WITH_GITDIR; strbuf_release(&submodule_dotgit); } else { const char *src_w_slash = add_slash(src); int last, len_w_slash = length + 1; modes[i] = WORKING_DIRECTORY; first = cache_name_pos(src_w_slash, len_w_slash); if (first >= 0) die (_("Huh? %.*s is in index?"), len_w_slash, src_w_slash); first = -1 - first; for (last = first; last < active_nr; last++) { const char *path = active_cache[last]->name; if (strncmp(path, src_w_slash, len_w_slash)) break; } free((char *)src_w_slash); if (last - first < 1) bad = _("source directory is empty"); else { int j, dst_len; if (last - first > 0) { source = xrealloc(source, (argc + last - first) * sizeof(char *)); destination = xrealloc(destination, (argc + last - first) * sizeof(char *)); modes = xrealloc(modes, (argc + last - first) * sizeof(enum update_mode)); submodule_gitfile = xrealloc(submodule_gitfile, (argc + last - first) * sizeof(char *)); } dst = add_slash(dst); dst_len = strlen(dst); for (j = 0; j < last - first; j++) { const char *path = active_cache[first + j]->name; source[argc + j] = path; destination[argc + j] = prefix_path(dst, dst_len, path + length + 1); modes[argc + j] = INDEX; submodule_gitfile[argc + j] = NULL; } argc += last - first; } } } else if (cache_name_pos(src, length) < 0) bad = _("not under version control"); else if (lstat(dst, &st) == 0) { bad = _("destination exists"); if (force) { /* * only files can overwrite each other: * check both source and destination */ if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { if (verbose) warning(_("overwriting '%s'"), dst); bad = NULL; } else bad = _("Cannot overwrite"); } } else if (string_list_has_string(&src_for_dst, dst)) bad = _("multiple sources for the same target"); else if (is_dir_sep(dst[strlen(dst) - 1])) bad = _("destination directory does not exist"); else string_list_insert(&src_for_dst, dst); if (bad) { if (ignore_errors) { if (--argc > 0) { memmove(source + i, source + i + 1, (argc - i) * sizeof(char *)); memmove(destination + i, destination + i + 1, (argc - i) * sizeof(char *)); memmove(modes + i, modes + i + 1, (argc - i) * sizeof(enum update_mode)); memmove(submodule_gitfile + i, submodule_gitfile + i + 1, (argc - i) * sizeof(char *)); i--; } } else die (_("%s, source=%s, destination=%s"), bad, src, dst); } } for (i = 0; i < argc; i++) { const char *src = source[i], *dst = destination[i]; enum update_mode mode = modes[i]; int pos; if (show_only || verbose) printf(_("Renaming %s to %s\n"), src, dst); if (!show_only && mode != INDEX) { if (rename(src, dst) < 0 && !ignore_errors) die_errno (_("renaming '%s' failed"), src); if (submodule_gitfile[i]) { if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR) connect_work_tree_and_git_dir(dst, submodule_gitfile[i]); if (!update_path_in_gitmodules(src, dst)) gitmodules_modified = 1; } } if (mode == WORKING_DIRECTORY) continue; pos = cache_name_pos(src, strlen(src)); assert(pos >= 0); if (!show_only) rename_cache_entry_at(pos, dst); } if (gitmodules_modified) stage_updated_gitmodules(); if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) die(_("Unable to write new index file")); } return 0; }
int cmd_add(int argc, const char **argv, const char *prefix) { int exit_status = 0; int newfd; struct pathspec pathspec; struct dir_struct dir; int flags; int add_new_files; int require_pathspec; char *seen = NULL; int implicit_dot = 0; struct update_callback_data update_data; git_config(add_config, NULL); argc = parse_options(argc, argv, prefix, builtin_add_options, builtin_add_usage, PARSE_OPT_KEEP_ARGV0); if (patch_interactive) add_interactive = 1; if (add_interactive) exit(interactive_add(argc - 1, argv + 1, prefix, patch_interactive)); if (edit_interactive) return(edit_patch(argc, argv, prefix)); argc--; argv++; if (0 <= addremove_explicit) addremove = addremove_explicit; else if (take_worktree_changes && ADDREMOVE_DEFAULT) addremove = 0; /* "-u" was given but not "-A" */ if (addremove && take_worktree_changes) die(_("-A and -u are mutually incompatible")); /* * Warn when "git add pathspec..." was given without "-u" or "-A" * and pathspec... covers a removed path. */ memset(&update_data, 0, sizeof(update_data)); if (!take_worktree_changes && addremove_explicit < 0) update_data.warn_add_would_remove = 1; if (!take_worktree_changes && addremove_explicit < 0 && argc) /* * Turn "git add pathspec..." to "git add -A pathspec..." * in Git 2.0 but not yet */ ; /* addremove = 1; */ if (!show_only && ignore_missing) die(_("Option --ignore-missing can only be used together with --dry-run")); if (addremove) { option_with_implicit_dot = "--all"; short_option_with_implicit_dot = "-A"; } if (take_worktree_changes) { option_with_implicit_dot = "--update"; short_option_with_implicit_dot = "-u"; } if (option_with_implicit_dot && !argc) { static const char *here[2] = { ".", NULL }; argc = 1; argv = here; implicit_dot = 1; } add_new_files = !take_worktree_changes && !refresh_only; require_pathspec = !take_worktree_changes; newfd = hold_locked_index(&lock_file, 1); flags = ((verbose ? ADD_CACHE_VERBOSE : 0) | (show_only ? ADD_CACHE_PRETEND : 0) | (intent_to_add ? ADD_CACHE_INTENT : 0) | (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) | (!(addremove || take_worktree_changes) ? ADD_CACHE_IGNORE_REMOVAL : 0)) | (implicit_dot ? ADD_CACHE_IMPLICIT_DOT : 0); if (require_pathspec && argc == 0) { fprintf(stderr, _("Nothing specified, nothing added.\n")); fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n")); return 0; } if (read_cache() < 0) die(_("index file corrupt")); /* * Check the "pathspec '%s' did not match any files" block * below before enabling new magic. */ parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_FULL | PATHSPEC_SYMLINK_LEADING_PATH | PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE, prefix, argv); if (add_new_files) { int baselen; struct pathspec empty_pathspec; /* Set up the default git porcelain excludes */ memset(&dir, 0, sizeof(dir)); if (!ignored_too) { dir.flags |= DIR_COLLECT_IGNORED; setup_standard_excludes(&dir); } memset(&empty_pathspec, 0, sizeof(empty_pathspec)); /* This picks up the paths that are not tracked */ baselen = fill_directory(&dir, implicit_dot ? &empty_pathspec : &pathspec); if (pathspec.nr) seen = prune_directory(&dir, &pathspec, baselen, implicit_dot ? WARN_IMPLICIT_DOT : 0); } if (refresh_only) { refresh(verbose, &pathspec); goto finish; } if (implicit_dot && prefix) refresh_cache(REFRESH_QUIET); if (pathspec.nr) { int i; if (!seen) seen = find_pathspecs_matching_against_index(&pathspec); /* * file_exists() assumes exact match */ GUARD_PATHSPEC(&pathspec, PATHSPEC_FROMTOP | PATHSPEC_LITERAL | PATHSPEC_GLOB | PATHSPEC_ICASE); for (i = 0; i < pathspec.nr; i++) { const char *path = pathspec.items[i].match; if (!seen[i] && ((pathspec.items[i].magic & (PATHSPEC_GLOB | PATHSPEC_ICASE)) || !file_exists(path))) { if (ignore_missing) { int dtype = DT_UNKNOWN; if (is_excluded(&dir, path, &dtype)) dir_add_ignored(&dir, path, pathspec.items[i].len); } else die(_("pathspec '%s' did not match any files"), pathspec.items[i].original); } } free(seen); } plug_bulk_checkin(); if ((flags & ADD_CACHE_IMPLICIT_DOT) && prefix) { /* * Check for modified files throughout the worktree so * update_callback has a chance to warn about changes * outside the cwd. */ update_data.implicit_dot = prefix; update_data.implicit_dot_len = strlen(prefix); free_pathspec(&pathspec); memset(&pathspec, 0, sizeof(pathspec)); } update_data.flags = flags & ~ADD_CACHE_IMPLICIT_DOT; update_files_in_cache(prefix, &pathspec, &update_data); exit_status |= !!update_data.add_errors; if (add_new_files) exit_status |= add_files(&dir, flags); unplug_bulk_checkin(); finish: if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) die(_("Unable to write new index file")); } return exit_status; }
int cmd_rm(int argc, const char **argv, const char *prefix) { int i, newfd; struct pathspec pathspec; char *seen; gitmodules_config(); git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, builtin_rm_options, builtin_rm_usage, 0); if (!argc) usage_with_options(builtin_rm_usage, builtin_rm_options); if (!index_only) setup_work_tree(); newfd = hold_locked_index(&lock_file, 1); if (read_cache() < 0) die(_("index file corrupt")); parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD | PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP, prefix, argv); refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL); seen = xcalloc(pathspec.nr, 1); for (i = 0; i < active_nr; i++) { const struct cache_entry *ce = active_cache[i]; if (!ce_path_match(ce, &pathspec, seen)) continue; ALLOC_GROW(list.entry, list.nr + 1, list.alloc); list.entry[list.nr].name = xstrdup(ce->name); list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode); if (list.entry[list.nr++].is_submodule && !is_staging_gitmodules_ok()) die (_("Please, stage your changes to .gitmodules or stash them to proceed")); } if (pathspec.nr) { const char *original; int seen_any = 0; for (i = 0; i < pathspec.nr; i++) { original = pathspec.items[i].original; if (!seen[i]) { if (!ignore_unmatch) { die(_("pathspec '%s' did not match any files"), original); } } else { seen_any = 1; } if (!recursive && seen[i] == MATCHED_RECURSIVELY) die(_("not removing '%s' recursively without -r"), *original ? original : "."); } if (!seen_any) exit(0); } /* * If not forced, the file, the index and the HEAD (if exists) * must match; but the file can already been removed, since * this sequence is a natural "novice" way: * * rm F; git rm F * * Further, if HEAD commit exists, "diff-index --cached" must * report no changes unless forced. */ if (!force) { unsigned char sha1[20]; if (get_sha1("HEAD", sha1)) hashclr(sha1); if (check_local_mod(sha1, index_only)) exit(1); } else if (!index_only) { if (check_submodules_use_gitfiles()) exit(1); } /* * First remove the names from the index: we won't commit * the index unless all of them succeed. */ for (i = 0; i < list.nr; i++) { const char *path = list.entry[i].name; if (!quiet) printf("rm '%s'\n", path); if (remove_file_from_cache(path)) die(_("git rm: unable to remove %s"), path); } if (show_only) return 0; /* * Then, unless we used "--cached", remove the filenames from * the workspace. If we fail to remove the first one, we * abort the "git rm" (but once we've successfully removed * any file at all, we'll go ahead and commit to it all: * by then we've already committed ourselves and can't fail * in the middle) */ if (!index_only) { int removed = 0, gitmodules_modified = 0; for (i = 0; i < list.nr; i++) { const char *path = list.entry[i].name; if (list.entry[i].is_submodule) { if (is_empty_dir(path)) { if (!rmdir(path)) { removed = 1; if (!remove_path_from_gitmodules(path)) gitmodules_modified = 1; continue; } } else { struct strbuf buf = STRBUF_INIT; strbuf_addstr(&buf, path); if (!remove_dir_recursively(&buf, 0)) { removed = 1; if (!remove_path_from_gitmodules(path)) gitmodules_modified = 1; strbuf_release(&buf); continue; } else if (!file_exists(path)) /* Submodule was removed by user */ if (!remove_path_from_gitmodules(path)) gitmodules_modified = 1; strbuf_release(&buf); /* Fallthrough and let remove_path() fail. */ } } if (!remove_path(path)) { removed = 1; continue; } if (!removed) die_errno("git rm: '%s'", path); } if (gitmodules_modified) stage_updated_gitmodules(); } if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) die(_("Unable to write new index file")); } return 0; }
int cmd_update_index(int argc, const char **argv, const char *prefix) { int i, newfd, entries, has_errors = 0, line_termination = '\n'; int allow_options = 1; int read_from_stdin = 0; int prefix_length = prefix ? strlen(prefix) : 0; char set_executable_bit = 0; unsigned int refresh_flags = 0; int lock_error = 0; struct lock_file *lock_file; git_config(git_default_config, NULL); /* We can't free this memory, it becomes part of a linked list parsed atexit() */ lock_file = xcalloc(1, sizeof(struct lock_file)); newfd = hold_locked_index(lock_file, 0); if (newfd < 0) lock_error = errno; entries = read_cache(); if (entries < 0) die("cache corrupted"); for (i = 1 ; i < argc; i++) { const char *path = argv[i]; const char *p; if (allow_options && *path == '-') { if (!strcmp(path, "--")) { allow_options = 0; continue; } if (!strcmp(path, "-q")) { refresh_flags |= REFRESH_QUIET; continue; } if (!strcmp(path, "--ignore-submodules")) { refresh_flags |= REFRESH_IGNORE_SUBMODULES; continue; } if (!strcmp(path, "--add")) { allow_add = 1; continue; } if (!strcmp(path, "--replace")) { allow_replace = 1; continue; } if (!strcmp(path, "--remove")) { allow_remove = 1; continue; } if (!strcmp(path, "--unmerged")) { refresh_flags |= REFRESH_UNMERGED; continue; } if (!strcmp(path, "--refresh")) { setup_work_tree(); has_errors |= refresh_cache(refresh_flags); continue; } if (!strcmp(path, "--really-refresh")) { setup_work_tree(); has_errors |= refresh_cache(REFRESH_REALLY | refresh_flags); continue; } if (!strcmp(path, "--cacheinfo")) { unsigned char sha1[20]; unsigned int mode; if (i+3 >= argc) die("git update-index: --cacheinfo <mode> <sha1> <path>"); if (strtoul_ui(argv[i+1], 8, &mode) || get_sha1_hex(argv[i+2], sha1) || add_cacheinfo(mode, sha1, argv[i+3], 0)) die("git update-index: --cacheinfo" " cannot add %s", argv[i+3]); i += 3; continue; } if (!strcmp(path, "--chmod=-x") || !strcmp(path, "--chmod=+x")) { if (argc <= i+1) die("git update-index: %s <path>", path); set_executable_bit = path[8]; continue; } if (!strcmp(path, "--assume-unchanged")) { mark_valid_only = MARK_VALID; continue; } if (!strcmp(path, "--no-assume-unchanged")) { mark_valid_only = UNMARK_VALID; continue; } if (!strcmp(path, "--info-only")) { info_only = 1; continue; } if (!strcmp(path, "--force-remove")) { force_remove = 1; continue; } if (!strcmp(path, "-z")) { line_termination = 0; continue; } if (!strcmp(path, "--stdin")) { if (i != argc - 1) die("--stdin must be at the end"); read_from_stdin = 1; break; } if (!strcmp(path, "--index-info")) { if (i != argc - 1) die("--index-info must be at the end"); allow_add = allow_replace = allow_remove = 1; read_index_info(line_termination); break; } if (!strcmp(path, "--unresolve")) { has_errors = do_unresolve(argc - i, argv + i, prefix, prefix_length); if (has_errors) active_cache_changed = 0; goto finish; } if (!strcmp(path, "--again") || !strcmp(path, "-g")) { setup_work_tree(); has_errors = do_reupdate(argc - i, argv + i, prefix, prefix_length); if (has_errors) active_cache_changed = 0; goto finish; } if (!strcmp(path, "--ignore-missing")) { refresh_flags |= REFRESH_IGNORE_MISSING; continue; } if (!strcmp(path, "--verbose")) { verbose = 1; continue; } if (!strcmp(path, "-h") || !strcmp(path, "--help")) usage(update_index_usage); die("unknown option %s", path); } setup_work_tree(); p = prefix_path(prefix, prefix_length, path); update_one(p, NULL, 0); if (set_executable_bit) chmod_path(set_executable_bit, p); if (p < path || p > path + strlen(path)) free((char*)p); } if (read_from_stdin) { struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; setup_work_tree(); while (strbuf_getline(&buf, stdin, line_termination) != EOF) { const char *p; if (line_termination && buf.buf[0] == '"') { strbuf_reset(&nbuf); if (unquote_c_style(&nbuf, buf.buf, NULL)) die("line is badly quoted"); strbuf_swap(&buf, &nbuf); } p = prefix_path(prefix, prefix_length, buf.buf); update_one(p, NULL, 0); if (set_executable_bit) chmod_path(set_executable_bit, p); if (p < buf.buf || p > buf.buf + buf.len) free((char *)p); } strbuf_release(&nbuf); strbuf_release(&buf); } finish: if (active_cache_changed) { if (newfd < 0) { if (refresh_flags & REFRESH_QUIET) exit(128); unable_to_lock_index_die(get_index_file(), lock_error); } if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(lock_file)) die("Unable to write new index file"); } rollback_lock_file(lock_file); return has_errors ? 1 : 0; }
int cmd_checkout_index(int argc, const char **argv, const char *prefix) { int i; int newfd = -1; int all = 0; int read_from_stdin = 0; int prefix_length; int force = 0, quiet = 0, not_new = 0; struct option builtin_checkout_index_options[] = { OPT_BOOLEAN('a', "all", &all, "checks out all files in the index"), OPT_BOOLEAN('f', "force", &force, "forces overwrite of existing files"), OPT__QUIET(&quiet), OPT_BOOLEAN('n', "no-create", ¬_new, "don't checkout new files"), { OPTION_CALLBACK, 'u', "index", &newfd, NULL, "update stat information in the index file", PARSE_OPT_NOARG, option_parse_u }, { OPTION_CALLBACK, 'z', NULL, NULL, NULL, "paths are separated with NUL character", PARSE_OPT_NOARG, option_parse_z }, OPT_BOOLEAN(0, "stdin", &read_from_stdin, "read list of paths from the standard input"), OPT_BOOLEAN(0, "temp", &to_tempfile, "write the content to temporary files"), OPT_CALLBACK(0, "prefix", NULL, "string", "when creating files, prepend <string>", option_parse_prefix), OPT_CALLBACK(0, "stage", NULL, NULL, "copy out the files from named stage", option_parse_stage), OPT_END() }; git_config(git_default_config, NULL); state.base_dir = ""; prefix_length = prefix ? strlen(prefix) : 0; if (read_cache() < 0) { die("invalid cache"); } argc = parse_options(argc, argv, builtin_checkout_index_options, builtin_checkout_index_usage, 0); state.force = force; state.quiet = quiet; state.not_new = not_new; if (state.base_dir_len || to_tempfile) { /* when --prefix is specified we do not * want to update cache. */ if (state.refresh_cache) { rollback_lock_file(&lock_file); newfd = -1; } state.refresh_cache = 0; } /* Check out named files first */ for (i = 0; i < argc; i++) { const char *arg = argv[i]; const char *p; if (all) die("git checkout-index: don't mix '--all' and explicit filenames"); if (read_from_stdin) die("git checkout-index: don't mix '--stdin' and explicit filenames"); p = prefix_path(prefix, prefix_length, arg); checkout_file(p, prefix_length); if (p < arg || p > arg + strlen(arg)) free((char*)p); } if (read_from_stdin) { struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; if (all) die("git checkout-index: don't mix '--all' and '--stdin'"); while (strbuf_getline(&buf, stdin, line_termination) != EOF) { const char *p; if (line_termination && buf.buf[0] == '"') { strbuf_reset(&nbuf); if (unquote_c_style(&nbuf, buf.buf, NULL)) die("line is badly quoted"); strbuf_swap(&buf, &nbuf); } p = prefix_path(prefix, prefix_length, buf.buf); checkout_file(p, prefix_length); if (p < buf.buf || p > buf.buf + buf.len) free((char *)p); } strbuf_release(&nbuf); strbuf_release(&buf); } if (all) checkout_all(prefix, prefix_length); if (0 <= newfd && (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file))) die("Unable to write new index file"); return 0; }
int cmd_add(int argc, const char **argv, const char *prefix) { int exit_status = 0; int newfd; const char **pathspec; struct dir_struct dir; int flags; int add_new_files; int require_pathspec; argc = parse_options(argc, argv, builtin_add_options, builtin_add_usage, 0); if (patch_interactive) add_interactive = 1; if (add_interactive) exit(interactive_add(argc, argv, prefix)); git_config(add_config, NULL); if (addremove && take_worktree_changes) die("-A and -u are mutually incompatible"); if ((addremove || take_worktree_changes) && !argc) { static const char *here[2] = { ".", NULL }; argc = 1; argv = here; } add_new_files = !take_worktree_changes && !refresh_only; require_pathspec = !take_worktree_changes; newfd = hold_locked_index(&lock_file, 1); flags = ((verbose ? ADD_CACHE_VERBOSE : 0) | (show_only ? ADD_CACHE_PRETEND : 0) | (intent_to_add ? ADD_CACHE_INTENT : 0) | (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) | (!(addremove || take_worktree_changes) ? ADD_CACHE_IGNORE_REMOVAL : 0)); if (require_pathspec && argc == 0) { fprintf(stderr, "Nothing specified, nothing added.\n"); fprintf(stderr, "Maybe you wanted to say 'git add .'?\n"); return 0; } pathspec = validate_pathspec(argc, argv, prefix); if (read_cache() < 0) die("index file corrupt"); treat_gitlinks(pathspec); if (add_new_files) /* This picks up the paths that are not tracked */ fill_directory(&dir, pathspec, ignored_too); if (refresh_only) { refresh(verbose, pathspec); goto finish; } exit_status |= add_files_to_cache(prefix, pathspec, flags); if (add_new_files) exit_status |= add_files(&dir, flags); finish: if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) die("Unable to write new index file"); } return exit_status; }
int cmd_clone(int argc, const char **argv, const char *prefix) { int is_bundle = 0; struct stat buf; const char *repo_name, *repo, *work_tree, *git_dir; char *path, *dir; int dest_exists; const struct ref *refs, *remote_head; const struct ref *remote_head_points_at; const struct ref *our_head_points_at; struct ref *mapped_refs; struct strbuf key = STRBUF_INIT, value = STRBUF_INIT; struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT; struct transport *transport = NULL; char *src_ref_prefix = "refs/heads/"; int err = 0; struct refspec *refspec; const char *fetch_pattern; junk_pid = getpid(); argc = parse_options(argc, argv, prefix, builtin_clone_options, builtin_clone_usage, 0); if (argc > 2) usage_msg_opt("Too many arguments.", builtin_clone_usage, builtin_clone_options); if (argc == 0) usage_msg_opt("You must specify a repository to clone.", builtin_clone_usage, builtin_clone_options); if (option_mirror) option_bare = 1; if (option_bare) { if (option_origin) die("--bare and --origin %s options are incompatible.", option_origin); option_no_checkout = 1; } if (!option_origin) option_origin = "origin"; repo_name = argv[0]; path = get_repo_path(repo_name, &is_bundle); if (path) repo = xstrdup(make_nonrelative_path(repo_name)); else if (!strchr(repo_name, ':')) repo = xstrdup(make_absolute_path(repo_name)); else repo = repo_name; if (argc == 2) dir = xstrdup(argv[1]); else dir = guess_dir_name(repo_name, is_bundle, option_bare); strip_trailing_slashes(dir); dest_exists = !stat(dir, &buf); if (dest_exists && !is_empty_dir(dir)) die("destination path '%s' already exists and is not " "an empty directory.", dir); strbuf_addf(&reflog_msg, "clone: from %s", repo); if (option_bare) work_tree = NULL; else { work_tree = getenv("GIT_WORK_TREE"); if (work_tree && !stat(work_tree, &buf)) die("working tree '%s' already exists.", work_tree); } if (option_bare || work_tree) git_dir = xstrdup(dir); else { work_tree = dir; git_dir = xstrdup(mkpath("%s/.git", dir)); } if (!option_bare) { junk_work_tree = work_tree; if (safe_create_leading_directories_const(work_tree) < 0) die_errno("could not create leading directories of '%s'", work_tree); if (!dest_exists && mkdir(work_tree, 0755)) die_errno("could not create work tree dir '%s'.", work_tree); set_git_work_tree(work_tree); } junk_git_dir = git_dir; atexit(remove_junk); sigchain_push_common(remove_junk_on_signal); setenv(CONFIG_ENVIRONMENT, mkpath("%s/config", git_dir), 1); if (safe_create_leading_directories_const(git_dir) < 0) die("could not create leading directories of '%s'", git_dir); set_git_dir(make_absolute_path(git_dir)); init_db(option_template, option_quiet ? INIT_DB_QUIET : 0); /* * At this point, the config exists, so we do not need the * environment variable. We actually need to unset it, too, to * re-enable parsing of the global configs. */ unsetenv(CONFIG_ENVIRONMENT); if (option_reference) setup_reference(git_dir); git_config(git_default_config, NULL); if (option_bare) { if (option_mirror) src_ref_prefix = "refs/"; strbuf_addstr(&branch_top, src_ref_prefix); git_config_set("core.bare", "true"); } else { strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin); } strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf); if (option_mirror || !option_bare) { /* Configure the remote */ strbuf_addf(&key, "remote.%s.fetch", option_origin); git_config_set_multivar(key.buf, value.buf, "^$", 0); strbuf_reset(&key); if (option_mirror) { strbuf_addf(&key, "remote.%s.mirror", option_origin); git_config_set(key.buf, "true"); strbuf_reset(&key); } strbuf_addf(&key, "remote.%s.url", option_origin); git_config_set(key.buf, repo); strbuf_reset(&key); } fetch_pattern = value.buf; refspec = parse_fetch_refspec(1, &fetch_pattern); strbuf_reset(&value); if (path && !is_bundle) { refs = clone_local(path, git_dir); mapped_refs = wanted_peer_refs(refs, refspec); } else { struct remote *remote = remote_get(argv[0]); transport = transport_get(remote, remote->url[0]); if (!transport->get_refs_list || !transport->fetch) die("Don't know how to clone %s", transport->url); transport_set_option(transport, TRANS_OPT_KEEP, "yes"); if (option_depth) transport_set_option(transport, TRANS_OPT_DEPTH, option_depth); if (option_quiet) transport->verbose = -1; else if (option_verbose) transport->verbose = 1; if (option_progress) transport->progress = 1; if (option_upload_pack) transport_set_option(transport, TRANS_OPT_UPLOADPACK, option_upload_pack); refs = transport_get_remote_refs(transport); if (refs) { mapped_refs = wanted_peer_refs(refs, refspec); transport_fetch_refs(transport, mapped_refs); } } if (refs) { clear_extra_refs(); write_remote_refs(mapped_refs); remote_head = find_ref_by_name(refs, "HEAD"); remote_head_points_at = guess_remote_head(remote_head, mapped_refs, 0); if (option_branch) { struct strbuf head = STRBUF_INIT; strbuf_addstr(&head, src_ref_prefix); strbuf_addstr(&head, option_branch); our_head_points_at = find_ref_by_name(mapped_refs, head.buf); strbuf_release(&head); if (!our_head_points_at) { warning("Remote branch %s not found in " "upstream %s, using HEAD instead", option_branch, option_origin); our_head_points_at = remote_head_points_at; } } else our_head_points_at = remote_head_points_at; } else { warning("You appear to have cloned an empty repository."); our_head_points_at = NULL; remote_head_points_at = NULL; remote_head = NULL; option_no_checkout = 1; if (!option_bare) install_branch_config(0, "master", option_origin, "refs/heads/master"); } if (remote_head_points_at && !option_bare) { struct strbuf head_ref = STRBUF_INIT; strbuf_addstr(&head_ref, branch_top.buf); strbuf_addstr(&head_ref, "HEAD"); create_symref(head_ref.buf, remote_head_points_at->peer_ref->name, reflog_msg.buf); } if (our_head_points_at) { /* Local default branch link */ create_symref("HEAD", our_head_points_at->name, NULL); if (!option_bare) { const char *head = skip_prefix(our_head_points_at->name, "refs/heads/"); update_ref(reflog_msg.buf, "HEAD", our_head_points_at->old_sha1, NULL, 0, DIE_ON_ERR); install_branch_config(0, head, option_origin, our_head_points_at->name); } } else if (remote_head) { /* Source had detached HEAD pointing somewhere. */ if (!option_bare) { update_ref(reflog_msg.buf, "HEAD", remote_head->old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); our_head_points_at = remote_head; } } else { /* Nothing to checkout out */ if (!option_no_checkout) warning("remote HEAD refers to nonexistent ref, " "unable to checkout.\n"); option_no_checkout = 1; } if (transport) { transport_unlock_pack(transport); transport_disconnect(transport); } if (!option_no_checkout) { struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); struct unpack_trees_options opts; struct tree *tree; struct tree_desc t; int fd; /* We need to be in the new work tree for the checkout */ setup_work_tree(); fd = hold_locked_index(lock_file, 1); memset(&opts, 0, sizeof opts); opts.update = 1; opts.merge = 1; opts.fn = oneway_merge; opts.verbose_update = !option_quiet; opts.src_index = &the_index; opts.dst_index = &the_index; tree = parse_tree_indirect(our_head_points_at->old_sha1); parse_tree(tree); init_tree_desc(&t, tree->buffer, tree->size); unpack_trees(1, &t, &opts); if (write_cache(fd, active_cache, active_nr) || commit_locked_index(lock_file)) die("unable to write new index file"); err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1), sha1_to_hex(our_head_points_at->old_sha1), "1", NULL); if (!err && option_recursive) err = run_command_v_opt(argv_submodule, RUN_GIT_CMD); } strbuf_release(&reflog_msg); strbuf_release(&branch_top); strbuf_release(&key); strbuf_release(&value); junk_pid = 0; return err; }
int cmd_reset(int argc, const char **argv, const char *prefix) { int reset_type = NONE, update_ref_status = 0, quiet = 0; int patch_mode = 0, unborn; const char *rev; unsigned char sha1[20]; const char **pathspec = NULL; const struct option options[] = { OPT__QUIET(&quiet, N_("be quiet, only report errors")), OPT_SET_INT(0, "mixed", &reset_type, N_("reset HEAD and index"), MIXED), OPT_SET_INT(0, "soft", &reset_type, N_("reset only HEAD"), SOFT), OPT_SET_INT(0, "hard", &reset_type, N_("reset HEAD, index and working tree"), HARD), OPT_SET_INT(0, "merge", &reset_type, N_("reset HEAD, index and working tree"), MERGE), OPT_SET_INT(0, "keep", &reset_type, N_("reset HEAD but keep local changes"), KEEP), OPT_BOOL('p', "patch", &patch_mode, N_("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); pathspec = parse_args(argv, prefix, &rev); unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", sha1); if (unborn) { /* reset on unborn branch: treat as reset to empty tree */ hashcpy(sha1, EMPTY_TREE_SHA1_BIN); } else if (!pathspec) { struct commit *commit; if (get_sha1_committish(rev, sha1)) die(_("Failed to resolve '%s' as a valid revision."), rev); commit = lookup_commit_reference(sha1); if (!commit) die(_("Could not parse object '%s'."), rev); hashcpy(sha1, commit->object.sha1); } else { struct tree *tree; if (get_sha1_treeish(rev, sha1)) die(_("Failed to resolve '%s' as a valid tree."), rev); tree = parse_tree_indirect(sha1); if (!tree) die(_("Could not parse object '%s'."), rev); hashcpy(sha1, tree->object.sha1); } if (patch_mode) { if (reset_type != NONE) die(_("--patch is incompatible with --{hard,mixed,soft}")); return run_add_interactive(sha1_to_hex(sha1), "--patch=reset", pathspec); } /* 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 (pathspec) { 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])); } 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 || reset_type == KEEP) die_if_unmerged_cache(reset_type); if (reset_type != SOFT) { struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); int newfd = hold_locked_index(lock, 1); if (reset_type == MIXED) { if (read_from_tree(pathspec, sha1)) return 1; } else { int err = reset_index(sha1, reset_type, quiet); if (reset_type == KEEP && !err) err = reset_index(sha1, MIXED, quiet); if (err) die(_("Could not reset index file to revision '%s'."), rev); } if (reset_type == MIXED) { /* Report what has not been updated. */ int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN; refresh_index(&the_index, flags, NULL, NULL, _("Unstaged changes after reset:")); } if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(lock)) die(_("Could not write new index file.")); } if (!pathspec && !unborn) { /* Any resets without paths update HEAD to the head being * switched to, saving the previous head in ORIG_HEAD before. */ update_ref_status = update_refs(rev, sha1); if (reset_type == HARD && !update_ref_status && !quiet) print_new_head_line(lookup_commit_reference(sha1)); } if (!pathspec) remove_branch_state(); return update_ref_status; }
static char *prepare_index(int argc, const char **argv, const char *prefix) { int fd; struct path_list partial; const char **pathspec = NULL; if (interactive) { interactive_add(argc, argv, prefix); commit_style = COMMIT_AS_IS; return get_index_file(); } if (read_cache() < 0) die("index file corrupt"); if (*argv) pathspec = get_pathspec(prefix, argv); /* * Non partial, non as-is commit. * * (1) get the real index; * (2) update the_index as necessary; * (3) write the_index out to the real index (still locked); * (4) return the name of the locked index file. * * The caller should run hooks on the locked real index, and * (A) if all goes well, commit the real index; * (B) on failure, rollback the real index. */ if (all || (also && pathspec && *pathspec)) { int fd = hold_locked_index(&index_lock, 1); add_files_to_cache(0, also ? prefix : NULL, pathspec); refresh_cache(REFRESH_QUIET); if (write_cache(fd, active_cache, active_nr) || close_lock_file(&index_lock)) die("unable to write new_index file"); commit_style = COMMIT_NORMAL; return index_lock.filename; } /* * As-is commit. * * (1) return the name of the real index file. * * The caller should run hooks on the real index, and run * hooks on the real index, and create commit from the_index. * We still need to refresh the index here. */ if (!pathspec || !*pathspec) { fd = hold_locked_index(&index_lock, 1); refresh_cache(REFRESH_QUIET); if (write_cache(fd, active_cache, active_nr) || commit_locked_index(&index_lock)) die("unable to write new_index file"); commit_style = COMMIT_AS_IS; return get_index_file(); } /* * A partial commit. * * (0) find the set of affected paths; * (1) get lock on the real index file; * (2) update the_index with the given paths; * (3) write the_index out to the real index (still locked); * (4) get lock on the false index file; * (5) reset the_index from HEAD; * (6) update the_index the same way as (2); * (7) write the_index out to the false index file; * (8) return the name of the false index file (still locked); * * The caller should run hooks on the locked false index, and * create commit from it. Then * (A) if all goes well, commit the real index; * (B) on failure, rollback the real index; * In either case, rollback the false index. */ commit_style = COMMIT_PARTIAL; if (file_exists(git_path("MERGE_HEAD"))) die("cannot do a partial commit during a merge."); memset(&partial, 0, sizeof(partial)); partial.strdup_paths = 1; if (list_paths(&partial, initial_commit ? NULL : "HEAD", prefix, pathspec)) exit(1); discard_cache(); if (read_cache() < 0) die("cannot read the index"); fd = hold_locked_index(&index_lock, 1); add_remove_files(&partial); refresh_cache(REFRESH_QUIET); if (write_cache(fd, active_cache, active_nr) || close_lock_file(&index_lock)) die("unable to write new_index file"); fd = hold_lock_file_for_update(&false_lock, git_path("next-index-%d", getpid()), 1); create_base_index(); add_remove_files(&partial); refresh_cache(REFRESH_QUIET); if (write_cache(fd, active_cache, active_nr) || close_lock_file(&false_lock)) die("unable to write temporary index file"); discard_cache(); read_cache_from(false_lock.filename); return false_lock.filename; }
int cmd_mv(int argc, const char **argv, const char *prefix) { int i, newfd; int verbose = 0, show_only = 0, force = 0, ignore_errors = 0; struct option builtin_mv_options[] = { OPT__DRY_RUN(&show_only), OPT_BOOLEAN('f', "force", &force, "force move/rename even if target exists"), OPT_BOOLEAN('k', NULL, &ignore_errors, "skip move/rename errors"), OPT_END(), }; const char **source, **destination, **dest_path; enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes; struct stat st; struct string_list src_for_dst = STRING_LIST_INIT_NODUP; git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, builtin_mv_options, builtin_mv_usage, 0); if (--argc < 1) usage_with_options(builtin_mv_usage, builtin_mv_options); newfd = hold_locked_index(&lock_file, 1); if (read_cache() < 0) die("index file corrupt"); source = copy_pathspec(prefix, argv, argc, 0); modes = xcalloc(argc, sizeof(enum update_mode)); dest_path = copy_pathspec(prefix, argv + argc, 1, 0); if (dest_path[0][0] == '\0') /* special case: "." was normalized to "" */ destination = copy_pathspec(dest_path[0], argv, argc, 1); else if (!lstat(dest_path[0], &st) && S_ISDIR(st.st_mode)) { dest_path[0] = add_slash(dest_path[0]); destination = copy_pathspec(dest_path[0], argv, argc, 1); } else { if (argc != 1) usage_with_options(builtin_mv_usage, builtin_mv_options); destination = dest_path; } /* Checking */ for (i = 0; i < argc; i++) { const char *src = source[i], *dst = destination[i]; int length, src_is_dir; const char *bad = NULL; if (show_only) printf("Checking rename of '%s' to '%s'\n", src, dst); length = strlen(src); if (lstat(src, &st) < 0) bad = "bad source"; else if (!strncmp(src, dst, length) && (dst[length] == 0 || dst[length] == '/')) { bad = "can not move directory into itself"; } else if ((src_is_dir = S_ISDIR(st.st_mode)) && lstat(dst, &st) == 0) bad = "cannot move directory over file"; else if (src_is_dir) { const char *src_w_slash = add_slash(src); int len_w_slash = length + 1; int first, last; modes[i] = WORKING_DIRECTORY; first = cache_name_pos(src_w_slash, len_w_slash); if (first >= 0) die ("Huh? %.*s is in index?", len_w_slash, src_w_slash); first = -1 - first; for (last = first; last < active_nr; last++) { const char *path = active_cache[last]->name; if (strncmp(path, src_w_slash, len_w_slash)) break; } free((char *)src_w_slash); if (last - first < 1) bad = "source directory is empty"; else { int j, dst_len; if (last - first > 0) { source = xrealloc(source, (argc + last - first) * sizeof(char *)); destination = xrealloc(destination, (argc + last - first) * sizeof(char *)); modes = xrealloc(modes, (argc + last - first) * sizeof(enum update_mode)); } dst = add_slash(dst); dst_len = strlen(dst); for (j = 0; j < last - first; j++) { const char *path = active_cache[first + j]->name; source[argc + j] = path; destination[argc + j] = prefix_path(dst, dst_len, path + length + 1); modes[argc + j] = INDEX; } argc += last - first; } } else if (cache_name_pos(src, length) < 0) bad = "not under version control"; else if (lstat(dst, &st) == 0) { bad = "destination exists"; if (force) { /* * only files can overwrite each other: * check both source and destination */ if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { warning("%s; will overwrite!", bad); bad = NULL; } else bad = "Cannot overwrite"; } } else if (string_list_has_string(&src_for_dst, dst)) bad = "multiple sources for the same target"; else string_list_insert(&src_for_dst, dst); if (bad) { if (ignore_errors) { if (--argc > 0) { memmove(source + i, source + i + 1, (argc - i) * sizeof(char *)); memmove(destination + i, destination + i + 1, (argc - i) * sizeof(char *)); i--; } } else die ("%s, source=%s, destination=%s", bad, src, dst); } } for (i = 0; i < argc; i++) { const char *src = source[i], *dst = destination[i]; enum update_mode mode = modes[i]; int pos; if (show_only || verbose) printf("Renaming %s to %s\n", src, dst); if (!show_only && mode != INDEX && rename(src, dst) < 0 && !ignore_errors) die_errno ("renaming '%s' failed", src); if (mode == WORKING_DIRECTORY) continue; pos = cache_name_pos(src, strlen(src)); assert(pos >= 0); if (!show_only) rename_cache_entry_at(pos, dst); } if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) die("Unable to write new index file"); } return 0; }
int cmd_update_index(int argc, const char **argv, const char *prefix) { int newfd, entries, has_errors = 0, line_termination = '\n'; int read_from_stdin = 0; int prefix_length = prefix ? strlen(prefix) : 0; char set_executable_bit = 0; struct refresh_params refresh_args = {0, &has_errors}; int lock_error = 0; struct lock_file *lock_file; struct parse_opt_ctx_t ctx; int parseopt_state = PARSE_OPT_UNKNOWN; struct option options[] = { OPT_BIT('q', NULL, &refresh_args.flags, "continue refresh even when index needs update", REFRESH_QUIET), OPT_BIT(0, "ignore-submodules", &refresh_args.flags, "refresh: ignore submodules", REFRESH_IGNORE_SUBMODULES), OPT_SET_INT(0, "add", &allow_add, "do not ignore new files", 1), OPT_SET_INT(0, "replace", &allow_replace, "let files replace directories and vice-versa", 1), OPT_SET_INT(0, "remove", &allow_remove, "notice files missing from worktree", 1), OPT_BIT(0, "unmerged", &refresh_args.flags, "refresh even if index contains unmerged entries", REFRESH_UNMERGED), {OPTION_CALLBACK, 0, "refresh", &refresh_args, NULL, "refresh stat information", PARSE_OPT_NOARG | PARSE_OPT_NONEG, refresh_callback}, {OPTION_CALLBACK, 0, "really-refresh", &refresh_args, NULL, "like --refresh, but ignore assume-unchanged setting", PARSE_OPT_NOARG | PARSE_OPT_NONEG, really_refresh_callback}, {OPTION_LOWLEVEL_CALLBACK, 0, "cacheinfo", NULL, "<mode> <object> <path>", "add the specified entry to the index", PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */ PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, (parse_opt_cb *) cacheinfo_callback}, {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, "(+/-)x", "override the executable bit of the listed files", PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, chmod_callback}, {OPTION_SET_INT, 0, "assume-unchanged", &mark_valid_only, NULL, "mark files as \"not changing\"", PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, {OPTION_SET_INT, 0, "no-assume-unchanged", &mark_valid_only, NULL, "clear assumed-unchanged bit", PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, {OPTION_SET_INT, 0, "skip-worktree", &mark_skip_worktree_only, NULL, "mark files as \"index-only\"", PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, {OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL, "clear skip-worktree bit", PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, OPT_SET_INT(0, "info-only", &info_only, "add to index only; do not add content to object database", 1), OPT_SET_INT(0, "force-remove", &force_remove, "remove named paths even if present in worktree", 1), OPT_SET_INT('z', NULL, &line_termination, "with --stdin: input lines are terminated by null bytes", '\0'), {OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL, "read list of paths to be updated from standard input", PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) stdin_callback}, {OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &line_termination, NULL, "add entries from standard input to the index", PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) stdin_cacheinfo_callback}, {OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL, "repopulate stages #2 and #3 for the listed paths", PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) unresolve_callback}, {OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL, "only update entries that differ from HEAD", PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) reupdate_callback}, OPT_BIT(0, "ignore-missing", &refresh_args.flags, "ignore files missing from worktree", REFRESH_IGNORE_MISSING), OPT_SET_INT(0, "verbose", &verbose, "report actions to standard output", 1), {OPTION_CALLBACK, 0, "clear-resolve-undo", NULL, NULL, "(for porcelains) forget saved unresolved conflicts", PARSE_OPT_NOARG | PARSE_OPT_NONEG, resolve_undo_clear_callback}, OPT_END() }; if (argc == 2 && !strcmp(argv[1], "-h")) usage(update_index_usage[0]); git_config(git_default_config, NULL); /* We can't free this memory, it becomes part of a linked list parsed atexit() */ lock_file = xcalloc(1, sizeof(struct lock_file)); newfd = hold_locked_index(lock_file, 0); if (newfd < 0) lock_error = errno; entries = read_cache(); if (entries < 0) die("cache corrupted"); /* * Custom copy of parse_options() because we want to handle * filename arguments as they come. */ parse_options_start(&ctx, argc, argv, prefix, options, PARSE_OPT_STOP_AT_NON_OPTION); while (ctx.argc) { if (parseopt_state != PARSE_OPT_DONE) parseopt_state = parse_options_step(&ctx, options, update_index_usage); if (!ctx.argc) break; switch (parseopt_state) { case PARSE_OPT_HELP: exit(129); case PARSE_OPT_NON_OPTION: case PARSE_OPT_DONE: { const char *path = ctx.argv[0]; const char *p; setup_work_tree(); p = prefix_path(prefix, prefix_length, path); update_one(p, NULL, 0); if (set_executable_bit) chmod_path(set_executable_bit, p); if (p < path || p > path + strlen(path)) free((char *)p); ctx.argc--; ctx.argv++; break; } case PARSE_OPT_UNKNOWN: if (ctx.argv[0][1] == '-') error("unknown option '%s'", ctx.argv[0] + 2); else error("unknown switch '%c'", *ctx.opt); usage_with_options(update_index_usage, options); } } argc = parse_options_end(&ctx); if (read_from_stdin) { struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; setup_work_tree(); while (strbuf_getline(&buf, stdin, line_termination) != EOF) { const char *p; if (line_termination && buf.buf[0] == '"') { strbuf_reset(&nbuf); if (unquote_c_style(&nbuf, buf.buf, NULL)) die("line is badly quoted"); strbuf_swap(&buf, &nbuf); } p = prefix_path(prefix, prefix_length, buf.buf); update_one(p, NULL, 0); if (set_executable_bit) chmod_path(set_executable_bit, p); if (p < buf.buf || p > buf.buf + buf.len) free((char *)p); } strbuf_release(&nbuf); strbuf_release(&buf); } if (active_cache_changed) { if (newfd < 0) { if (refresh_args.flags & REFRESH_QUIET) exit(128); unable_to_lock_index_die(get_index_file(), lock_error); } if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(lock_file)) die("Unable to write new index file"); } rollback_lock_file(lock_file); return has_errors ? 1 : 0; }
static char *prepare_index(int argc, const char **argv, const char *prefix, const struct commit *current_head, int is_status) { int fd; struct string_list partial; struct pathspec pathspec; int refresh_flags = REFRESH_QUIET; if (is_status) refresh_flags |= REFRESH_UNMERGED; parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_FULL, prefix, argv); if (read_cache_preload(&pathspec) < 0) die(_("index file corrupt")); if (interactive) { char *old_index_env = NULL; fd = hold_locked_index(&index_lock, 1); refresh_cache_or_die(refresh_flags); if (write_cache(fd, active_cache, active_nr) || close_lock_file(&index_lock)) die(_("unable to create temporary index")); old_index_env = getenv(INDEX_ENVIRONMENT); setenv(INDEX_ENVIRONMENT, index_lock.filename, 1); if (interactive_add(argc, argv, prefix, patch_interactive) != 0) die(_("interactive add failed")); if (old_index_env && *old_index_env) setenv(INDEX_ENVIRONMENT, old_index_env, 1); else unsetenv(INDEX_ENVIRONMENT); discard_cache(); read_cache_from(index_lock.filename); commit_style = COMMIT_NORMAL; return index_lock.filename; } /* * Non partial, non as-is commit. * * (1) get the real index; * (2) update the_index as necessary; * (3) write the_index out to the real index (still locked); * (4) return the name of the locked index file. * * The caller should run hooks on the locked real index, and * (A) if all goes well, commit the real index; * (B) on failure, rollback the real index. */ if (all || (also && pathspec.nr)) { fd = hold_locked_index(&index_lock, 1); add_files_to_cache(also ? prefix : NULL, &pathspec, 0); refresh_cache_or_die(refresh_flags); update_main_cache_tree(WRITE_TREE_SILENT); if (write_cache(fd, active_cache, active_nr) || close_lock_file(&index_lock)) die(_("unable to write new_index file")); commit_style = COMMIT_NORMAL; return index_lock.filename; } /* * As-is commit. * * (1) return the name of the real index file. * * The caller should run hooks on the real index, * and create commit from the_index. * We still need to refresh the index here. */ if (!only && !pathspec.nr) { fd = hold_locked_index(&index_lock, 1); refresh_cache_or_die(refresh_flags); if (active_cache_changed) { update_main_cache_tree(WRITE_TREE_SILENT); if (write_cache(fd, active_cache, active_nr) || commit_locked_index(&index_lock)) die(_("unable to write new_index file")); } else { rollback_lock_file(&index_lock); } commit_style = COMMIT_AS_IS; return get_index_file(); } /* * A partial commit. * * (0) find the set of affected paths; * (1) get lock on the real index file; * (2) update the_index with the given paths; * (3) write the_index out to the real index (still locked); * (4) get lock on the false index file; * (5) reset the_index from HEAD; * (6) update the_index the same way as (2); * (7) write the_index out to the false index file; * (8) return the name of the false index file (still locked); * * The caller should run hooks on the locked false index, and * create commit from it. Then * (A) if all goes well, commit the real index; * (B) on failure, rollback the real index; * In either case, rollback the false index. */ commit_style = COMMIT_PARTIAL; if (whence != FROM_COMMIT) { if (whence == FROM_MERGE) die(_("cannot do a partial commit during a merge.")); else if (whence == FROM_CHERRY_PICK) die(_("cannot do a partial commit during a cherry-pick.")); } memset(&partial, 0, sizeof(partial)); partial.strdup_strings = 1; if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, &pathspec)) exit(1); discard_cache(); if (read_cache() < 0) die(_("cannot read the index")); fd = hold_locked_index(&index_lock, 1); add_remove_files(&partial); refresh_cache(REFRESH_QUIET); if (write_cache(fd, active_cache, active_nr) || close_lock_file(&index_lock)) die(_("unable to write new_index file")); fd = hold_lock_file_for_update(&false_lock, git_path("next-index-%"PRIuMAX, (uintmax_t) getpid()), LOCK_DIE_ON_ERROR); create_base_index(current_head); add_remove_files(&partial); refresh_cache(REFRESH_QUIET); if (write_cache(fd, active_cache, active_nr) || close_lock_file(&false_lock)) die(_("unable to write temporary index file")); discard_cache(); read_cache_from(false_lock.filename); return false_lock.filename; }
static int try_merge_strategy(const char *strategy, struct commit_list *common, const char *head_arg) { const char **args; int i = 0, ret; struct commit_list *j; struct strbuf buf = STRBUF_INIT; int index_fd; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); index_fd = hold_locked_index(lock, 1); refresh_cache(REFRESH_QUIET); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) return error("Unable to write index."); rollback_lock_file(lock); if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) { int clean; struct commit *result; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); int index_fd; struct commit_list *reversed = NULL; struct merge_options o; if (remoteheads->next) { error("Not handling anything other than two heads merge."); return 2; } init_merge_options(&o); if (!strcmp(strategy, "subtree")) o.subtree_merge = 1; o.branch1 = head_arg; o.branch2 = remoteheads->item->util; for (j = common; j; j = j->next) commit_list_insert(j->item, &reversed); index_fd = hold_locked_index(lock, 1); clean = merge_recursive(&o, lookup_commit(head), remoteheads->item, reversed, &result); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) die ("unable to write %s", get_index_file()); rollback_lock_file(lock); return clean ? 0 : 1; } else { args = xmalloc((4 + commit_list_count(common) + commit_list_count(remoteheads)) * sizeof(char *)); strbuf_addf(&buf, "merge-%s", strategy); args[i++] = buf.buf; for (j = common; j; j = j->next) args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); args[i++] = "--"; args[i++] = head_arg; for (j = remoteheads; j; j = j->next) args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); args[i] = NULL; ret = run_command_v_opt(args, RUN_GIT_CMD); strbuf_release(&buf); i = 1; for (j = common; j; j = j->next) free((void *)args[i++]); i += 2; for (j = remoteheads; j; j = j->next) free((void *)args[i++]); free(args); discard_cache(); if (read_cache() < 0) die("failed to read the cache"); return ret; } }