diff options
Diffstat (limited to 'builtin')
36 files changed, 977 insertions, 515 deletions
diff --git a/builtin/add.c b/builtin/add.c index b7d3ff1e28..3dfcfc5fba 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -3,7 +3,7 @@ * * Copyright (C) 2006 Linus Torvalds */ -#define USE_THE_INDEX_VARIABLE + #include "builtin.h" #include "advice.h" #include "config.h" @@ -40,20 +40,20 @@ static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only) { int i, ret = 0; - for (i = 0; i < the_index.cache_nr; i++) { - struct cache_entry *ce = the_index.cache[i]; + for (i = 0; i < the_repository->index->cache_nr; i++) { + struct cache_entry *ce = the_repository->index->cache[i]; int err; if (!include_sparse && (ce_skip_worktree(ce) || - !path_in_sparse_checkout(ce->name, &the_index))) + !path_in_sparse_checkout(ce->name, the_repository->index))) continue; - if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL)) + if (pathspec && !ce_path_match(the_repository->index, ce, pathspec, NULL)) continue; if (!show_only) - err = chmod_index_entry(&the_index, ce, flip); + err = chmod_index_entry(the_repository->index, ce, flip); else err = S_ISREG(ce->ce_mode) ? 0 : -1; @@ -68,20 +68,20 @@ static int renormalize_tracked_files(const struct pathspec *pathspec, int flags) { int i, retval = 0; - for (i = 0; i < the_index.cache_nr; i++) { - struct cache_entry *ce = the_index.cache[i]; + for (i = 0; i < the_repository->index->cache_nr; i++) { + struct cache_entry *ce = the_repository->index->cache[i]; if (!include_sparse && (ce_skip_worktree(ce) || - !path_in_sparse_checkout(ce->name, &the_index))) + !path_in_sparse_checkout(ce->name, the_repository->index))) continue; if (ce_stage(ce)) continue; /* do not touch unmerged paths */ if (!S_ISREG(ce->ce_mode) && !S_ISLNK(ce->ce_mode)) continue; /* do not touch non blobs */ - if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL)) + if (pathspec && !ce_path_match(the_repository->index, ce, pathspec, NULL)) continue; - retval |= add_file_to_index(&the_index, ce->name, + retval |= add_file_to_index(the_repository->index, ce->name, flags | ADD_CACHE_RENORMALIZE); } @@ -100,11 +100,11 @@ static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec, i = dir->nr; while (--i >= 0) { struct dir_entry *entry = *src++; - if (dir_path_match(&the_index, entry, pathspec, prefix, seen)) + if (dir_path_match(the_repository->index, entry, pathspec, prefix, seen)) *dst++ = entry; } dir->nr = dst - dir->entries; - add_pathspec_matches_against_index(pathspec, &the_index, seen, + add_pathspec_matches_against_index(pathspec, the_repository->index, seen, PS_IGNORE_SKIP_WORKTREE); return seen; } @@ -119,14 +119,14 @@ static int refresh(int verbose, const struct pathspec *pathspec) (verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET); seen = xcalloc(pathspec->nr, 1); - refresh_index(&the_index, flags, pathspec, seen, + refresh_index(the_repository->index, flags, pathspec, seen, _("Unstaged changes after refreshing the index:")); for (i = 0; i < pathspec->nr; i++) { if (!seen[i]) { const char *path = pathspec->items[i].original; if (matches_skip_worktree(pathspec, i, &skip_worktree_seen) || - !path_in_sparse_checkout(path, &the_index)) { + !path_in_sparse_checkout(path, the_repository->index)) { string_list_append(&only_match_skip_worktree, pathspec->items[i].original); } else { @@ -338,12 +338,12 @@ static int add_files(struct dir_struct *dir, int flags) for (i = 0; i < dir->nr; i++) { if (!include_sparse && - !path_in_sparse_checkout(dir->entries[i]->name, &the_index)) { + !path_in_sparse_checkout(dir->entries[i]->name, the_repository->index)) { string_list_append(&matched_sparse_paths, dir->entries[i]->name); continue; } - if (add_file_to_index(&the_index, dir->entries[i]->name, flags)) { + if (add_file_to_index(the_repository->index, dir->entries[i]->name, flags)) { if (!ignore_add_errors) die(_("adding files failed")); exit_status = 1; @@ -461,8 +461,8 @@ int cmd_add(int argc, const char **argv, const char *prefix) if (repo_read_index_preload(the_repository, &pathspec, 0) < 0) die(_("index file corrupt")); - die_in_unpopulated_submodule(&the_index, prefix); - die_path_inside_submodule(&the_index, &pathspec); + die_in_unpopulated_submodule(the_repository->index, prefix); + die_path_inside_submodule(the_repository->index, &pathspec); if (add_new_files) { int baselen; @@ -474,7 +474,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) } /* This picks up the paths that are not tracked */ - baselen = fill_directory(&dir, &the_index, &pathspec); + baselen = fill_directory(&dir, the_repository->index, &pathspec); if (pathspec.nr) seen = prune_directory(&dir, &pathspec, baselen); } @@ -491,7 +491,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) if (!seen) seen = find_pathspecs_matching_against_index(&pathspec, - &the_index, PS_IGNORE_SKIP_WORKTREE); + the_repository->index, PS_IGNORE_SKIP_WORKTREE); /* * file_exists() assumes exact match @@ -527,8 +527,8 @@ int cmd_add(int argc, const char **argv, const char *prefix) !file_exists(path)) { if (ignore_missing) { int dtype = DT_UNKNOWN; - if (is_excluded(&dir, &the_index, path, &dtype)) - dir_add_ignored(&dir, &the_index, + if (is_excluded(&dir, the_repository->index, path, &dtype)) + dir_add_ignored(&dir, the_repository->index, path, pathspec.items[i].len); } else die(_("pathspec '%s' did not match any files"), @@ -569,7 +569,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) end_odb_transaction(); finish: - if (write_locked_index(&the_index, &lock_file, + if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK | SKIP_IF_UNCHANGED)) die(_("unable to write new index file")); diff --git a/builtin/am.c b/builtin/am.c index c62c5a6f71..36839029d2 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -3,7 +3,7 @@ * * Based on git-am.sh by Junio C Hamano. */ -#define USE_THE_INDEX_VARIABLE + #include "builtin.h" #include "abspath.h" #include "advice.h" @@ -1542,8 +1542,8 @@ static int run_apply(const struct am_state *state, const char *index_file) if (index_file) { /* Reload index as apply_all_patches() will have modified it. */ - discard_index(&the_index); - read_index_from(&the_index, index_file, get_git_dir()); + discard_index(the_repository->index); + read_index_from(the_repository->index, index_file, get_git_dir()); } return 0; @@ -1585,10 +1585,10 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa if (build_fake_ancestor(state, index_path)) return error("could not build fake ancestor"); - discard_index(&the_index); - read_index_from(&the_index, index_path, get_git_dir()); + discard_index(the_repository->index); + read_index_from(the_repository->index, index_path, get_git_dir()); - if (write_index_as_tree(&orig_tree, &the_index, index_path, 0, NULL)) + if (write_index_as_tree(&orig_tree, the_repository->index, index_path, 0, NULL)) return error(_("Repository lacks necessary blobs to fall back on 3-way merge.")); say(state, stdout, _("Using index info to reconstruct a base tree...")); @@ -1614,12 +1614,12 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa return error(_("Did you hand edit your patch?\n" "It does not apply to blobs recorded in its index.")); - if (write_index_as_tree(&their_tree, &the_index, index_path, 0, NULL)) + if (write_index_as_tree(&their_tree, the_repository->index, index_path, 0, NULL)) return error("could not write tree"); say(state, stdout, _("Falling back to patching base and 3-way merge...")); - discard_index(&the_index); + discard_index(the_repository->index); repo_read_index(the_repository); /* @@ -1666,7 +1666,7 @@ static void do_commit(const struct am_state *state) if (!state->no_verify && run_hooks("pre-applypatch")) exit(1); - if (write_index_as_tree(&tree, &the_index, get_index_file(), 0, NULL)) + if (write_index_as_tree(&tree, the_repository->index, get_index_file(), 0, NULL)) die(_("git write-tree failed to write a tree")); if (!repo_get_oid_commit(the_repository, "HEAD", &parent)) { @@ -1955,7 +1955,7 @@ static void am_resolve(struct am_state *state, int allow_empty) } } - if (unmerged_index(&the_index)) { + if (unmerged_index(the_repository->index)) { printf_ln(_("You still have unmerged paths in your index.\n" "You should 'git add' each file with resolved conflicts to mark them as such.\n" "You might run `git rm` on a file to accept \"deleted by them\" for it.")); @@ -1994,12 +1994,12 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset) repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR); - refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL); + refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL); memset(&opts, 0, sizeof(opts)); opts.head_idx = 1; - opts.src_index = &the_index; - opts.dst_index = &the_index; + opts.src_index = the_repository->index; + opts.dst_index = the_repository->index; opts.update = 1; opts.merge = 1; opts.reset = reset ? UNPACK_RESET_PROTECT_UNTRACKED : 0; @@ -2013,7 +2013,7 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset) return -1; } - if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) + if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); return 0; @@ -2036,8 +2036,8 @@ static int merge_tree(struct tree *tree) memset(&opts, 0, sizeof(opts)); opts.head_idx = 1; - opts.src_index = &the_index; - opts.dst_index = &the_index; + opts.src_index = the_repository->index; + opts.dst_index = the_repository->index; opts.merge = 1; opts.fn = oneway_merge; init_tree_desc(&t[0], &tree->object.oid, tree->buffer, tree->size); @@ -2047,7 +2047,7 @@ static int merge_tree(struct tree *tree) return -1; } - if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) + if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); return 0; @@ -2075,7 +2075,7 @@ static int clean_index(const struct object_id *head, const struct object_id *rem if (fast_forward_to(head_tree, head_tree, 1)) return -1; - if (write_index_as_tree(&index, &the_index, get_index_file(), 0, NULL)) + if (write_index_as_tree(&index, the_repository->index, get_index_file(), 0, NULL)) return -1; index_tree = parse_tree_indirect(&index); diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 0c948f40fb..43a1d7ac49 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -3,7 +3,7 @@ * * Copyright (C) Linus Torvalds, 2005 */ -#define USE_THE_INDEX_VARIABLE + #include "builtin.h" #include "config.h" #include "convert.h" @@ -77,7 +77,7 @@ static int filter_object(const char *path, unsigned mode, struct checkout_metadata meta; init_checkout_metadata(&meta, NULL, NULL, oid); - if (convert_to_working_tree(&the_index, path, *buf, *size, &strbuf, &meta)) { + if (convert_to_working_tree(the_repository->index, path, *buf, *size, &strbuf, &meta)) { free(*buf); *size = strbuf.len; *buf = strbuf_detach(&strbuf, NULL); diff --git a/builtin/check-attr.c b/builtin/check-attr.c index c1da1d184e..9376810710 100644 --- a/builtin/check-attr.c +++ b/builtin/check-attr.c @@ -1,4 +1,3 @@ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "config.h" #include "attr.h" @@ -71,9 +70,9 @@ static void check_attr(const char *prefix, struct attr_check *check, prefix_path(prefix, prefix ? strlen(prefix) : 0, file); if (collect_all) { - git_all_attrs(&the_index, full_path, check); + git_all_attrs(the_repository->index, full_path, check); } else { - git_check_attr(&the_index, full_path, check); + git_check_attr(the_repository->index, full_path, check); } output_attr(check, file); diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c index 906cd96753..6c43430ec4 100644 --- a/builtin/check-ignore.c +++ b/builtin/check-ignore.c @@ -1,4 +1,3 @@ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "config.h" #include "dir.h" @@ -95,21 +94,21 @@ static int check_ignore(struct dir_struct *dir, PATHSPEC_KEEP_ORDER, prefix, argv); - die_path_inside_submodule(&the_index, &pathspec); + die_path_inside_submodule(the_repository->index, &pathspec); /* * look for pathspecs matching entries in the index, since these * should not be ignored, in order to be consistent with * 'git status', 'git add' etc. */ - seen = find_pathspecs_matching_against_index(&pathspec, &the_index, + seen = find_pathspecs_matching_against_index(&pathspec, the_repository->index, PS_HEED_SKIP_WORKTREE); for (i = 0; i < pathspec.nr; i++) { full_path = pathspec.items[i].match; pattern = NULL; if (!seen[i]) { int dtype = DT_UNKNOWN; - pattern = last_matching_pattern(dir, &the_index, + pattern = last_matching_pattern(dir, the_repository->index, full_path, &dtype); if (!verbose && pattern && pattern->flags & PATTERN_FLAG_NEGATIVE) diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index 2e086a204d..29e744d11b 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -4,7 +4,7 @@ * Copyright (C) 2005 Linus Torvalds * */ -#define USE_THE_INDEX_VARIABLE + #include "builtin.h" #include "config.h" #include "gettext.h" @@ -69,7 +69,7 @@ static void write_tempfile_record(const char *name, const char *prefix) static int checkout_file(const char *name, const char *prefix) { int namelen = strlen(name); - int pos = index_name_pos(&the_index, name, namelen); + int pos = index_name_pos(the_repository->index, name, namelen); int has_same_name = 0; int is_file = 0; int is_skipped = 1; @@ -79,8 +79,8 @@ static int checkout_file(const char *name, const char *prefix) if (pos < 0) pos = -pos - 1; - while (pos < the_index.cache_nr) { - struct cache_entry *ce = the_index.cache[pos]; + while (pos <the_repository->index->cache_nr) { + struct cache_entry *ce =the_repository->index->cache[pos]; if (ce_namelen(ce) != namelen || memcmp(ce->name, name, namelen)) break; @@ -140,8 +140,8 @@ static int checkout_all(const char *prefix, int prefix_length) int i, errs = 0; struct cache_entry *last_ce = NULL; - for (i = 0; i < the_index.cache_nr ; i++) { - struct cache_entry *ce = the_index.cache[i]; + for (i = 0; i < the_repository->index->cache_nr ; i++) { + struct cache_entry *ce = the_repository->index->cache[i]; if (S_ISSPARSEDIR(ce->ce_mode)) { if (!ce_skip_worktree(ce)) @@ -154,8 +154,8 @@ static int checkout_all(const char *prefix, int prefix_length) * first entry inside the expanded sparse directory). */ if (ignore_skip_worktree) { - ensure_full_index(&the_index); - ce = the_index.cache[i]; + ensure_full_index(the_repository->index); + ce = the_repository->index->cache[i]; } } @@ -260,7 +260,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, builtin_checkout_index_options, builtin_checkout_index_usage, 0); - state.istate = &the_index; + state.istate = the_repository->index; state.force = force; state.quiet = quiet; state.not_new = not_new; @@ -280,7 +280,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) */ if (index_opt && !state.base_dir_len && !to_tempfile) { state.refresh_cache = 1; - state.istate = &the_index; + state.istate = the_repository->index; repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR); } @@ -339,7 +339,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) return 1; if (is_lock_file_locked(&lock_file) && - write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) + write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK)) die("Unable to write new index file"); return 0; } diff --git a/builtin/checkout.c b/builtin/checkout.c index 3944a9fcba..536b894190 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -1,4 +1,3 @@ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "advice.h" #include "branch.h" @@ -146,7 +145,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base, return READ_TREE_RECURSIVE; len = base->len + strlen(pathname); - ce = make_empty_cache_entry(&the_index, len); + ce = make_empty_cache_entry(the_repository->index, len); oidcpy(&ce->oid, oid); memcpy(ce->name, base->buf, base->len); memcpy(ce->name + base->len, pathname, len - base->len); @@ -159,9 +158,9 @@ static int update_some(const struct object_id *oid, struct strbuf *base, * entry in place. Whether it is UPTODATE or not, checkout_entry will * do the right thing. */ - pos = index_name_pos(&the_index, ce->name, ce->ce_namelen); + pos = index_name_pos(the_repository->index, ce->name, ce->ce_namelen); if (pos >= 0) { - struct cache_entry *old = the_index.cache[pos]; + struct cache_entry *old = the_repository->index->cache[pos]; if (ce->ce_mode == old->ce_mode && !ce_intent_to_add(old) && oideq(&ce->oid, &old->oid)) { @@ -171,7 +170,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base, } } - add_index_entry(&the_index, ce, + add_index_entry(the_repository->index, ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE); return 0; } @@ -190,8 +189,8 @@ static int read_tree_some(struct tree *tree, const struct pathspec *pathspec) static int skip_same_name(const struct cache_entry *ce, int pos) { - while (++pos < the_index.cache_nr && - !strcmp(the_index.cache[pos]->name, ce->name)) + while (++pos < the_repository->index->cache_nr && + !strcmp(the_repository->index->cache[pos]->name, ce->name)) ; /* skip */ return pos; } @@ -199,9 +198,9 @@ static int skip_same_name(const struct cache_entry *ce, int pos) static int check_stage(int stage, const struct cache_entry *ce, int pos, int overlay_mode) { - while (pos < the_index.cache_nr && - !strcmp(the_index.cache[pos]->name, ce->name)) { - if (ce_stage(the_index.cache[pos]) == stage) + while (pos < the_repository->index->cache_nr && + !strcmp(the_repository->index->cache[pos]->name, ce->name)) { + if (ce_stage(the_repository->index->cache[pos]) == stage) return 0; pos++; } @@ -218,8 +217,8 @@ static int check_stages(unsigned stages, const struct cache_entry *ce, int pos) unsigned seen = 0; const char *name = ce->name; - while (pos < the_index.cache_nr) { - ce = the_index.cache[pos]; + while (pos < the_repository->index->cache_nr) { + ce = the_repository->index->cache[pos]; if (strcmp(name, ce->name)) break; seen |= (1 << ce_stage(ce)); @@ -235,10 +234,10 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos, const struct checkout *state, int *nr_checkouts, int overlay_mode) { - while (pos < the_index.cache_nr && - !strcmp(the_index.cache[pos]->name, ce->name)) { - if (ce_stage(the_index.cache[pos]) == stage) - return checkout_entry(the_index.cache[pos], state, + while (pos < the_repository->index->cache_nr && + !strcmp(the_repository->index->cache[pos]->name, ce->name)) { + if (ce_stage(the_repository->index->cache[pos]) == stage) + return checkout_entry(the_repository->index->cache[pos], state, NULL, nr_checkouts); pos++; } @@ -256,7 +255,7 @@ static int checkout_merged(int pos, const struct checkout *state, int *nr_checkouts, struct mem_pool *ce_mem_pool, int conflict_style) { - struct cache_entry *ce = the_index.cache[pos]; + struct cache_entry *ce = the_repository->index->cache[pos]; const char *path = ce->name; mmfile_t ancestor, ours, theirs; enum ll_merge_result merge_status; @@ -269,7 +268,7 @@ static int checkout_merged(int pos, const struct checkout *state, int renormalize = 0; memset(threeway, 0, sizeof(threeway)); - while (pos < the_index.cache_nr) { + while (pos < the_repository->index->cache_nr) { int stage; stage = ce_stage(ce); if (!stage || strcmp(path, ce->name)) @@ -278,7 +277,7 @@ static int checkout_merged(int pos, const struct checkout *state, if (stage == 2) mode = create_ce_mode(ce->ce_mode); pos++; - ce = the_index.cache[pos]; + ce = the_repository->index->cache[pos]; } if (is_null_oid(&threeway[1]) || is_null_oid(&threeway[2])) return error(_("path '%s' does not have necessary versions"), path); @@ -356,7 +355,7 @@ static void mark_ce_for_checkout_overlay(struct cache_entry *ce, * match_pathspec() for _all_ entries when * opts->source_tree != NULL. */ - if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) + if (ce_path_match(the_repository->index, ce, &opts->pathspec, ps_matched)) ce->ce_flags |= CE_MATCHED; } @@ -367,7 +366,7 @@ static void mark_ce_for_checkout_no_overlay(struct cache_entry *ce, ce->ce_flags &= ~CE_MATCHED; if (!opts->ignore_skipworktree && ce_skip_worktree(ce)) return; - if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) { + if (ce_path_match(the_repository->index, ce, &opts->pathspec, ps_matched)) { ce->ce_flags |= CE_MATCHED; if (opts->source_tree && !(ce->ce_flags & CE_UPDATE)) /* @@ -391,7 +390,7 @@ static int checkout_worktree(const struct checkout_opts *opts, state.force = 1; state.refresh_cache = 1; - state.istate = &the_index; + state.istate = the_repository->index; mem_pool_init(&ce_mem_pool, 0); get_parallel_checkout_configs(&pc_workers, &pc_threshold); @@ -404,8 +403,8 @@ static int checkout_worktree(const struct checkout_opts *opts, if (pc_workers > 1) init_parallel_checkout(); - for (pos = 0; pos < the_index.cache_nr; pos++) { - struct cache_entry *ce = the_index.cache[pos]; + for (pos = 0; pos < the_repository->index->cache_nr; pos++) { + struct cache_entry *ce = the_repository->index->cache[pos]; if (ce->ce_flags & CE_MATCHED) { if (!ce_stage(ce)) { errs |= checkout_entry(ce, &state, @@ -429,7 +428,7 @@ static int checkout_worktree(const struct checkout_opts *opts, errs |= run_parallel_checkout(&state, pc_workers, pc_threshold, NULL, NULL); mem_pool_discard(&ce_mem_pool, should_validate_cache_entries()); - remove_marked_cache_entries(&the_index, 1); + remove_marked_cache_entries(the_repository->index, 1); remove_scheduled_dirs(); errs |= finish_delayed_checkout(&state, opts->show_progress); @@ -571,7 +570,7 @@ static int checkout_paths(const struct checkout_opts *opts, if (opts->source_tree) read_tree_some(opts->source_tree, &opts->pathspec); if (opts->merge) - unmerge_index(&the_index, &opts->pathspec, CE_MATCHED); + unmerge_index(the_repository->index, &opts->pathspec, CE_MATCHED); ps_matched = xcalloc(opts->pathspec.nr, 1); @@ -579,13 +578,13 @@ static int checkout_paths(const struct checkout_opts *opts, * Make sure all pathspecs participated in locating the paths * to be checked out. */ - for (pos = 0; pos < the_index.cache_nr; pos++) + for (pos = 0; pos < the_repository->index->cache_nr; pos++) if (opts->overlay_mode) - mark_ce_for_checkout_overlay(the_index.cache[pos], + mark_ce_for_checkout_overlay(the_repository->index->cache[pos], ps_matched, opts); else - mark_ce_for_checkout_no_overlay(the_index.cache[pos], + mark_ce_for_checkout_no_overlay(the_repository->index->cache[pos], ps_matched, opts); @@ -596,8 +595,8 @@ static int checkout_paths(const struct checkout_opts *opts, free(ps_matched); /* Any unmerged paths? */ - for (pos = 0; pos < the_index.cache_nr; pos++) { - const struct cache_entry *ce = the_index.cache[pos]; + for (pos = 0; pos < the_repository->index->cache_nr; pos++) { + const struct cache_entry *ce = the_repository->index->cache[pos]; if (ce->ce_flags & CE_MATCHED) { if (!ce_stage(ce)) continue; @@ -622,7 +621,7 @@ static int checkout_paths(const struct checkout_opts *opts, if (opts->checkout_worktree) errs |= checkout_worktree(opts, new_branch_info); else - remove_marked_cache_entries(&the_index, 1); + remove_marked_cache_entries(the_repository->index, 1); /* * Allow updating the index when checking out from the index. @@ -634,7 +633,7 @@ static int checkout_paths(const struct checkout_opts *opts, checkout_index = opts->checkout_index; if (checkout_index) { - if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) + if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); } else { /* @@ -704,8 +703,8 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o, opts.merge = 1; opts.fn = oneway_merge; opts.verbose_update = o->show_progress; - opts.src_index = &the_index; - opts.dst_index = &the_index; + opts.src_index = the_repository->index; + opts.dst_index = the_repository->index; init_checkout_metadata(&opts.meta, info->refname, info->commit ? &info->commit->object.oid : null_oid(), NULL); @@ -757,12 +756,12 @@ static void init_topts(struct unpack_trees_options *topts, int merge, { memset(topts, 0, sizeof(*topts)); topts->head_idx = -1; - topts->src_index = &the_index; - topts->dst_index = &the_index; + topts->src_index = the_repository->index; + topts->dst_index = the_repository->index; setup_unpack_trees_porcelain(topts, "checkout"); - topts->initial_checkout = is_index_unborn(&the_index); + topts->initial_checkout = is_index_unborn(the_repository->index); topts->update = 1; topts->merge = 1; topts->quiet = merge && old_commit; @@ -784,7 +783,7 @@ static int merge_working_tree(const struct checkout_opts *opts, if (repo_read_index_preload(the_repository, NULL, 0) < 0) return error(_("index file corrupt")); - resolve_undo_clear_index(&the_index); + resolve_undo_clear_index(the_repository->index); if (opts->new_orphan_branch && opts->orphan_from_empty_tree) { if (new_branch_info->commit) BUG("'switch --orphan' should never accept a commit as starting point"); @@ -808,9 +807,9 @@ static int merge_working_tree(const struct checkout_opts *opts, struct unpack_trees_options topts; const struct object_id *old_commit_oid; - refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL); + refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL); - if (unmerged_index(&the_index)) { + if (unmerged_index(the_repository->index)) { error(_("you need to resolve your current index first")); return 1; } @@ -920,10 +919,10 @@ static int merge_working_tree(const struct checkout_opts *opts, } } - if (!cache_tree_fully_valid(the_index.cache_tree)) - cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR); + if (!cache_tree_fully_valid(the_repository->index->cache_tree)) + cache_tree_update(the_repository->index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR); - if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) + if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); if (!opts->discard_changes && !opts->quiet && new_branch_info->commit) diff --git a/builtin/clean.c b/builtin/clean.c index 29efe84153..ded5a91534 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -6,7 +6,6 @@ * Based on git-clean.sh by Pavel Roskin */ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "abspath.h" #include "config.h" @@ -714,7 +713,7 @@ static int filter_by_patterns_cmd(void) for_each_string_list_item(item, &del_list) { int dtype = DT_UNKNOWN; - if (is_excluded(&dir, &the_index, item->string, &dtype)) { + if (is_excluded(&dir, the_repository->index, item->string, &dtype)) { *item->string = '\0'; changed++; } @@ -1021,7 +1020,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) PATHSPEC_PREFER_CWD, prefix, argv); - fill_directory(&dir, &the_index, &pathspec); + fill_directory(&dir, the_repository->index, &pathspec); correct_untracked_entries(&dir); for (i = 0; i < dir.nr; i++) { @@ -1029,7 +1028,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) struct stat st; const char *rel; - if (!index_name_is_other(&the_index, ent->name, ent->len)) + if (!index_name_is_other(the_repository->index, ent->name, ent->len)) continue; if (lstat(ent->name, &st)) diff --git a/builtin/clone.c b/builtin/clone.c index f279b84a84..554b29768c 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -8,7 +8,6 @@ * Clone a repository into a different directory that does not yet exist. */ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "abspath.h" #include "advice.h" @@ -329,7 +328,20 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest, int src_len, dest_len; struct dir_iterator *iter; int iter_status; - struct strbuf realpath = STRBUF_INIT; + + /* + * Refuse copying directories by default which aren't owned by us. The + * code that performs either the copying or hardlinking is not prepared + * to handle various edge cases where an adversary may for example + * racily swap out files for symlinks. This can cause us to + * inadvertently use the wrong source file. + * + * Furthermore, even if we were prepared to handle such races safely, + * creating hardlinks across user boundaries is an inherently unsafe + * operation as the hardlinked files can be rewritten at will by the + * potentially-untrusted user. We thus refuse to do so by default. + */ + die_upon_dubious_ownership(NULL, NULL, src_repo); mkdir_if_missing(dest->buf, 0777); @@ -377,9 +389,27 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest, if (unlink(dest->buf) && errno != ENOENT) die_errno(_("failed to unlink '%s'"), dest->buf); if (!option_no_hardlinks) { - strbuf_realpath(&realpath, src->buf, 1); - if (!link(realpath.buf, dest->buf)) + if (!link(src->buf, dest->buf)) { + struct stat st; + + /* + * Sanity-check whether the created hardlink + * actually links to the expected file now. This + * catches time-of-check-time-of-use bugs in + * case the source file was meanwhile swapped. + */ + if (lstat(dest->buf, &st)) + die(_("hardlink cannot be checked at '%s'"), dest->buf); + if (st.st_mode != iter->st.st_mode || + st.st_ino != iter->st.st_ino || + st.st_dev != iter->st.st_dev || + st.st_size != iter->st.st_size || + st.st_uid != iter->st.st_uid || + st.st_gid != iter->st.st_gid) + die(_("hardlink different from source at '%s'"), dest->buf); + continue; + } if (option_local > 0) die_errno(_("failed to create link '%s'"), dest->buf); option_no_hardlinks = 1; @@ -392,8 +422,6 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest, strbuf_setlen(src, src_len); die(_("failed to iterate over '%s'"), src->buf); } - - strbuf_release(&realpath); } static void clone_local(const char *src_repo, const char *dest_repo) @@ -737,8 +765,8 @@ static int checkout(int submodule_progress, int filter_submodules) opts.preserve_ignored = 0; opts.fn = oneway_merge; opts.verbose_update = (option_verbosity >= 0); - opts.src_index = &the_index; - opts.dst_index = &the_index; + opts.src_index = the_repository->index; + opts.dst_index = the_repository->index; init_checkout_metadata(&opts.meta, head, &oid, NULL); tree = parse_tree_indirect(&oid); @@ -752,7 +780,7 @@ static int checkout(int submodule_progress, int filter_submodules) free(head); - if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) + if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); err |= run_hooks_l("post-checkout", oid_to_hex(null_oid()), @@ -944,6 +972,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) int hash_algo; unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN; const int do_not_override_repo_unix_permissions = -1; + const char *template_dir; + char *template_dir_dup = NULL; struct transport_ls_refs_options transport_ls_refs_options = TRANSPORT_LS_REFS_OPTIONS_INIT; @@ -963,6 +993,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix) usage_msg_opt(_("You must specify a repository to clone."), builtin_clone_usage, builtin_clone_options); + xsetenv("GIT_CLONE_PROTECTION_ACTIVE", "true", 0 /* allow user override */); + template_dir = get_template_dir(option_template); + if (*template_dir && !is_absolute_path(template_dir)) + template_dir = template_dir_dup = + absolute_pathdup(template_dir); + xsetenv("GIT_CLONE_TEMPLATE_DIR", template_dir, 1); + if (option_depth || option_since || option_not.nr) deepen = 1; if (option_single_branch == -1) @@ -1124,7 +1161,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) * repository, and reference backends may persist that information into * their on-disk data structures. */ - init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, + init_db(git_dir, real_git_dir, template_dir, GIT_HASH_UNKNOWN, ref_storage_format, NULL, do_not_override_repo_unix_permissions, INIT_DB_QUIET | INIT_DB_SKIP_REFDB); @@ -1513,6 +1550,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) free(dir); free(path); free(repo_to_free); + free(template_dir_dup); junk_mode = JUNK_LEAVE_ALL; transport_ls_refs_options_release(&transport_ls_refs_options); diff --git a/builtin/commit.c b/builtin/commit.c index 6e1484446b..78bfae2164 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -5,7 +5,6 @@ * Based on git-commit.sh by Junio C Hamano and Linus Torvalds */ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "advice.h" #include "config.h" @@ -38,6 +37,7 @@ #include "commit-reach.h" #include "commit-graph.h" #include "pretty.h" +#include "trailer.h" static const char * const builtin_commit_usage[] = { N_("git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n" @@ -142,14 +142,6 @@ static struct strbuf message = STRBUF_INIT; static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED; -static int opt_pass_trailer(const struct option *opt, const char *arg, int unset) -{ - BUG_ON_OPT_NEG(unset); - - strvec_pushl(opt->value, "--trailer", arg, NULL); - return 0; -} - static int opt_parse_porcelain(const struct option *opt, const char *arg, int unset) { enum wt_status_format *value = (enum wt_status_format *)opt->value; @@ -266,19 +258,19 @@ static int list_paths(struct string_list *list, const char *with_tree, if (with_tree) { char *max_prefix = common_prefix(pattern); - overlay_tree_on_index(&the_index, with_tree, max_prefix); + overlay_tree_on_index(the_repository->index, with_tree, max_prefix); free(max_prefix); } /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(&the_index); - for (i = 0; i < the_index.cache_nr; i++) { - const struct cache_entry *ce = the_index.cache[i]; + ensure_full_index(the_repository->index); + for (i = 0; i < the_repository->index->cache_nr; i++) { + const struct cache_entry *ce = the_repository->index->cache[i]; struct string_list_item *item; if (ce->ce_flags & CE_UPDATE) continue; - if (!ce_path_match(&the_index, ce, pattern, m)) + if (!ce_path_match(the_repository->index, ce, pattern, m)) continue; item = string_list_insert(list, ce->name); if (ce_skip_worktree(ce)) @@ -302,10 +294,10 @@ static void add_remove_files(struct string_list *list) continue; if (!lstat(p->string, &st)) { - if (add_to_index(&the_index, p->string, &st, 0)) + if (add_to_index(the_repository->index, p->string, &st, 0)) die(_("updating files failed")); } else - remove_file_from_index(&the_index, p->string); + remove_file_from_index(the_repository->index, p->string); } } @@ -316,7 +308,7 @@ static void create_base_index(const struct commit *current_head) struct tree_desc t; if (!current_head) { - discard_index(&the_index); + discard_index(the_repository->index); return; } @@ -324,8 +316,8 @@ static void create_base_index(const struct commit *current_head) opts.head_idx = 1; opts.index_only = 1; opts.merge = 1; - opts.src_index = &the_index; - opts.dst_index = &the_index; + opts.src_index = the_repository->index; + opts.dst_index = the_repository->index; opts.fn = oneway_merge; tree = parse_tree_indirect(¤t_head->object.oid); @@ -344,7 +336,7 @@ static void refresh_cache_or_die(int refresh_flags) * refresh_flags contains REFRESH_QUIET, so the only errors * are for unmerged entries. */ - if (refresh_index(&the_index, refresh_flags | REFRESH_IN_PORCELAIN, NULL, NULL, NULL)) + if (refresh_index(the_repository->index, refresh_flags | REFRESH_IN_PORCELAIN, NULL, NULL, NULL)) die_resolve_conflict("commit"); } @@ -393,7 +385,7 @@ static const char *prepare_index(const char **argv, const char *prefix, refresh_cache_or_die(refresh_flags); - if (write_locked_index(&the_index, &index_lock, 0)) + if (write_locked_index(the_repository->index, &index_lock, 0)) die(_("unable to create temporary index")); old_repo_index_file = the_repository->index_file; @@ -412,13 +404,13 @@ static const char *prepare_index(const char **argv, const char *prefix, unsetenv(INDEX_ENVIRONMENT); FREE_AND_NULL(old_index_env); - discard_index(&the_index); - read_index_from(&the_index, get_lock_file_path(&index_lock), + discard_index(the_repository->index); + read_index_from(the_repository->index, get_lock_file_path(&index_lock), get_git_dir()); - if (cache_tree_update(&the_index, WRITE_TREE_SILENT) == 0) { + if (cache_tree_update(the_repository->index, WRITE_TREE_SILENT) == 0) { if (reopen_lock_file(&index_lock) < 0) die(_("unable to write index file")); - if (write_locked_index(&the_index, &index_lock, 0)) + if (write_locked_index(the_repository->index, &index_lock, 0)) die(_("unable to update temporary index")); } else warning(_("Failed to update main cache tree")); @@ -450,8 +442,8 @@ static const char *prepare_index(const char **argv, const char *prefix, exit(128); refresh_cache_or_die(refresh_flags); - cache_tree_update(&the_index, WRITE_TREE_SILENT); - if (write_locked_index(&the_index, &index_lock, 0)) + cache_tree_update(the_repository->index, WRITE_TREE_SILENT); + if (write_locked_index(the_repository->index, &index_lock, 0)) die(_("unable to write new index file")); commit_style = COMMIT_NORMAL; ret = get_lock_file_path(&index_lock); @@ -472,10 +464,10 @@ static const char *prepare_index(const char **argv, const char *prefix, repo_hold_locked_index(the_repository, &index_lock, LOCK_DIE_ON_ERROR); refresh_cache_or_die(refresh_flags); - if (the_index.cache_changed - || !cache_tree_fully_valid(the_index.cache_tree)) - cache_tree_update(&the_index, WRITE_TREE_SILENT); - if (write_locked_index(&the_index, &index_lock, + if (the_repository->index->cache_changed + || !cache_tree_fully_valid(the_repository->index->cache_tree)) + cache_tree_update(the_repository->index, WRITE_TREE_SILENT); + if (write_locked_index(the_repository->index, &index_lock, COMMIT_LOCK | SKIP_IF_UNCHANGED)) die(_("unable to write new index file")); commit_style = COMMIT_AS_IS; @@ -516,15 +508,15 @@ static const char *prepare_index(const char **argv, const char *prefix, if (list_paths(&partial, !current_head ? NULL : "HEAD", &pathspec)) exit(1); - discard_index(&the_index); + discard_index(the_repository->index); if (repo_read_index(the_repository) < 0) die(_("cannot read the index")); repo_hold_locked_index(the_repository, &index_lock, LOCK_DIE_ON_ERROR); add_remove_files(&partial); - refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL); - cache_tree_update(&the_index, WRITE_TREE_SILENT); - if (write_locked_index(&the_index, &index_lock, 0)) + refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL); + cache_tree_update(the_repository->index, WRITE_TREE_SILENT); + if (write_locked_index(the_repository->index, &index_lock, 0)) die(_("unable to write new index file")); hold_lock_file_for_update(&false_lock, @@ -534,14 +526,14 @@ static const char *prepare_index(const char **argv, const char *prefix, create_base_index(current_head); add_remove_files(&partial); - refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL); + refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL); - if (write_locked_index(&the_index, &false_lock, 0)) + if (write_locked_index(the_repository->index, &false_lock, 0)) die(_("unable to write temporary index file")); - discard_index(&the_index); + discard_index(the_repository->index); ret = get_lock_file_path(&false_lock); - read_index_from(&the_index, ret, get_git_dir()); + read_index_from(the_repository->index, ret, get_git_dir()); out: string_list_clear(&partial, 0); clear_pathspec(&pathspec); @@ -999,7 +991,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, struct object_id oid; const char *parent = "HEAD"; - if (!the_index.initialized && repo_read_index(the_repository) < 0) + if (!the_repository->index->initialized && repo_read_index(the_repository) < 0) die(_("Cannot read index")); if (amend) @@ -1009,11 +1001,11 @@ static int prepare_to_commit(const char *index_file, const char *prefix, int i, ita_nr = 0; /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(&the_index); - for (i = 0; i < the_index.cache_nr; i++) - if (ce_intent_to_add(the_index.cache[i])) + ensure_full_index(the_repository->index); + for (i = 0; i < the_repository->index->cache_nr; i++) + if (ce_intent_to_add(the_repository->index->cache[i])) ita_nr++; - committable = the_index.cache_nr - ita_nr > 0; + committable = the_repository->index->cache_nr - ita_nr > 0; } else { /* * Unless the user did explicitly request a submodule @@ -1038,14 +1030,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, fclose(s->fp); if (trailer_args.nr) { - struct child_process run_trailer = CHILD_PROCESS_INIT; - - strvec_pushl(&run_trailer.args, "interpret-trailers", - "--in-place", "--no-divider", - git_path_commit_editmsg(), NULL); - strvec_pushv(&run_trailer.args, trailer_args.v); - run_trailer.git_cmd = 1; - if (run_command(&run_trailer)) + if (amend_file_with_trailers(git_path_commit_editmsg(), &trailer_args)) die(_("unable to pass trailers to --trailers")); strvec_clear(&trailer_args); } @@ -1081,11 +1066,11 @@ static int prepare_to_commit(const char *index_file, const char *prefix, * and could have updated it. We must do this before we invoke * the editor and after we invoke run_status above. */ - discard_index(&the_index); + discard_index(the_repository->index); } - read_index_from(&the_index, index_file, get_git_dir()); + read_index_from(the_repository->index, index_file, get_git_dir()); - if (cache_tree_update(&the_index, 0)) { + if (cache_tree_update(the_repository->index, 0)) { error(_("Error building trees")); return 0; } @@ -1586,7 +1571,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) status_format != STATUS_FORMAT_PORCELAIN_V2) progress_flag = REFRESH_PROGRESS; repo_read_index(the_repository); - refresh_index(&the_index, + refresh_index(the_repository->index, REFRESH_QUIET|REFRESH_UNMERGED|progress_flag, &s.pathspec, NULL, NULL); @@ -1673,7 +1658,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) OPT_STRING(0, "fixup", &fixup_message, N_("[(amend|reword):]commit"), N_("use autosquash formatted message to fixup or amend/reword specified commit")), OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash specified commit")), OPT_BOOL(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")), - OPT_CALLBACK_F(0, "trailer", &trailer_args, N_("trailer"), N_("add custom trailer(s)"), PARSE_OPT_NONEG, opt_pass_trailer), + OPT_PASSTHRU_ARGV(0, "trailer", &trailer_args, N_("trailer"), N_("add custom trailer(s)"), PARSE_OPT_NONEG), OPT_BOOL('s', "signoff", &signoff, N_("add a Signed-off-by trailer")), OPT_FILENAME('t', "template", &template_file, N_("use specified template file")), OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")), @@ -1856,7 +1841,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) append_merge_tag_headers(parents, &tail); } - if (commit_tree_extended(sb.buf, sb.len, &the_index.cache_tree->oid, + if (commit_tree_extended(sb.buf, sb.len, &the_repository->index->cache_tree->oid, parents, &oid, author_ident.buf, NULL, sign_commit, extra)) { rollback_index_files(); diff --git a/builtin/config.c b/builtin/config.c index 0015620dde..80aa9d8a66 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -16,7 +16,49 @@ #include "worktree.h" static const char *const builtin_config_usage[] = { - N_("git config [<options>]"), + N_("git config list [<file-option>] [<display-option>] [--includes]"), + N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>"), + N_("git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>"), + N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> <value>"), + N_("git config rename-section [<file-option>] <old-name> <new-name>"), + N_("git config remove-section [<file-option>] <name>"), + N_("git config edit [<file-option>]"), + N_("git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"), + NULL +}; + +static const char *const builtin_config_list_usage[] = { + N_("git config list [<file-option>] [<display-option>] [--includes]"), + NULL +}; + +static const char *const builtin_config_get_usage[] = { + N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>"), + NULL +}; + +static const char *const builtin_config_set_usage[] = { + N_("git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] [--value=<value>] [--fixed-value] <name> <value>"), + NULL +}; + +static const char *const builtin_config_unset_usage[] = { + N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> <value>"), + NULL +}; + +static const char *const builtin_config_rename_section_usage[] = { + N_("git config rename-section [<file-option>] <old-name> <new-name>"), + NULL +}; + +static const char *const builtin_config_remove_section_usage[] = { + N_("git config remove-section [<file-option>] <name>"), + NULL +}; + +static const char *const builtin_config_edit_usage[] = { + N_("git config edit [<file-option>]"), NULL }; @@ -33,6 +75,7 @@ static char delim = '='; static char key_delim = ' '; static char term = '\n'; +static parse_opt_subcommand_fn *subcommand; static int use_global_config, use_system_config, use_local_config; static int use_worktree_config; static struct git_config_source given_config_source; @@ -44,7 +87,7 @@ static struct config_options config_options; static int show_origin; static int show_scope; static int fixed_value; -static const char *comment; +static const char *comment_arg; #define ACTION_GET (1<<0) #define ACTION_GET_ALL (1<<1) @@ -135,54 +178,6 @@ static int option_parse_type(const struct option *opt, const char *arg, return 0; } -static struct option builtin_config_options[] = { - OPT_GROUP(N_("Config file location")), - OPT_BOOL(0, "global", &use_global_config, N_("use global config file")), - OPT_BOOL(0, "system", &use_system_config, N_("use system config file")), - OPT_BOOL(0, "local", &use_local_config, N_("use repository config file")), - OPT_BOOL(0, "worktree", &use_worktree_config, N_("use per-worktree config file")), - OPT_STRING('f', "file", &given_config_source.file, N_("file"), N_("use given config file")), - OPT_STRING(0, "blob", &given_config_source.blob, N_("blob-id"), N_("read config from given blob object")), - OPT_GROUP(N_("Action")), - OPT_BIT(0, "get", &actions, N_("get value: name [value-pattern]"), ACTION_GET), - OPT_BIT(0, "get-all", &actions, N_("get all values: key [value-pattern]"), ACTION_GET_ALL), - OPT_BIT(0, "get-regexp", &actions, N_("get values for regexp: name-regex [value-pattern]"), ACTION_GET_REGEXP), - OPT_BIT(0, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH), - OPT_BIT(0, "replace-all", &actions, N_("replace all matching variables: name value [value-pattern]"), ACTION_REPLACE_ALL), - OPT_BIT(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD), - OPT_BIT(0, "unset", &actions, N_("remove a variable: name [value-pattern]"), ACTION_UNSET), - OPT_BIT(0, "unset-all", &actions, N_("remove all matches: name [value-pattern]"), ACTION_UNSET_ALL), - OPT_BIT(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION), - OPT_BIT(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION), - OPT_BIT('l', "list", &actions, N_("list all"), ACTION_LIST), - OPT_BOOL(0, "fixed-value", &fixed_value, N_("use string equality when comparing values to 'value-pattern'")), - OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT), - OPT_BIT(0, "get-color", &actions, N_("find the color configured: slot [default]"), ACTION_GET_COLOR), - OPT_BIT(0, "get-colorbool", &actions, N_("find the color setting: slot [stdout-is-tty]"), ACTION_GET_COLORBOOL), - OPT_GROUP(N_("Type")), - OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type), - OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL), - OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT), - OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT), - OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR), - OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH), - OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE), - OPT_GROUP(N_("Other")), - OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")), - OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")), - OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")), - OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")), - OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (worktree, local, global, system, command)")), - OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")), - OPT_STRING(0, "comment", &comment, N_("value"), N_("human-readable comment string (# will be prepended as needed)")), - OPT_END(), -}; - -static NORETURN void usage_builtin_config(void) -{ - usage_with_options(builtin_config_usage, builtin_config_options); -} - static void check_argc(int argc, int min, int max) { if (argc >= min && argc <= max) @@ -671,20 +666,8 @@ static char *default_user_config(void) return strbuf_detach(&buf, NULL); } -int cmd_config(int argc, const char **argv, const char *prefix) +static void handle_config_location(const char *prefix) { - int nongit = !startup_info->have_repository; - char *value = NULL; - int flags = 0; - int ret = 0; - struct key_value_info default_kvi = KVI_INIT; - - given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT)); - - argc = parse_options(argc, argv, prefix, builtin_config_options, - builtin_config_usage, - PARSE_OPT_STOP_AT_NON_OPTION); - if (use_global_config + use_system_config + use_local_config + use_worktree_config + !!given_config_source.file + !!given_config_source.blob > 1) { @@ -692,14 +675,13 @@ int cmd_config(int argc, const char **argv, const char *prefix) usage_builtin_config(); } - if (nongit) { + if (!startup_info->have_repository) { if (use_local_config) die(_("--local can only be used inside a git repository")); if (given_config_source.blob) die(_("--blob can only be used inside a git repository")); if (use_worktree_config) die(_("--worktree can only be used inside a git repository")); - } if (given_config_source.file && @@ -753,26 +735,384 @@ int cmd_config(int argc, const char **argv, const char *prefix) config_options.respect_includes = !given_config_source.file; else config_options.respect_includes = respect_includes_opt; - if (!nongit) { + if (startup_info->have_repository) { config_options.commondir = get_git_common_dir(); config_options.git_dir = get_git_dir(); } +} +static void handle_nul(void) { if (end_nul) { term = '\0'; delim = '\n'; key_delim = '\n'; } +} + +#define CONFIG_LOCATION_OPTIONS \ + OPT_GROUP(N_("Config file location")), \ + OPT_BOOL(0, "global", &use_global_config, N_("use global config file")), \ + OPT_BOOL(0, "system", &use_system_config, N_("use system config file")), \ + OPT_BOOL(0, "local", &use_local_config, N_("use repository config file")), \ + OPT_BOOL(0, "worktree", &use_worktree_config, N_("use per-worktree config file")), \ + OPT_STRING('f', "file", &given_config_source.file, N_("file"), N_("use given config file")), \ + OPT_STRING(0, "blob", &given_config_source.blob, N_("blob-id"), N_("read config from given blob object")) + +#define CONFIG_TYPE_OPTIONS \ + OPT_GROUP(N_("Type")), \ + OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type), \ + OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL), \ + OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT), \ + OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT), \ + OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR), \ + OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH), \ + OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE) + +#define CONFIG_DISPLAY_OPTIONS \ + OPT_GROUP(N_("Display options")), \ + OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")), \ + OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")), \ + OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")), \ + OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (worktree, local, global, system, command)")) + +static struct option builtin_config_options[] = { + CONFIG_LOCATION_OPTIONS, + OPT_GROUP(N_("Action")), + OPT_CMDMODE(0, "get", &actions, N_("get value: name [<value-pattern>]"), ACTION_GET), + OPT_CMDMODE(0, "get-all", &actions, N_("get all values: key [<value-pattern>]"), ACTION_GET_ALL), + OPT_CMDMODE(0, "get-regexp", &actions, N_("get values for regexp: name-regex [<value-pattern>]"), ACTION_GET_REGEXP), + OPT_CMDMODE(0, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH), + OPT_CMDMODE(0, "replace-all", &actions, N_("replace all matching variables: name value [<value-pattern>]"), ACTION_REPLACE_ALL), + OPT_CMDMODE(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD), + OPT_CMDMODE(0, "unset", &actions, N_("remove a variable: name [<value-pattern>]"), ACTION_UNSET), + OPT_CMDMODE(0, "unset-all", &actions, N_("remove all matches: name [<value-pattern>]"), ACTION_UNSET_ALL), + OPT_CMDMODE(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION), + OPT_CMDMODE(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION), + OPT_CMDMODE('l', "list", &actions, N_("list all"), ACTION_LIST), + OPT_CMDMODE('e', "edit", &actions, N_("open an editor"), ACTION_EDIT), + OPT_CMDMODE(0, "get-color", &actions, N_("find the color configured: slot [<default>]"), ACTION_GET_COLOR), + OPT_CMDMODE(0, "get-colorbool", &actions, N_("find the color setting: slot [<stdout-is-tty>]"), ACTION_GET_COLORBOOL), + CONFIG_TYPE_OPTIONS, + CONFIG_DISPLAY_OPTIONS, + OPT_GROUP(N_("Other")), + OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")), + OPT_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")), + OPT_BOOL(0, "fixed-value", &fixed_value, N_("use string equality when comparing values to 'value-pattern'")), + OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")), + OPT_END(), +}; + +static NORETURN void usage_builtin_config(void) +{ + usage_with_options(builtin_config_usage, builtin_config_options); +} + +static int cmd_config_list(int argc, const char **argv, const char *prefix) +{ + struct option opts[] = { + CONFIG_LOCATION_OPTIONS, + CONFIG_DISPLAY_OPTIONS, + OPT_GROUP(N_("Other")), + OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")), + OPT_END(), + }; + + argc = parse_options(argc, argv, prefix, opts, builtin_config_list_usage, 0); + check_argc(argc, 0, 0); + + handle_config_location(prefix); + handle_nul(); + + setup_auto_pager("config", 1); + + if (config_with_options(show_all_config, NULL, + &given_config_source, the_repository, + &config_options) < 0) { + if (given_config_source.file) + die_errno(_("unable to read config file '%s'"), + given_config_source.file); + else + die(_("error processing config file(s)")); + } + + return 0; +} + +static int cmd_config_get(int argc, const char **argv, const char *prefix) +{ + const char *value_pattern = NULL, *url = NULL; + int flags = 0; + struct option opts[] = { + CONFIG_LOCATION_OPTIONS, + CONFIG_TYPE_OPTIONS, + OPT_GROUP(N_("Filter options")), + OPT_BOOL(0, "all", &do_all, N_("return all values for multi-valued config options")), + OPT_BOOL(0, "regexp", &use_key_regexp, N_("interpret the name as a regular expression")), + OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")), + OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE), + OPT_STRING(0, "url", &url, N_("URL"), N_("show config matching the given URL")), + CONFIG_DISPLAY_OPTIONS, + OPT_BOOL(0, "show-names", &show_keys, N_("show config keys in addition to their values")), + OPT_GROUP(N_("Other")), + OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")), + OPT_STRING(0, "default", &default_value, N_("value"), N_("use default value when missing entry")), + OPT_END(), + }; + + argc = parse_options(argc, argv, prefix, opts, builtin_config_get_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + check_argc(argc, 1, 1); + + if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern) + die(_("--fixed-value only applies with 'value-pattern'")); + if (default_value && (do_all || url)) + die(_("--default= cannot be used with --all or --url=")); + if (url && (do_all || use_key_regexp || value_pattern)) + die(_("--url= cannot be used with --all, --regexp or --value")); + + handle_config_location(prefix); + handle_nul(); + + setup_auto_pager("config", 1); + + if (url) + return get_urlmatch(argv[0], url); + return get_value(argv[0], value_pattern, flags); +} + +static int cmd_config_set(int argc, const char **argv, const char *prefix) +{ + const char *value_pattern = NULL, *comment_arg = NULL; + char *comment = NULL; + int flags = 0, append = 0; + struct option opts[] = { + CONFIG_LOCATION_OPTIONS, + CONFIG_TYPE_OPTIONS, + OPT_GROUP(N_("Filter")), + OPT_BIT(0, "all", &flags, N_("replace multi-valued config option with new value"), CONFIG_FLAGS_MULTI_REPLACE), + OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")), + OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE), + OPT_GROUP(N_("Other")), + OPT_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")), + OPT_BOOL(0, "append", &append, N_("add a new line without altering any existing values")), + OPT_END(), + }; + struct key_value_info default_kvi = KVI_INIT; + char *value; + int ret; + + argc = parse_options(argc, argv, prefix, opts, builtin_config_set_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + check_write(); + check_argc(argc, 2, 2); + + if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern) + die(_("--fixed-value only applies with --value=<pattern>")); + if (append && value_pattern) + die(_("--append cannot be used with --value=<pattern>")); + if (append) + value_pattern = CONFIG_REGEX_NONE; + + comment = git_config_prepare_comment_string(comment_arg); + + handle_config_location(prefix); + + value = normalize_value(argv[0], argv[1], &default_kvi); + + if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern) { + ret = git_config_set_multivar_in_file_gently(given_config_source.file, + argv[0], value, value_pattern, + comment, flags); + } else { + ret = git_config_set_in_file_gently(given_config_source.file, + argv[0], comment, value); + if (ret == CONFIG_NOTHING_SET) + error(_("cannot overwrite multiple values with a single value\n" + " Use a regexp, --add or --replace-all to change %s."), argv[0]); + } + + free(comment); + free(value); + return ret; +} + +static int cmd_config_unset(int argc, const char **argv, const char *prefix) +{ + const char *value_pattern = NULL; + int flags = 0; + struct option opts[] = { + CONFIG_LOCATION_OPTIONS, + OPT_GROUP(N_("Filter")), + OPT_BIT(0, "all", &flags, N_("replace multi-valued config option with new value"), CONFIG_FLAGS_MULTI_REPLACE), + OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")), + OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE), + OPT_END(), + }; + + argc = parse_options(argc, argv, prefix, opts, builtin_config_unset_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + check_write(); + check_argc(argc, 1, 1); + + if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern) + die(_("--fixed-value only applies with 'value-pattern'")); + + handle_config_location(prefix); + + if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern) + return git_config_set_multivar_in_file_gently(given_config_source.file, + argv[0], NULL, value_pattern, + NULL, flags); + else + return git_config_set_in_file_gently(given_config_source.file, argv[0], + NULL, NULL); +} + +static int cmd_config_rename_section(int argc, const char **argv, const char *prefix) +{ + struct option opts[] = { + CONFIG_LOCATION_OPTIONS, + OPT_END(), + }; + int ret; + + argc = parse_options(argc, argv, prefix, opts, builtin_config_rename_section_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + check_write(); + check_argc(argc, 2, 2); + + handle_config_location(prefix); + + ret = git_config_rename_section_in_file(given_config_source.file, + argv[0], argv[1]); + if (ret < 0) + return ret; + else if (!ret) + die(_("no such section: %s"), argv[0]); + + return 0; +} + +static int cmd_config_remove_section(int argc, const char **argv, const char *prefix) +{ + struct option opts[] = { + CONFIG_LOCATION_OPTIONS, + OPT_END(), + }; + int ret; + + argc = parse_options(argc, argv, prefix, opts, builtin_config_remove_section_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + check_write(); + check_argc(argc, 1, 1); + + handle_config_location(prefix); + + ret = git_config_rename_section_in_file(given_config_source.file, + argv[0], NULL); + if (ret < 0) + return ret; + else if (!ret) + die(_("no such section: %s"), argv[0]); + + return 0; +} + +static int show_editor(void) +{ + char *config_file; + + if (!given_config_source.file && !startup_info->have_repository) + die(_("not in a git directory")); + if (given_config_source.use_stdin) + die(_("editing stdin is not supported")); + if (given_config_source.blob) + die(_("editing blobs is not supported")); + git_config(git_default_config, NULL); + config_file = given_config_source.file ? + xstrdup(given_config_source.file) : + git_pathdup("config"); + if (use_global_config) { + int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666); + if (fd >= 0) { + char *content = default_user_config(); + write_str_in_full(fd, content); + free(content); + close(fd); + } + else if (errno != EEXIST) + die_errno(_("cannot create configuration file %s"), config_file); + } + launch_editor(config_file, NULL, NULL); + free(config_file); + + return 0; +} + +static int cmd_config_edit(int argc, const char **argv, const char *prefix) +{ + struct option opts[] = { + CONFIG_LOCATION_OPTIONS, + OPT_END(), + }; + + argc = parse_options(argc, argv, prefix, opts, builtin_config_edit_usage, 0); + check_write(); + check_argc(argc, 0, 0); + + handle_config_location(prefix); + + return show_editor(); +} + +static struct option builtin_subcommand_options[] = { + OPT_SUBCOMMAND("list", &subcommand, cmd_config_list), + OPT_SUBCOMMAND("get", &subcommand, cmd_config_get), + OPT_SUBCOMMAND("set", &subcommand, cmd_config_set), + OPT_SUBCOMMAND("unset", &subcommand, cmd_config_unset), + OPT_SUBCOMMAND("rename-section", &subcommand, cmd_config_rename_section), + OPT_SUBCOMMAND("remove-section", &subcommand, cmd_config_remove_section), + OPT_SUBCOMMAND("edit", &subcommand, cmd_config_edit), + OPT_END(), +}; + +int cmd_config(int argc, const char **argv, const char *prefix) +{ + char *value = NULL, *comment = NULL; + int flags = 0; + int ret = 0; + struct key_value_info default_kvi = KVI_INIT; + + given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT)); + + /* + * This is somewhat hacky: we first parse the command line while + * keeping all args intact in order to determine whether a subcommand + * has been specified. If so, we re-parse it a second time, but this + * time we drop KEEP_ARGV0. This is so that we don't munge the command + * line in case no subcommand was given, which would otherwise confuse + * us when parsing the legacy-style modes that don't use subcommands. + */ + argc = parse_options(argc, argv, prefix, builtin_subcommand_options, builtin_config_usage, + PARSE_OPT_SUBCOMMAND_OPTIONAL|PARSE_OPT_KEEP_ARGV0|PARSE_OPT_KEEP_UNKNOWN_OPT); + if (subcommand) { + argc = parse_options(argc, argv, prefix, builtin_subcommand_options, builtin_config_usage, + PARSE_OPT_SUBCOMMAND_OPTIONAL|PARSE_OPT_KEEP_UNKNOWN_OPT); + return subcommand(argc, argv, prefix); + } + + argc = parse_options(argc, argv, prefix, builtin_config_options, + builtin_config_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + + handle_config_location(prefix); + handle_nul(); if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && type) { error(_("--get-color and variable type are incoherent")); usage_builtin_config(); } - if (HAS_MULTI_BITS(actions)) { - error(_("only one action at a time")); - usage_builtin_config(); - } if (actions == 0) switch (argc) { case 1: actions = ACTION_GET; break; @@ -799,7 +1139,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) usage_builtin_config(); } - if (comment && + if (comment_arg && !(actions & (ACTION_ADD|ACTION_SET|ACTION_SET_ALL|ACTION_REPLACE_ALL))) { error(_("--comment is only applicable to add/set/replace operations")); usage_builtin_config(); @@ -841,7 +1181,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) flags |= CONFIG_FLAGS_FIXED_VALUE; } - comment = git_config_prepare_comment_string(comment); + comment = git_config_prepare_comment_string(comment_arg); if (actions & PAGING_ACTIONS) setup_auto_pager("config", 1); @@ -859,32 +1199,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } } else if (actions == ACTION_EDIT) { - char *config_file; - - check_argc(argc, 0, 0); - if (!given_config_source.file && nongit) - die(_("not in a git directory")); - if (given_config_source.use_stdin) - die(_("editing stdin is not supported")); - if (given_config_source.blob) - die(_("editing blobs is not supported")); - git_config(git_default_config, NULL); - config_file = given_config_source.file ? - xstrdup(given_config_source.file) : - git_pathdup("config"); - if (use_global_config) { - int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666); - if (fd >= 0) { - char *content = default_user_config(); - write_str_in_full(fd, content); - free(content); - close(fd); - } - else if (errno != EEXIST) - die_errno(_("cannot create configuration file %s"), config_file); - } - launch_editor(config_file, NULL, NULL); - free(config_file); + ret = show_editor(); } else if (actions == ACTION_SET) { check_write(); @@ -993,6 +1308,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) return get_colorbool(argv[0], argc == 2); } + free(comment); free(value); return ret; } diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c index 17f929dede..4952b22547 100644 --- a/builtin/credential-cache--daemon.c +++ b/builtin/credential-cache--daemon.c @@ -115,7 +115,9 @@ static int read_request(FILE *fh, struct credential *c, return error("client sent bogus timeout line: %s", item.buf); *timeout = atoi(p); - if (credential_read(c, fh) < 0) + credential_set_all_capabilities(c, CREDENTIAL_OP_INITIAL); + + if (credential_read(c, fh, CREDENTIAL_OP_HELPER) < 0) return -1; return 0; } @@ -131,8 +133,18 @@ static void serve_one_client(FILE *in, FILE *out) else if (!strcmp(action.buf, "get")) { struct credential_cache_entry *e = lookup_credential(&c); if (e) { - fprintf(out, "username=%s\n", e->item.username); - fprintf(out, "password=%s\n", e->item.password); + e->item.capa_authtype.request_initial = 1; + e->item.capa_authtype.request_helper = 1; + + fprintf(out, "capability[]=authtype\n"); + if (e->item.username) + fprintf(out, "username=%s\n", e->item.username); + if (e->item.password) + fprintf(out, "password=%s\n", e->item.password); + if (credential_has_capability(&c.capa_authtype, CREDENTIAL_OP_HELPER) && e->item.authtype) + fprintf(out, "authtype=%s\n", e->item.authtype); + if (credential_has_capability(&c.capa_authtype, CREDENTIAL_OP_HELPER) && e->item.credential) + fprintf(out, "credential=%s\n", e->item.credential); if (e->item.password_expiry_utc != TIME_MAX) fprintf(out, "password_expiry_utc=%"PRItime"\n", e->item.password_expiry_utc); @@ -157,8 +169,10 @@ static void serve_one_client(FILE *in, FILE *out) else if (!strcmp(action.buf, "store")) { if (timeout < 0) warning("cache client didn't specify a timeout"); - else if (!c.username || !c.password) + else if ((!c.username || !c.password) && (!c.authtype && !c.credential)) warning("cache client gave us a partial credential"); + else if (c.ephemeral) + warning("not storing ephemeral credential"); else { remove_credential(&c, 0); cache_credential(&c, timeout); diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c index bef120b537..3db8df70a9 100644 --- a/builtin/credential-cache.c +++ b/builtin/credential-cache.c @@ -1,4 +1,5 @@ #include "builtin.h" +#include "credential.h" #include "gettext.h" #include "parse-options.h" #include "path.h" @@ -127,6 +128,13 @@ static char *get_socket_path(void) return socket; } +static void announce_capabilities(void) +{ + struct credential c = CREDENTIAL_INIT; + c.capa_authtype.request_initial = 1; + credential_announce_capabilities(&c, stdout); +} + int cmd_credential_cache(int argc, const char **argv, const char *prefix) { char *socket_path = NULL; @@ -163,6 +171,8 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix) do_cache(socket_path, op, timeout, FLAG_RELAY); else if (!strcmp(op, "store")) do_cache(socket_path, op, timeout, FLAG_RELAY|FLAG_SPAWN); + else if (!strcmp(op, "capability")) + announce_capabilities(); else ; /* ignore unknown operation */ diff --git a/builtin/credential-store.c b/builtin/credential-store.c index 4a492411bb..494c809332 100644 --- a/builtin/credential-store.c +++ b/builtin/credential-store.c @@ -205,7 +205,7 @@ int cmd_credential_store(int argc, const char **argv, const char *prefix) if (!fns.nr) die("unable to set up default path; use --file"); - if (credential_read(&c, stdin) < 0) + if (credential_read(&c, stdin, CREDENTIAL_OP_HELPER) < 0) die("unable to read credential"); if (!strcmp(op, "get")) diff --git a/builtin/credential.c b/builtin/credential.c index 7010752987..5100d441f2 100644 --- a/builtin/credential.c +++ b/builtin/credential.c @@ -17,15 +17,24 @@ int cmd_credential(int argc, const char **argv, const char *prefix UNUSED) usage(usage_msg); op = argv[1]; - if (credential_read(&c, stdin) < 0) + if (!strcmp(op, "capability")) { + credential_set_all_capabilities(&c, CREDENTIAL_OP_INITIAL); + credential_announce_capabilities(&c, stdout); + return 0; + } + + if (credential_read(&c, stdin, CREDENTIAL_OP_INITIAL) < 0) die("unable to read credential from stdin"); if (!strcmp(op, "fill")) { - credential_fill(&c); - credential_write(&c, stdout); + credential_fill(&c, 0); + credential_next_state(&c); + credential_write(&c, stdout, CREDENTIAL_OP_RESPONSE); } else if (!strcmp(op, "approve")) { + credential_set_all_capabilities(&c, CREDENTIAL_OP_HELPER); credential_approve(&c); } else if (!strcmp(op, "reject")) { + credential_set_all_capabilities(&c, CREDENTIAL_OP_HELPER); credential_reject(&c); } else { usage(usage_msg); diff --git a/builtin/describe.c b/builtin/describe.c index e63fa8d84e..82aca00c80 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -1,4 +1,3 @@ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "config.h" #include "environment.h" @@ -675,7 +674,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix) prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; repo_read_index(the_repository); - refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, + refresh_index(the_repository->index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL); fd = repo_hold_locked_index(the_repository, &index_lock, 0); diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index a8e68ce8ef..0d3c611aac 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -1,4 +1,3 @@ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "config.h" #include "diff.h" @@ -206,7 +205,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) opt->diffopt.rotate_to_strict = 0; opt->diffopt.no_free = 1; if (opt->diffopt.detect_rename) { - if (!the_index.cache) + if (the_repository->index->cache) repo_read_index(the_repository); opt->diffopt.setup |= DIFF_SETUP_USE_SIZE_CACHE; } diff --git a/builtin/diff.c b/builtin/diff.c index 6e196e0c7d..efc37483b3 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -3,7 +3,7 @@ * * Copyright (c) 2006 Junio C Hamano */ -#define USE_THE_INDEX_VARIABLE + #include "builtin.h" #include "config.h" #include "ewah/ewok.h" @@ -239,9 +239,9 @@ static void refresh_index_quietly(void) fd = repo_hold_locked_index(the_repository, &lock_file, 0); if (fd < 0) return; - discard_index(&the_index); + discard_index(the_repository->index); repo_read_index(the_repository); - refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, + refresh_index(the_repository->index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL); repo_update_index_if_able(the_repository, &lock_file); } diff --git a/builtin/difftool.c b/builtin/difftool.c index a3c72b8258..a130faae4f 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -11,7 +11,7 @@ * * Copyright (C) 2016 Johannes Schindelin */ -#define USE_THE_INDEX_VARIABLE + #include "builtin.h" #include "abspath.h" #include "config.h" @@ -117,7 +117,7 @@ static int use_wt_file(const char *workdir, const char *name, int fd = open(buf.buf, O_RDONLY); if (fd >= 0 && - !index_fd(&the_index, &wt_oid, fd, &st, OBJ_BLOB, name, 0)) { + !index_fd(the_repository->index, &wt_oid, fd, &st, OBJ_BLOB, name, 0)) { if (is_null_oid(oid)) { oidcpy(oid, &wt_oid); use = 1; diff --git a/builtin/merge-index.c b/builtin/merge-index.c index 270d5f644a..0fabe3f6bb 100644 --- a/builtin/merge-index.c +++ b/builtin/merge-index.c @@ -1,4 +1,3 @@ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "hex.h" #include "read-cache-ll.h" @@ -18,11 +17,11 @@ static int merge_entry(int pos, const char *path) char ownbuf[4][60]; struct child_process cmd = CHILD_PROCESS_INIT; - if (pos >= the_index.cache_nr) + if (pos >= the_repository->index->cache_nr) die("git merge-index: %s not in the cache", path); found = 0; do { - const struct cache_entry *ce = the_index.cache[pos]; + const struct cache_entry *ce = the_repository->index->cache[pos]; int stage = ce_stage(ce); if (strcmp(ce->name, path)) @@ -32,7 +31,7 @@ static int merge_entry(int pos, const char *path) xsnprintf(ownbuf[stage], sizeof(ownbuf[stage]), "%o", ce->ce_mode); arguments[stage] = hexbuf[stage]; arguments[stage + 4] = ownbuf[stage]; - } while (++pos < the_index.cache_nr); + } while (++pos < the_repository->index->cache_nr); if (!found) die("git merge-index: %s not in the cache", path); @@ -51,7 +50,7 @@ static int merge_entry(int pos, const char *path) static void merge_one_path(const char *path) { - int pos = index_name_pos(&the_index, path, strlen(path)); + int pos = index_name_pos(the_repository->index, path, strlen(path)); /* * If it already exists in the cache as stage0, it's @@ -65,9 +64,9 @@ static void merge_all(void) { int i; /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(&the_index); - for (i = 0; i < the_index.cache_nr; i++) { - const struct cache_entry *ce = the_index.cache[i]; + ensure_full_index(the_repository->index); + for (i = 0; i < the_repository->index->cache_nr; i++) { + const struct cache_entry *ce = the_repository->index->cache[i]; if (!ce_stage(ce)) continue; i += merge_entry(i, ce->name)-1; @@ -89,7 +88,7 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix UNUSED) repo_read_index(the_repository); /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(&the_index); + ensure_full_index(the_repository->index); i = 1; if (!strcmp(argv[i], "-o")) { diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 8bdb439131..1082d919fd 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -1,4 +1,3 @@ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "tree-walk.h" #include "xdiff-interface.h" @@ -364,7 +363,7 @@ static void trivial_merge_trees(struct tree_desc t[3], const char *base) setup_traverse_info(&info, base); info.fn = threeway_callback; - traverse_trees(&the_index, 3, t, &info); + traverse_trees(the_repository->index, 3, t, &info); } static void *get_tree_descriptor(struct repository *r, diff --git a/builtin/merge.c b/builtin/merge.c index c9af4cab6c..e4bd65eeba 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -6,7 +6,6 @@ * Based on git-merge.sh by Junio C Hamano. */ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "abspath.h" #include "advice.h" @@ -300,7 +299,7 @@ static int save_state(struct object_id *stash) int rc = -1; fd = repo_hold_locked_index(the_repository, &lock_file, 0); - refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL); + refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL); if (0 <= fd) repo_update_index_if_able(the_repository, &lock_file); rollback_lock_file(&lock_file); @@ -372,7 +371,7 @@ static void restore_state(const struct object_id *head, run_command(&cmd); refresh_cache: - discard_index(&the_index); + discard_index(the_repository->index); if (repo_read_index(the_repository) < 0) die(_("could not read index")); } @@ -659,8 +658,8 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head, memset(&opts, 0, sizeof(opts)); opts.head_idx = 2; - opts.src_index = &the_index; - opts.dst_index = &the_index; + opts.src_index = the_repository->index; + opts.dst_index = the_repository->index; opts.update = 1; opts.verbose_update = 1; opts.trivial_merges_only = 1; @@ -676,7 +675,7 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head, if (!trees[nr_trees++]) return -1; opts.fn = threeway_merge; - cache_tree_free(&the_index.cache_tree); + cache_tree_free(&the_repository->index->cache_tree); for (i = 0; i < nr_trees; i++) { parse_tree(trees[i]); init_tree_desc(t+i, &trees[i]->object.oid, @@ -689,7 +688,7 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head, static void write_tree_trivial(struct object_id *oid) { - if (write_index_as_tree(oid, &the_index, get_index_file(), 0, NULL)) + if (write_index_as_tree(oid, the_repository->index, get_index_file(), 0, NULL)) die(_("git write-tree failed to write a tree")); } @@ -747,7 +746,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, rollback_lock_file(&lock); return 2; } - if (write_locked_index(&the_index, &lock, + if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK | SKIP_IF_UNCHANGED)) die(_("unable to write %s"), get_index_file()); return clean ? 0 : 1; @@ -770,8 +769,8 @@ static int count_unmerged_entries(void) { int i, ret = 0; - for (i = 0; i < the_index.cache_nr; i++) - if (ce_stage(the_index.cache[i])) + for (i = 0; i < the_repository->index->cache_nr; i++) + if (ce_stage(the_repository->index->cache[i])) ret++; return ret; @@ -845,9 +844,9 @@ static void prepare_to_commit(struct commit_list *remoteheads) * the editor and after we invoke run_status above. */ if (invoked_hook) - discard_index(&the_index); + discard_index(the_repository->index); } - read_index_from(&the_index, index_file, get_git_dir()); + read_index_from(the_repository->index, index_file, get_git_dir()); strbuf_addbuf(&msg, &merge_msg); if (squash) BUG("the control must not reach here under --squash"); @@ -959,7 +958,7 @@ static int suggest_conflicts(void) * Thus, we will get the cleanup mode which is returned when we _are_ * using an editor. */ - append_conflicts_hint(&the_index, &msgbuf, + append_conflicts_hint(the_repository->index, &msgbuf, get_cleanup_mode(cleanup_arg, 1)); fputs(msgbuf.buf, fp); strbuf_release(&msgbuf); @@ -1392,7 +1391,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) else die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).")); } - resolve_undo_clear_index(&the_index); + resolve_undo_clear_index(the_repository->index); if (option_edit < 0) option_edit = default_edit_option(); @@ -1605,7 +1604,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) * We are not doing octopus, not fast-forward, and have * only one common. */ - refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL); + refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL); if (allow_trivial && fast_forward != FF_ONLY) { /* * Must first ensure that index matches HEAD before @@ -1794,6 +1793,6 @@ done: } strbuf_release(&buf); free(branch_to_free); - discard_index(&the_index); + discard_index(the_repository->index); return ret; } diff --git a/builtin/mv.c b/builtin/mv.c index 22e64fc290..74aa9746aa 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -3,7 +3,7 @@ * * Copyright (C) 2006 Johannes Schindelin */ -#define USE_THE_INDEX_VARIABLE + #include "builtin.h" #include "abspath.h" #include "advice.h" @@ -95,9 +95,9 @@ static void prepare_move_submodule(const char *src, int first, const char **submodule_gitfile) { struct strbuf submodule_dotgit = STRBUF_INIT; - if (!S_ISGITLINK(the_index.cache[first]->ce_mode)) + if (!S_ISGITLINK(the_repository->index->cache[first]->ce_mode)) die(_("Directory %s is in index and no submodule?"), src); - if (!is_staging_gitmodules_ok(&the_index)) + if (!is_staging_gitmodules_ok(the_repository->index)) die(_("Please stage your changes to .gitmodules or stash them to proceed")); strbuf_addf(&submodule_dotgit, "%s/.git", src); *submodule_gitfile = read_gitfile(submodule_dotgit.buf); @@ -114,13 +114,13 @@ static int index_range_of_same_dir(const char *src, int length, const char *src_w_slash = add_slash(src); int first, last, len_w_slash = length + 1; - first = index_name_pos(&the_index, src_w_slash, len_w_slash); + first = index_name_pos(the_repository->index, src_w_slash, len_w_slash); if (first >= 0) die(_("%.*s is in index"), len_w_slash, src_w_slash); first = -1 - first; - for (last = first; last < the_index.cache_nr; last++) { - const char *path = the_index.cache[last]->name; + for (last = first; last < the_repository->index->cache_nr; last++) { + const char *path = the_repository->index->cache[last]->name; if (strncmp(path, src_w_slash, len_w_slash)) break; } @@ -144,14 +144,14 @@ static int empty_dir_has_sparse_contents(const char *name) const char *with_slash = add_slash(name); int length = strlen(with_slash); - int pos = index_name_pos(&the_index, with_slash, length); + int pos = index_name_pos(the_repository->index, with_slash, length); const struct cache_entry *ce; if (pos < 0) { pos = -pos - 1; - if (pos >= the_index.cache_nr) + if (pos >= the_repository->index->cache_nr) goto free_return; - ce = the_index.cache[pos]; + ce = the_repository->index->cache[pos]; if (strncmp(with_slash, ce->name, length)) goto free_return; if (ce_skip_worktree(ce)) @@ -223,7 +223,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) S_ISDIR(st.st_mode)) { destination = internal_prefix_pathspec(dst_w_slash, argv, argc, DUP_BASENAME); } else { - if (!path_in_sparse_checkout(dst_w_slash, &the_index) && + if (!path_in_sparse_checkout(dst_w_slash, the_repository->index) && empty_dir_has_sparse_contents(dst_w_slash)) { destination = internal_prefix_pathspec(dst_w_slash, argv, argc, DUP_BASENAME); dst_mode = SKIP_WORKTREE_DIR; @@ -239,7 +239,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) * is deprecated at this point) sparse-checkout. As * SPARSE here is only considering cone-mode situation. */ - if (!path_in_cone_mode_sparse_checkout(destination[0], &the_index)) + if (!path_in_cone_mode_sparse_checkout(destination[0], the_repository->index)) dst_mode = SPARSE; } } @@ -263,10 +263,10 @@ int cmd_mv(int argc, const char **argv, const char *prefix) int pos; const struct cache_entry *ce; - pos = index_name_pos(&the_index, src, length); + pos = index_name_pos(the_repository->index, src, length); if (pos < 0) { const char *src_w_slash = add_slash(src); - if (!path_in_sparse_checkout(src_w_slash, &the_index) && + if (!path_in_sparse_checkout(src_w_slash, the_repository->index) && empty_dir_has_sparse_contents(src)) { modes[i] |= SKIP_WORKTREE_DIR; goto dir_check; @@ -276,7 +276,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) bad = _("bad source"); goto act_on_entry; } - ce = the_index.cache[pos]; + ce = the_repository->index->cache[pos]; if (!ce_skip_worktree(ce)) { bad = _("bad source"); goto act_on_entry; @@ -286,7 +286,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) goto act_on_entry; } /* Check if dst exists in index */ - if (index_name_pos(&the_index, dst, strlen(dst)) < 0) { + if (index_name_pos(the_repository->index, dst, strlen(dst)) < 0) { modes[i] |= SPARSE; goto act_on_entry; } @@ -311,7 +311,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) dir_check: if (S_ISDIR(st.st_mode)) { int j, dst_len, n; - int first = index_name_pos(&the_index, src, length), last; + int first = index_name_pos(the_repository->index, src, length), last; if (first >= 0) { prepare_move_submodule(src, first, @@ -339,7 +339,7 @@ dir_check: dst_len = strlen(dst); for (j = 0; j < last - first; j++) { - const struct cache_entry *ce = the_index.cache[first + j]; + const struct cache_entry *ce = the_repository->index->cache[first + j]; const char *path = ce->name; source[argc + j] = path; destination[argc + j] = @@ -351,7 +351,7 @@ dir_check: argc += last - first; goto act_on_entry; } - if (!(ce = index_file_exists(&the_index, src, length, 0))) { + if (!(ce = index_file_exists(the_repository->index, src, length, 0))) { bad = _("not under version control"); goto act_on_entry; } @@ -387,7 +387,7 @@ dir_check: if (ignore_sparse && (dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) && - index_entry_exists(&the_index, dst, strlen(dst))) { + index_entry_exists(the_repository->index, dst, strlen(dst))) { bad = _("destination exists in the index"); if (force) { if (verbose) @@ -404,12 +404,12 @@ dir_check: * option as a way to have a successful run. */ if (!ignore_sparse && - !path_in_sparse_checkout(src, &the_index)) { + !path_in_sparse_checkout(src, the_repository->index)) { string_list_append(&only_match_skip_worktree, src); skip_sparse = 1; } if (!ignore_sparse && - !path_in_sparse_checkout(dst, &the_index)) { + !path_in_sparse_checkout(dst, the_repository->index)) { string_list_append(&only_match_skip_worktree, dst); skip_sparse = 1; } @@ -449,7 +449,7 @@ remove_entry: int pos; int sparse_and_dirty = 0; struct checkout state = CHECKOUT_INIT; - state.istate = &the_index; + state.istate = the_repository->index; if (force) state.force = 1; @@ -476,14 +476,14 @@ remove_entry: if (mode & (WORKING_DIRECTORY | SKIP_WORKTREE_DIR)) continue; - pos = index_name_pos(&the_index, src, strlen(src)); + pos = index_name_pos(the_repository->index, src, strlen(src)); assert(pos >= 0); if (!(mode & SPARSE) && !lstat(src, &st)) - sparse_and_dirty = ie_modified(&the_index, - the_index.cache[pos], + sparse_and_dirty = ie_modified(the_repository->index, + the_repository->index->cache[pos], &st, 0); - rename_index_entry_at(&the_index, pos, dst); + rename_index_entry_at(the_repository->index, pos, dst); if (ignore_sparse && core_apply_sparse_checkout && @@ -495,11 +495,11 @@ remove_entry: * should be added in a future patch. */ if ((mode & SPARSE) && - path_in_sparse_checkout(dst, &the_index)) { + path_in_sparse_checkout(dst, the_repository->index)) { /* from out-of-cone to in-cone */ - int dst_pos = index_name_pos(&the_index, dst, + int dst_pos = index_name_pos(the_repository->index, dst, strlen(dst)); - struct cache_entry *dst_ce = the_index.cache[dst_pos]; + struct cache_entry *dst_ce = the_repository->index->cache[dst_pos]; dst_ce->ce_flags &= ~CE_SKIP_WORKTREE; @@ -507,11 +507,11 @@ remove_entry: die(_("cannot checkout %s"), dst_ce->name); } else if ((dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) && !(mode & SPARSE) && - !path_in_sparse_checkout(dst, &the_index)) { + !path_in_sparse_checkout(dst, the_repository->index)) { /* from in-cone to out-of-cone */ - int dst_pos = index_name_pos(&the_index, dst, + int dst_pos = index_name_pos(the_repository->index, dst, strlen(dst)); - struct cache_entry *dst_ce = the_index.cache[dst_pos]; + struct cache_entry *dst_ce = the_repository->index->cache[dst_pos]; /* * if src is clean, it will suffice to remove it @@ -559,9 +559,9 @@ remove_entry: advise_on_moving_dirty_path(&dirty_paths); if (gitmodules_modified) - stage_updated_gitmodules(&the_index); + stage_updated_gitmodules(the_repository->index); - if (write_locked_index(&the_index, &lock_file, + if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK | SKIP_IF_UNCHANGED)) die(_("Unable to write new index file")); diff --git a/builtin/pull.c b/builtin/pull.c index 26a0806969..d622202bce 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -5,7 +5,7 @@ * * Fetch one or more remote refs and merge it/them into the current HEAD. */ -#define USE_THE_INDEX_VARIABLE + #include "builtin.h" #include "advice.h" #include "config.h" @@ -1044,7 +1044,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix) if (opt_autostash == -1) opt_autostash = config_autostash; - if (is_null_oid(&orig_head) && !is_index_unborn(&the_index)) + if (is_null_oid(&orig_head) && !is_index_unborn(the_repository->index)) die(_("Updating an unborn branch with changes added to the index.")); if (!opt_autostash) diff --git a/builtin/read-tree.c b/builtin/read-tree.c index 6f89cec0fb..a8cf8504b8 100644 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@ -4,7 +4,6 @@ * Copyright (C) Linus Torvalds, 2005 */ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "config.h" #include "gettext.h" @@ -159,8 +158,8 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix) memset(&opts, 0, sizeof(opts)); opts.head_idx = -1; - opts.src_index = &the_index; - opts.dst_index = &the_index; + opts.src_index = the_repository->index; + opts.dst_index = the_repository->index; git_config(git_read_tree_config, NULL); @@ -197,7 +196,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix) die(_("You need to resolve your current index first")); stage = opts.merge = 1; } - resolve_undo_clear_index(&the_index); + resolve_undo_clear_index(the_repository->index); for (i = 0; i < argc; i++) { const char *arg = argv[i]; @@ -225,7 +224,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix) setup_work_tree(); if (opts.skip_sparse_checkout) - ensure_full_index(&the_index); + ensure_full_index(the_repository->index); if (opts.merge) { switch (stage - 1) { @@ -237,7 +236,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix) break; case 2: opts.fn = twoway_merge; - opts.initial_checkout = is_index_unborn(&the_index); + opts.initial_checkout = is_index_unborn(the_repository->index); break; case 3: default: @@ -258,7 +257,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix) if (nr_trees == 1 && !opts.prefix) opts.skip_cache_tree_update = 1; - cache_tree_free(&the_index.cache_tree); + cache_tree_free(&the_repository->index->cache_tree); for (i = 0; i < nr_trees; i++) { struct tree *tree = trees[i]; if (parse_tree(tree) < 0) @@ -282,7 +281,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix) the_repository->index, trees[0]); - if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) + if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK)) die("unable to write new index file"); return 0; } diff --git a/builtin/rebase.c b/builtin/rebase.c index 4399896d90..0466d9414a 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -4,7 +4,6 @@ * Copyright (c) 2018 Pratik Karki */ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "abspath.h" #include "environment.h" @@ -295,7 +294,7 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags) if (ret) error(_("could not generate todo list")); else { - discard_index(&the_index); + discard_index(the_repository->index); if (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf, &todo_list)) BUG("unusable todo list"); diff --git a/builtin/replay.c b/builtin/replay.c index 6bc4b47f09..6bf0691f15 100644 --- a/builtin/replay.c +++ b/builtin/replay.c @@ -2,7 +2,6 @@ * "git replay" builtin command */ -#define USE_THE_INDEX_VARIABLE #include "git-compat-util.h" #include "builtin.h" diff --git a/builtin/reset.c b/builtin/reset.c index bf23fe78fa..5f941fb3a2 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -7,7 +7,7 @@ * * Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano */ -#define USE_THE_INDEX_VARIABLE + #include "builtin.h" #include "advice.h" #include "config.h" @@ -66,8 +66,8 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t memset(&opts, 0, sizeof(opts)); opts.head_idx = 1; - opts.src_index = &the_index; - opts.dst_index = &the_index; + opts.src_index = the_repository->index; + opts.dst_index = the_repository->index; opts.fn = oneway_merge; opts.merge = 1; init_checkout_metadata(&opts.meta, ref, oid, NULL); @@ -159,11 +159,11 @@ static void update_index_from_diff(struct diff_queue_struct *q, struct cache_entry *ce; if (!is_in_reset_tree && !intent_to_add) { - remove_file_from_index(&the_index, one->path); + remove_file_from_index(the_repository->index, one->path); continue; } - ce = make_cache_entry(&the_index, one->mode, &one->oid, one->path, + ce = make_cache_entry(the_repository->index, one->mode, &one->oid, one->path, 0, 0); /* @@ -174,9 +174,9 @@ static void update_index_from_diff(struct diff_queue_struct *q, * if this entry is outside the sparse cone - this is necessary * to properly construct the reset sparse directory. */ - pos = index_name_pos(&the_index, one->path, strlen(one->path)); - if ((pos >= 0 && ce_skip_worktree(the_index.cache[pos])) || - (pos < 0 && !path_in_sparse_checkout(one->path, &the_index))) + pos = index_name_pos(the_repository->index, one->path, strlen(one->path)); + if ((pos >= 0 && ce_skip_worktree(the_repository->index->cache[pos])) || + (pos < 0 && !path_in_sparse_checkout(one->path, the_repository->index))) ce->ce_flags |= CE_SKIP_WORKTREE; if (!ce) @@ -186,7 +186,7 @@ static void update_index_from_diff(struct diff_queue_struct *q, ce->ce_flags |= CE_INTENT_TO_ADD; set_object_name_for_intent_to_add_entry(ce); } - add_index_entry(&the_index, ce, + add_index_entry(the_repository->index, ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE); } } @@ -208,8 +208,8 @@ static int read_from_tree(const struct pathspec *pathspec, opt.change = diff_change; opt.add_remove = diff_addremove; - if (pathspec->nr && pathspec_needs_expanded_index(&the_index, pathspec)) - ensure_full_index(&the_index); + if (pathspec->nr && pathspec_needs_expanded_index(the_repository->index, pathspec)) + ensure_full_index(the_repository->index); if (do_diff_cache(tree_oid, &opt)) return 1; @@ -235,7 +235,7 @@ static void set_reflog_message(struct strbuf *sb, const char *action, static void die_if_unmerged_cache(int reset_type) { - if (is_merge() || unmerged_index(&the_index)) + if (is_merge() || unmerged_index(the_repository->index)) die(_("Cannot do a %s reset in the middle of a merge."), _(reset_type_names[reset_type])); @@ -473,12 +473,12 @@ int cmd_reset(int argc, const char **argv, const char *prefix) update_ref_status = 1; goto cleanup; } - the_index.updated_skipworktree = 1; + the_repository->index->updated_skipworktree = 1; if (!no_refresh && get_git_work_tree()) { uint64_t t_begin, t_delta_in_ms; t_begin = getnanotime(); - refresh_index(&the_index, flags, NULL, NULL, + refresh_index(the_repository->index, flags, NULL, NULL, _("Unstaged changes after reset:")); t_delta_in_ms = (getnanotime() - t_begin) / 1000000; if (!quiet && advice_enabled(ADVICE_RESET_NO_REFRESH_WARNING) && t_delta_in_ms > REFRESH_INDEX_DELAY_WARNING_IN_MS) { @@ -504,7 +504,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) free(ref); } - if (write_locked_index(&the_index, &lock, COMMIT_LOCK)) + if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK)) die(_("Could not write new index file.")); } @@ -519,7 +519,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) if (!pathspec.nr) remove_branch_state(the_repository, 0); - discard_index(&the_index); + discard_index(the_repository->index); cleanup: clear_pathspec(&pathspec); diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 5f79ec6338..2db047fff4 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -3,7 +3,7 @@ * * Copyright (C) Linus Torvalds, 2005 */ -#define USE_THE_INDEX_VARIABLE + #include "builtin.h" #include "abspath.h" #include "config.h" @@ -1060,8 +1060,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) if (!strcmp(arg, "--shared-index-path")) { if (repo_read_index(the_repository) < 0) die(_("Could not read the index")); - if (the_index.split_index) { - const struct object_id *oid = &the_index.split_index->base_oid; + if (the_repository->index->split_index) { + const struct object_id *oid = &the_repository->index->split_index->base_oid; const char *path = git_path("sharedindex.%s", oid_to_hex(oid)); print_path(path, prefix, format, DEFAULT_RELATIVE); } diff --git a/builtin/rm.c b/builtin/rm.c index fd130cea2d..d195c16e74 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -3,7 +3,7 @@ * * Copyright (C) Linus Torvalds 2006 */ -#define USE_THE_INDEX_VARIABLE + #include "builtin.h" #include "advice.h" #include "config.h" @@ -41,8 +41,8 @@ static int get_ours_cache_pos(const char *path, int pos) { int i = -pos - 1; - while ((i < the_index.cache_nr) && !strcmp(the_index.cache[i]->name, path)) { - if (ce_stage(the_index.cache[i]) == 2) + while ((i < the_repository->index->cache_nr) && !strcmp(the_repository->index->cache[i]->name, path)) { + if (ce_stage(the_repository->index->cache[i]) == 2) return i; i++; } @@ -78,13 +78,13 @@ static void submodules_absorb_gitdir_if_needed(void) int pos; const struct cache_entry *ce; - pos = index_name_pos(&the_index, name, strlen(name)); + pos = index_name_pos(the_repository->index, name, strlen(name)); if (pos < 0) { pos = get_ours_cache_pos(name, pos); if (pos < 0) continue; } - ce = the_index.cache[pos]; + ce = the_repository->index->cache[pos]; if (!S_ISGITLINK(ce->ce_mode) || !file_exists(ce->name) || @@ -122,7 +122,7 @@ static int check_local_mod(struct object_id *head, int index_only) int local_changes = 0; int staged_changes = 0; - pos = index_name_pos(&the_index, name, strlen(name)); + pos = index_name_pos(the_repository->index, name, strlen(name)); if (pos < 0) { /* * Skip unmerged entries except for populated submodules @@ -132,11 +132,11 @@ static int check_local_mod(struct object_id *head, int index_only) if (pos < 0) continue; - if (!S_ISGITLINK(the_index.cache[pos]->ce_mode) || + if (!S_ISGITLINK(the_repository->index->cache[pos]->ce_mode) || is_empty_dir(name)) continue; } - ce = the_index.cache[pos]; + ce = the_repository->index->cache[pos]; if (lstat(ce->name, &st) < 0) { if (!is_missing_file_error(errno)) @@ -173,7 +173,7 @@ static int check_local_mod(struct object_id *head, int index_only) * Is the index different from the file in the work tree? * If it's a submodule, is its work tree modified? */ - if (ie_match_stat(&the_index, ce, &st, 0) || + if (ie_match_stat(the_repository->index, ce, &st, 0) || (S_ISGITLINK(ce->ce_mode) && bad_to_remove_submodule(ce->name, SUBMODULE_REMOVAL_DIE_ON_ERROR | @@ -301,27 +301,27 @@ int cmd_rm(int argc, const char **argv, const char *prefix) if (repo_read_index(the_repository) < 0) die(_("index file corrupt")); - refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL); + refresh_index(the_repository->index, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL); seen = xcalloc(pathspec.nr, 1); - if (pathspec_needs_expanded_index(&the_index, &pathspec)) - ensure_full_index(&the_index); + if (pathspec_needs_expanded_index(the_repository->index, &pathspec)) + ensure_full_index(the_repository->index); - for (i = 0; i < the_index.cache_nr; i++) { - const struct cache_entry *ce = the_index.cache[i]; + for (i = 0; i < the_repository->index->cache_nr; i++) { + const struct cache_entry *ce = the_repository->index->cache[i]; if (!include_sparse && (ce_skip_worktree(ce) || - !path_in_sparse_checkout(ce->name, &the_index))) + !path_in_sparse_checkout(ce->name, the_repository->index))) continue; - if (!ce_path_match(&the_index, ce, &pathspec, seen)) + if (!ce_path_match(the_repository->index, 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(&the_index)) + !is_staging_gitmodules_ok(the_repository->index)) die(_("please stage your changes to .gitmodules or stash them to proceed")); } @@ -391,7 +391,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) if (!quiet) printf("rm '%s'\n", path); - if (remove_file_from_index(&the_index, path)) + if (remove_file_from_index(the_repository->index, path)) die(_("git rm: unable to remove %s"), path); } @@ -432,10 +432,10 @@ int cmd_rm(int argc, const char **argv, const char *prefix) } strbuf_release(&buf); if (gitmodules_modified) - stage_updated_gitmodules(&the_index); + stage_updated_gitmodules(the_repository->index); } - if (write_locked_index(&the_index, &lock_file, + if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK | SKIP_IF_UNCHANGED)) die(_("Unable to write new index file")); diff --git a/builtin/stash.c b/builtin/stash.c index 0a15ce287e..7859bc0866 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -1,4 +1,3 @@ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "abspath.h" #include "config.h" @@ -274,7 +273,7 @@ static int reset_tree(struct object_id *i_tree, int update, int reset) struct lock_file lock_file = LOCK_INIT; repo_read_index_preload(the_repository, NULL, 0); - if (refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL)) + if (refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL)) return -1; repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR); @@ -288,8 +287,8 @@ static int reset_tree(struct object_id *i_tree, int update, int reset) init_tree_desc(t, &tree->object.oid, tree->buffer, tree->size); opts.head_idx = 1; - opts.src_index = &the_index; - opts.dst_index = &the_index; + opts.src_index = the_repository->index; + opts.dst_index = the_repository->index; opts.merge = 1; opts.reset = reset ? UNPACK_RESET_PROTECT_UNTRACKED : 0; opts.update = update; @@ -300,7 +299,7 @@ static int reset_tree(struct object_id *i_tree, int update, int reset) if (unpack_trees(nr_trees, t, &opts)) return -1; - if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) + if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK)) return error(_("unable to write new index file")); return 0; @@ -431,7 +430,7 @@ static void unstage_changes_unless_new(struct object_id *orig_tree) state.force = 1; state.quiet = 1; state.refresh_cache = 1; - state.istate = &the_index; + state.istate = the_repository->index; /* * Step 1: get a difference between orig_tree (which corresponding @@ -455,7 +454,7 @@ static void unstage_changes_unless_new(struct object_id *orig_tree) /* Look up the path's position in the current index. */ p = diff_queued_diff.queue[i]; - pos = index_name_pos(&the_index, p->two->path, + pos = index_name_pos(the_repository->index, p->two->path, strlen(p->two->path)); /* @@ -466,10 +465,10 @@ static void unstage_changes_unless_new(struct object_id *orig_tree) * path, but left it out of the working tree, then clear the * SKIP_WORKTREE bit and write it to the working tree. */ - if (pos >= 0 && ce_skip_worktree(the_index.cache[pos])) { + if (pos >= 0 && ce_skip_worktree(the_repository->index->cache[pos])) { struct stat st; - ce = the_index.cache[pos]; + ce = the_repository->index->cache[pos]; if (!lstat(ce->name, &st)) { /* Conflicting path present; relocate it */ struct strbuf new_path = STRBUF_INIT; @@ -505,12 +504,12 @@ static void unstage_changes_unless_new(struct object_id *orig_tree) if (pos < 0) option = ADD_CACHE_OK_TO_ADD; - ce = make_cache_entry(&the_index, + ce = make_cache_entry(the_repository->index, p->one->mode, &p->one->oid, p->one->path, 0, 0); - add_index_entry(&the_index, ce, option); + add_index_entry(the_repository->index, ce, option); } } diff_flush(&diff_opts); @@ -519,7 +518,7 @@ static void unstage_changes_unless_new(struct object_id *orig_tree) * Step 4: write the new index to disk */ repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR); - if (write_locked_index(&the_index, &lock, + if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK | SKIP_IF_UNCHANGED)) die(_("could not write index")); } @@ -540,7 +539,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info, NULL, NULL, NULL)) return error(_("could not write index")); - if (write_index_as_tree(&c_tree, &the_index, get_index_file(), 0, + if (write_index_as_tree(&c_tree, the_repository->index, get_index_file(), 0, NULL)) return error(_("cannot apply a stash in the middle of a merge")); @@ -563,14 +562,14 @@ static int do_apply_stash(const char *prefix, struct stash_info *info, return error(_("conflicts in index. " "Try without --index.")); - discard_index(&the_index); + discard_index(the_repository->index); repo_read_index(the_repository); - if (write_index_as_tree(&index_tree, &the_index, + if (write_index_as_tree(&index_tree, the_repository->index, get_index_file(), 0, NULL)) return error(_("could not save index tree")); reset_head(); - discard_index(&the_index); + discard_index(the_repository->index); repo_read_index(the_repository); } } @@ -877,8 +876,8 @@ static void diff_include_untracked(const struct stash_info *info, struct diff_op } unpack_tree_opt.head_idx = -1; - unpack_tree_opt.src_index = &the_index; - unpack_tree_opt.dst_index = &the_index; + unpack_tree_opt.src_index = the_repository->index; + unpack_tree_opt.dst_index = the_repository->index; unpack_tree_opt.merge = 1; unpack_tree_opt.fn = stash_worktree_untracked_merge; @@ -1398,7 +1397,7 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b strbuf_addf(&commit_tree_label, "index on %s\n", msg.buf); commit_list_insert(head_commit, &parents); - if (write_index_as_tree(&info->i_tree, &the_index, get_index_file(), 0, + if (write_index_as_tree(&info->i_tree, the_repository->index, get_index_file(), 0, NULL) || commit_tree(commit_tree_label.buf, commit_tree_label.len, &info->i_tree, parents, &info->i_commit, NULL, NULL)) { @@ -1543,9 +1542,9 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q char *ps_matched = xcalloc(ps->nr, 1); /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(&the_index); - for (i = 0; i < the_index.cache_nr; i++) - ce_path_match(&the_index, the_index.cache[i], ps, + ensure_full_index(the_repository->index); + for (i = 0; i < the_repository->index->cache_nr; i++) + ce_path_match(the_repository->index, the_repository->index->cache[i], ps, ps_matched); if (report_path_error(ps_matched, ps)) { @@ -1615,7 +1614,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q goto done; } } - discard_index(&the_index); + discard_index(the_repository->index); if (ps->nr) { struct child_process cp_add = CHILD_PROCESS_INIT; struct child_process cp_diff = CHILD_PROCESS_INIT; diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 4be79eab23..e604cb5ddb 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -1,4 +1,3 @@ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "abspath.h" #include "environment.h" @@ -207,18 +206,18 @@ static int module_list_compute(const char **argv, if (repo_read_index(the_repository) < 0) die(_("index file corrupt")); - for (i = 0; i < the_index.cache_nr; i++) { - const struct cache_entry *ce = the_index.cache[i]; + for (i = 0; i < the_repository->index->cache_nr; i++) { + const struct cache_entry *ce = the_repository->index->cache[i]; - if (!match_pathspec(&the_index, pathspec, ce->name, ce_namelen(ce), + if (!match_pathspec(the_repository->index, pathspec, ce->name, ce_namelen(ce), 0, ps_matched, 1) || !S_ISGITLINK(ce->ce_mode)) continue; ALLOC_GROW(list->entries, list->nr + 1, list->alloc); list->entries[list->nr++] = ce; - while (i + 1 < the_index.cache_nr && - !strcmp(ce->name, the_index.cache[i + 1]->name)) + while (i + 1 < the_repository->index->cache_nr && + !strcmp(ce->name, the_repository->index->cache[i + 1]->name)) /* * Skip entries with the same name in different stages * to make sure an entry is returned only once. @@ -303,6 +302,9 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item, struct child_process cp = CHILD_PROCESS_INIT; char *displaypath; + if (validate_submodule_path(path) < 0) + exit(128); + displaypath = get_submodule_displaypath(path, info->prefix, info->super_prefix); @@ -634,6 +636,9 @@ static void status_submodule(const char *path, const struct object_id *ce_oid, .free_removed_argv_elements = 1, }; + if (validate_submodule_path(path) < 0) + exit(128); + if (!submodule_from_path(the_repository, null_oid(), path)) die(_("no submodule mapping found in .gitmodules for path '%s'"), path); @@ -907,7 +912,7 @@ static void generate_submodule_summary(struct summary_cb *info, int fd = open(p->sm_path, O_RDONLY); if (fd < 0 || fstat(fd, &st) < 0 || - index_fd(&the_index, &p->oid_dst, fd, &st, OBJ_BLOB, + index_fd(the_repository->index, &p->oid_dst, fd, &st, OBJ_BLOB, p->sm_path, 0)) error(_("couldn't hash object from '%s'"), p->sm_path); } else { @@ -1238,6 +1243,9 @@ static void sync_submodule(const char *path, const char *prefix, if (!is_submodule_active(the_repository, path)) return; + if (validate_submodule_path(path) < 0) + exit(128); + sub = submodule_from_path(the_repository, null_oid(), path); if (sub && sub->url) { @@ -1381,6 +1389,9 @@ static void deinit_submodule(const char *path, const char *prefix, struct strbuf sb_config = STRBUF_INIT; char *sub_git_dir = xstrfmt("%s/.git", path); + if (validate_submodule_path(path) < 0) + exit(128); + sub = submodule_from_path(the_repository, null_oid(), path); if (!sub || !sub->name) @@ -1662,16 +1673,42 @@ static char *clone_submodule_sm_gitdir(const char *name) return sm_gitdir; } +static int dir_contains_only_dotgit(const char *path) +{ + DIR *dir = opendir(path); + struct dirent *e; + int ret = 1; + + if (!dir) + return 0; + + e = readdir_skip_dot_and_dotdot(dir); + if (!e) + ret = 0; + else if (strcmp(DEFAULT_GIT_DIR_ENVIRONMENT, e->d_name) || + (e = readdir_skip_dot_and_dotdot(dir))) { + error("unexpected item '%s' in '%s'", e->d_name, path); + ret = 0; + } + + closedir(dir); + return ret; +} + static int clone_submodule(const struct module_clone_data *clone_data, struct string_list *reference) { char *p; char *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name); char *sm_alternate = NULL, *error_strategy = NULL; + struct stat st; struct child_process cp = CHILD_PROCESS_INIT; const char *clone_data_path = clone_data->path; char *to_free = NULL; + if (validate_submodule_path(clone_data_path) < 0) + exit(128); + if (!is_absolute_path(clone_data->path)) clone_data_path = to_free = xstrfmt("%s/%s", get_git_work_tree(), clone_data->path); @@ -1681,6 +1718,10 @@ static int clone_submodule(const struct module_clone_data *clone_data, "git dir"), sm_gitdir); if (!file_exists(sm_gitdir)) { + if (clone_data->require_init && !stat(clone_data_path, &st) && + !is_empty_dir(clone_data_path)) + die(_("directory not empty: '%s'"), clone_data_path); + if (safe_create_leading_directories_const(sm_gitdir) < 0) die(_("could not create directory '%s'"), sm_gitdir); @@ -1725,10 +1766,18 @@ static int clone_submodule(const struct module_clone_data *clone_data, if(run_command(&cp)) die(_("clone of '%s' into submodule path '%s' failed"), clone_data->url, clone_data_path); + + if (clone_data->require_init && !stat(clone_data_path, &st) && + !dir_contains_only_dotgit(clone_data_path)) { + char *dot_git = xstrfmt("%s/.git", clone_data_path); + unlink(dot_git); + free(dot_git); + die(_("directory not empty: '%s'"), clone_data_path); + } } else { char *path; - if (clone_data->require_init && !access(clone_data_path, X_OK) && + if (clone_data->require_init && !stat(clone_data_path, &st) && !is_empty_dir(clone_data_path)) die(_("directory not empty: '%s'"), clone_data_path); if (safe_create_leading_directories_const(clone_data_path) < 0) @@ -1738,6 +1787,23 @@ static int clone_submodule(const struct module_clone_data *clone_data, free(path); } + /* + * We already performed this check at the beginning of this function, + * before cloning the objects. This tries to detect racy behavior e.g. + * in parallel clones, where another process could easily have made the + * gitdir nested _after_ it was created. + * + * To prevent further harm coming from this unintentionally-nested + * gitdir, let's disable it by deleting the `HEAD` file. + */ + if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0) { + char *head = xstrfmt("%s/HEAD", sm_gitdir); + unlink(head); + free(head); + die(_("refusing to create/use '%s' in another submodule's " + "git dir"), sm_gitdir); + } + connect_work_tree_and_git_dir(clone_data_path, sm_gitdir, 0); p = git_pathdup_submodule(clone_data_path, "config"); @@ -2519,6 +2585,9 @@ static int update_submodule(struct update_data *update_data) { int ret; + if (validate_submodule_path(update_data->sm_path) < 0) + return -1; + ret = determine_submodule_update_strategy(the_repository, update_data->just_cloned, update_data->sm_path, @@ -2626,12 +2695,21 @@ static int update_submodules(struct update_data *update_data) for (i = 0; i < suc.update_clone_nr; i++) { struct update_clone_data ucd = suc.update_clone[i]; - int code; + int code = 128; oidcpy(&update_data->oid, &ucd.oid); update_data->just_cloned = ucd.just_cloned; update_data->sm_path = ucd.sub->path; + /* + * Verify that the submodule path does not contain any + * symlinks; if it does, it might have been tampered with. + * TODO: allow exempting it via + * `safe.submodule.path` or something + */ + if (validate_submodule_path(update_data->sm_path) < 0) + goto fail; + code = ensure_core_worktree(update_data->sm_path); if (code) goto fail; @@ -3246,21 +3324,21 @@ static void die_on_index_match(const char *path, int force) char *ps_matched = xcalloc(ps.nr, 1); /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(&the_index); + ensure_full_index(the_repository->index); /* * Since there is only one pathspec, we just need to * check ps_matched[0] to know if a cache entry matched. */ - for (i = 0; i < the_index.cache_nr; i++) { - ce_path_match(&the_index, the_index.cache[i], &ps, + for (i = 0; i < the_repository->index->cache_nr; i++) { + ce_path_match(the_repository->index, the_repository->index->cache[i], &ps, ps_matched); if (ps_matched[0]) { if (!force) die(_("'%s' already exists in the index"), path); - if (!S_ISGITLINK(the_index.cache[i]->ce_mode)) + if (!S_ISGITLINK(the_repository->index->cache[i]->ce_mode)) die(_("'%s' already exists in the index " "and is not a submodule"), path); break; @@ -3359,6 +3437,9 @@ static int module_add(int argc, const char **argv, const char *prefix) normalize_path_copy(add_data.sm_path, add_data.sm_path); strip_dir_trailing_slashes(add_data.sm_path); + if (validate_submodule_path(add_data.sm_path) < 0) + exit(128); + die_on_index_match(add_data.sm_path, force); die_on_repo_without_commits(add_data.sm_path); diff --git a/builtin/tag.c b/builtin/tag.c index 424a03ad18..b18eec91ab 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -28,9 +28,11 @@ #include "date.h" #include "write-or-die.h" #include "object-file-convert.h" +#include "trailer.h" static const char * const git_tag_usage[] = { N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n" + " [(--trailer <token>[(=|:)<value>])...]\n" " <tagname> [<commit> | <object>]"), N_("git tag -d <tagname>..."), N_("git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]\n" @@ -290,10 +292,12 @@ static const char message_advice_nested_tag[] = static void create_tag(const struct object_id *object, const char *object_ref, const char *tag, struct strbuf *buf, struct create_tag_options *opt, - struct object_id *prev, struct object_id *result, char *path) + struct object_id *prev, struct object_id *result, + struct strvec *trailer_args, char *path) { enum object_type type; struct strbuf header = STRBUF_INIT; + int should_edit; type = oid_object_info(the_repository, object, NULL); if (type <= OBJ_NONE) @@ -313,13 +317,15 @@ static void create_tag(const struct object_id *object, const char *object_ref, tag, git_committer_info(IDENT_STRICT)); - if (!opt->message_given || opt->use_editor) { + should_edit = opt->use_editor || !opt->message_given; + if (should_edit || trailer_args->nr) { int fd; /* write the template message before editing: */ fd = xopen(path, O_CREAT | O_TRUNC | O_WRONLY, 0600); - if (opt->message_given) { + if (opt->message_given && buf->len) { + strbuf_complete(buf, '\n'); write_or_die(fd, buf->buf, buf->len); strbuf_reset(buf); } else if (!is_null_oid(prev)) { @@ -338,10 +344,19 @@ static void create_tag(const struct object_id *object, const char *object_ref, } close(fd); - if (launch_editor(path, buf, NULL)) { - fprintf(stderr, - _("Please supply the message using either -m or -F option.\n")); - exit(1); + if (trailer_args->nr && amend_file_with_trailers(path, trailer_args)) + die(_("unable to pass trailers to --trailers")); + + if (should_edit) { + if (launch_editor(path, buf, NULL)) { + fprintf(stderr, + _("Please supply the message using either -m or -F option.\n")); + exit(1); + } + } else if (trailer_args->nr) { + strbuf_reset(buf); + if (strbuf_read_file(buf, path, 0) < 0) + die_errno(_("failed to read '%s'"), path); } } @@ -463,6 +478,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) struct ref_sorting *sorting; struct string_list sorting_options = STRING_LIST_INIT_DUP; struct ref_format format = REF_FORMAT_INIT; + struct strvec trailer_args = STRVEC_INIT; int icase = 0; int edit_flag = 0; struct option options[] = { @@ -479,6 +495,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix) OPT_CALLBACK_F('m', "message", &msg, N_("message"), N_("tag message"), PARSE_OPT_NONEG, parse_msg_arg), OPT_FILENAME('F', "file", &msgfile, N_("read message from file")), + OPT_PASSTHRU_ARGV(0, "trailer", &trailer_args, N_("trailer"), + N_("add custom trailer(s)"), PARSE_OPT_NONEG), OPT_BOOL('e', "edit", &edit_flag, N_("force edit of tag message")), OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")), OPT_CLEANUP(&cleanup_arg), @@ -548,7 +566,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix) opt.sign = 1; set_signing_key(keyid); } - create_tag_object = (opt.sign || annotate || msg.given || msgfile); + create_tag_object = (opt.sign || annotate || msg.given || msgfile || + edit_flag || trailer_args.nr); if ((create_tag_object || force) && (cmdmode != 0)) usage_with_options(git_tag_usage, options); @@ -654,7 +673,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) opt.sign = 1; path = git_pathdup("TAG_EDITMSG"); create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object, - path); + &trailer_args, path); } transaction = ref_store_transaction_begin(get_main_ref_store(the_repository), @@ -687,6 +706,7 @@ cleanup: strbuf_release(&reflog_msg); strbuf_release(&msg.buf); strbuf_release(&err); + strvec_clear(&trailer_args); free(msgfile); return ret; } diff --git a/builtin/update-index.c b/builtin/update-index.c index 9c9c24b831..20aa1c4c68 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -3,7 +3,7 @@ * * Copyright (C) Linus Torvalds, 2005 */ -#define USE_THE_INDEX_VARIABLE + #include "builtin.h" #include "bulk-checkin.h" #include "config.h" @@ -247,16 +247,16 @@ done: static int mark_ce_flags(const char *path, int flag, int mark) { int namelen = strlen(path); - int pos = index_name_pos(&the_index, path, namelen); + int pos = index_name_pos(the_repository->index, path, namelen); if (0 <= pos) { - mark_fsmonitor_invalid(&the_index, the_index.cache[pos]); + mark_fsmonitor_invalid(the_repository->index, the_repository->index->cache[pos]); if (mark) - the_index.cache[pos]->ce_flags |= flag; + the_repository->index->cache[pos]->ce_flags |= flag; else - the_index.cache[pos]->ce_flags &= ~flag; - the_index.cache[pos]->ce_flags |= CE_UPDATE_IN_BASE; - cache_tree_invalidate_path(&the_index, path); - the_index.cache_changed |= CE_ENTRY_CHANGED; + the_repository->index->cache[pos]->ce_flags &= ~flag; + the_repository->index->cache[pos]->ce_flags |= CE_UPDATE_IN_BASE; + cache_tree_invalidate_path(the_repository->index, path); + the_repository->index->cache_changed |= CE_ENTRY_CHANGED; return 0; } return -1; @@ -266,7 +266,7 @@ static int remove_one_path(const char *path) { if (!allow_remove) return error("%s: does not exist and --remove not passed", path); - if (remove_file_from_index(&the_index, path)) + if (remove_file_from_index(the_repository->index, path)) return error("%s: cannot remove from the index", path); return 0; } @@ -291,24 +291,24 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len struct cache_entry *ce; /* Was the old index entry already up-to-date? */ - if (old && !ce_stage(old) && !ie_match_stat(&the_index, old, st, 0)) + if (old && !ce_stage(old) && !ie_match_stat(the_repository->index, old, st, 0)) return 0; - ce = make_empty_cache_entry(&the_index, len); + ce = make_empty_cache_entry(the_repository->index, len); memcpy(ce->name, path, len); ce->ce_flags = create_ce_flags(0); ce->ce_namelen = len; - fill_stat_cache_info(&the_index, ce, st); + fill_stat_cache_info(the_repository->index, ce, st); ce->ce_mode = ce_mode_from_stat(old, st->st_mode); - if (index_path(&the_index, &ce->oid, path, st, + if (index_path(the_repository->index, &ce->oid, path, st, info_only ? 0 : HASH_WRITE_OBJECT)) { discard_cache_entry(ce); return -1; } option = allow_add ? ADD_CACHE_OK_TO_ADD : 0; option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0; - if (add_index_entry(&the_index, ce, option)) { + if (add_index_entry(the_repository->index, ce, option)) { discard_cache_entry(ce); return error("%s: cannot add to the index - missing --add option?", path); } @@ -341,11 +341,11 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len static int process_directory(const char *path, int len, struct stat *st) { struct object_id oid; - int pos = index_name_pos(&the_index, path, len); + int pos = index_name_pos(the_repository->index, path, len); /* Exact match: file or existing gitlink */ if (pos >= 0) { - const struct cache_entry *ce = the_index.cache[pos]; + const struct cache_entry *ce = the_repository->index->cache[pos]; if (S_ISGITLINK(ce->ce_mode)) { /* Do nothing to the index if there is no HEAD! */ @@ -360,8 +360,8 @@ static int process_directory(const char *path, int len, struct stat *st) /* Inexact match: is there perhaps a subdirectory match? */ pos = -pos-1; - while (pos < the_index.cache_nr) { - const struct cache_entry *ce = the_index.cache[pos++]; + while (pos < the_repository->index->cache_nr) { + const struct cache_entry *ce = the_repository->index->cache[pos++]; if (strncmp(ce->name, path, len)) break; @@ -391,8 +391,8 @@ static int process_path(const char *path, struct stat *st, int stat_errno) if (has_symlink_leading_path(path, len)) return error("'%s' is beyond a symbolic link", path); - pos = index_name_pos(&the_index, path, len); - ce = pos < 0 ? NULL : the_index.cache[pos]; + pos = index_name_pos(the_repository->index, path, len); + ce = pos < 0 ? NULL : the_repository->index->cache[pos]; if (ce && ce_skip_worktree(ce)) { /* * working directory version is assumed "good" @@ -400,7 +400,7 @@ static int process_path(const char *path, struct stat *st, int stat_errno) * On the other hand, removing it from index should work */ if (!ignore_skip_worktree_entries && allow_remove && - remove_file_from_index(&the_index, path)) + remove_file_from_index(the_repository->index, path)) return error("%s: cannot remove from the index", path); return 0; } @@ -428,7 +428,7 @@ static int add_cacheinfo(unsigned int mode, const struct object_id *oid, return error("Invalid path '%s'", path); len = strlen(path); - ce = make_empty_cache_entry(&the_index, len); + ce = make_empty_cache_entry(the_repository->index, len); oidcpy(&ce->oid, oid); memcpy(ce->name, path, len); @@ -439,7 +439,7 @@ static int add_cacheinfo(unsigned int mode, const struct object_id *oid, ce->ce_flags |= CE_VALID; option = allow_add ? ADD_CACHE_OK_TO_ADD : 0; option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0; - if (add_index_entry(&the_index, ce, option)) + if (add_index_entry(the_repository->index, ce, option)) return error("%s: cannot add to the index - missing --add option?", path); report("add '%s'", path); @@ -451,11 +451,11 @@ static void chmod_path(char flip, const char *path) int pos; struct cache_entry *ce; - pos = index_name_pos(&the_index, path, strlen(path)); + pos = index_name_pos(the_repository->index, path, strlen(path)); if (pos < 0) goto fail; - ce = the_index.cache[pos]; - if (chmod_index_entry(&the_index, ce, flip) < 0) + ce = the_repository->index->cache[pos]; + if (chmod_index_entry(the_repository->index, ce, flip) < 0) goto fail; report("chmod %cx '%s'", flip, path); @@ -498,7 +498,7 @@ static void update_one(const char *path) } if (force_remove) { - if (remove_file_from_index(&the_index, path)) + if (remove_file_from_index(the_repository->index, path)) die("git update-index: unable to remove %s", path); report("remove '%s'", path); return; @@ -581,7 +581,7 @@ static void read_index_info(int nul_term_line) if (!mode) { /* mode == 0 means there is no such path -- remove */ - if (remove_file_from_index(&the_index, path_name)) + if (remove_file_from_index(the_repository->index, path_name)) die("git update-index: unable to remove %s", ptr); } @@ -622,12 +622,12 @@ static struct cache_entry *read_one_ent(const char *which, error("%s: not in %s branch.", path, which); return NULL; } - if (!the_index.sparse_index && mode == S_IFDIR) { + if (!the_repository->index->sparse_index && mode == S_IFDIR) { if (which) error("%s: not a blob in %s branch.", path, which); return NULL; } - ce = make_empty_cache_entry(&the_index, namelen); + ce = make_empty_cache_entry(the_repository->index, namelen); oidcpy(&ce->oid, &oid); memcpy(ce->name, path, namelen); @@ -642,12 +642,12 @@ static int unresolve_one(const char *path) struct string_list_item *item; int res = 0; - if (!the_index.resolve_undo) + if (!the_repository->index->resolve_undo) return res; - item = string_list_lookup(the_index.resolve_undo, path); + item = string_list_lookup(the_repository->index->resolve_undo, path); if (!item) return res; /* no resolve-undo record for the path */ - res = unmerge_index_entry(&the_index, path, item->util, 0); + res = unmerge_index_entry(the_repository->index, path, item->util, 0); FREE_AND_NULL(item->util); return res; } @@ -688,13 +688,13 @@ static int do_reupdate(const char **paths, */ has_head = 0; redo: - for (pos = 0; pos < the_index.cache_nr; pos++) { - const struct cache_entry *ce = the_index.cache[pos]; + for (pos = 0; pos < the_repository->index->cache_nr; pos++) { + const struct cache_entry *ce = the_repository->index->cache[pos]; struct cache_entry *old = NULL; int save_nr; char *path; - if (ce_stage(ce) || !ce_path_match(&the_index, ce, &pathspec, NULL)) + if (ce_stage(ce) || !ce_path_match(the_repository->index, ce, &pathspec, NULL)) continue; if (has_head) old = read_one_ent(NULL, &head_oid, @@ -710,7 +710,7 @@ static int do_reupdate(const char **paths, * to process each path individually */ if (S_ISSPARSEDIR(ce->ce_mode)) { - ensure_full_index(&the_index); + ensure_full_index(the_repository->index); goto redo; } @@ -718,12 +718,12 @@ static int do_reupdate(const char **paths, * path anymore, in which case, under 'allow_remove', * or worse yet 'allow_replace', active_nr may decrease. */ - save_nr = the_index.cache_nr; + save_nr = the_repository->index->cache_nr; path = xstrdup(ce->name); update_one(path); free(path); discard_cache_entry(old); - if (save_nr != the_index.cache_nr) + if (save_nr != the_repository->index->cache_nr) goto redo; } clear_pathspec(&pathspec); @@ -739,9 +739,9 @@ static int refresh(struct refresh_params *o, unsigned int flag) { setup_work_tree(); repo_read_index(the_repository); - *o->has_errors |= refresh_index(&the_index, o->flags | flag, NULL, + *o->has_errors |= refresh_index(the_repository->index, o->flags | flag, NULL, NULL, NULL); - if (has_racy_timestamp(&the_index)) { + if (has_racy_timestamp(the_repository->index)) { /* * Even if nothing else has changed, updating the file * increases the chance that racy timestamps become @@ -750,7 +750,7 @@ static int refresh(struct refresh_params *o, unsigned int flag) * refresh_index() as these are no actual errors. * cmd_status() does the same. */ - the_index.cache_changed |= SOMETHING_CHANGED; + the_repository->index->cache_changed |= SOMETHING_CHANGED; } return 0; } @@ -787,7 +787,7 @@ static int resolve_undo_clear_callback(const struct option *opt UNUSED, { BUG_ON_OPT_NEG(unset); BUG_ON_OPT_ARG(arg); - resolve_undo_clear_index(&the_index); + resolve_undo_clear_index(the_repository->index); return 0; } @@ -888,7 +888,7 @@ static enum parse_opt_result unresolve_callback( *has_errors = do_unresolve(ctx->argc, ctx->argv, prefix, prefix ? strlen(prefix) : 0); if (*has_errors) - the_index.cache_changed = 0; + the_repository->index->cache_changed = 0; ctx->argv += ctx->argc - 1; ctx->argc = 1; @@ -909,7 +909,7 @@ static enum parse_opt_result reupdate_callback( setup_work_tree(); *has_errors = do_reupdate(ctx->argv + 1, prefix); if (*has_errors) - the_index.cache_changed = 0; + the_repository->index->cache_changed = 0; ctx->argv += ctx->argc - 1; ctx->argc = 1; @@ -1056,7 +1056,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) if (entries < 0) die("cache corrupted"); - the_index.updated_skipworktree = 1; + the_repository->index->updated_skipworktree = 1; /* * Custom copy of parse_options() because we want to handle @@ -1111,18 +1111,18 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf; if (preferred_index_format) { if (preferred_index_format < 0) { - printf(_("%d\n"), the_index.version); + printf(_("%d\n"), the_repository->index->version); } else if (preferred_index_format < INDEX_FORMAT_LB || INDEX_FORMAT_UB < preferred_index_format) { die("index-version %d not in range: %d..%d", preferred_index_format, INDEX_FORMAT_LB, INDEX_FORMAT_UB); } else { - if (the_index.version != preferred_index_format) - the_index.cache_changed |= SOMETHING_CHANGED; + if (the_repository->index->version != preferred_index_format) + the_repository->index->cache_changed |= SOMETHING_CHANGED; report(_("index-version: was %d, set to %d"), - the_index.version, preferred_index_format); - the_index.version = preferred_index_format; + the_repository->index->version, preferred_index_format); + the_repository->index->version = preferred_index_format; } } @@ -1159,16 +1159,16 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) warning(_("core.splitIndex is set to false; " "remove or change it, if you really want to " "enable split index")); - if (the_index.split_index) - the_index.cache_changed |= SPLIT_INDEX_ORDERED; + if (the_repository->index->split_index) + the_repository->index->cache_changed |= SPLIT_INDEX_ORDERED; else - add_split_index(&the_index); + add_split_index(the_repository->index); } else if (!split_index) { if (git_config_get_split_index() == 1) warning(_("core.splitIndex is set to true; " "remove or change it, if you really want to " "disable split index")); - remove_split_index(&the_index); + remove_split_index(the_repository->index); } prepare_repo_settings(r); @@ -1180,7 +1180,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) warning(_("core.untrackedCache is set to true; " "remove or change it, if you really want to " "disable the untracked cache")); - remove_untracked_cache(&the_index); + remove_untracked_cache(the_repository->index); report(_("Untracked cache disabled")); break; case UC_TEST: @@ -1192,7 +1192,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) warning(_("core.untrackedCache is set to false; " "remove or change it, if you really want to " "enable the untracked cache")); - add_untracked_cache(&the_index); + add_untracked_cache(the_repository->index); report(_("Untracked cache enabled for '%s'"), get_git_work_tree()); break; default: @@ -1222,7 +1222,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) "set it if you really want to " "enable fsmonitor")); } - add_fsmonitor(&the_index); + add_fsmonitor(the_repository->index); report(_("fsmonitor enabled")); } else if (!fsmonitor) { enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r); @@ -1230,17 +1230,17 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) warning(_("core.fsmonitor is set; " "remove it if you really want to " "disable fsmonitor")); - remove_fsmonitor(&the_index); + remove_fsmonitor(the_repository->index); report(_("fsmonitor disabled")); } - if (the_index.cache_changed || force_write) { + if (the_repository->index->cache_changed || force_write) { if (newfd < 0) { if (refresh_args.flags & REFRESH_QUIET) exit(128); unable_to_lock_die(get_index_file(), lock_error); } - if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) + if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK)) die("Unable to write new index file"); } diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c index 15afb97260..46d93278d9 100644 --- a/builtin/upload-pack.c +++ b/builtin/upload-pack.c @@ -9,6 +9,7 @@ #include "upload-pack.h" #include "serve.h" #include "commit.h" +#include "environment.h" static const char * const upload_pack_usage[] = { N_("git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n" @@ -39,6 +40,7 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix) packet_trace_identity("upload-pack"); disable_replace_refs(); save_commit_buffer = 0; + xsetenv(NO_LAZY_FETCH_ENVIRONMENT, "1", 0); argc = parse_options(argc, argv, prefix, options, upload_pack_usage, 0); diff --git a/builtin/write-tree.c b/builtin/write-tree.c index 66e83d0ecb..8c75b4609b 100644 --- a/builtin/write-tree.c +++ b/builtin/write-tree.c @@ -3,7 +3,7 @@ * * Copyright (C) Linus Torvalds, 2005 */ -#define USE_THE_INDEX_VARIABLE + #include "builtin.h" #include "config.h" #include "environment.h" @@ -44,8 +44,8 @@ int cmd_write_tree(int argc, const char **argv, const char *cmd_prefix) prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; - ret = write_index_as_tree(&oid, &the_index, get_index_file(), flags, - tree_prefix); + ret = write_index_as_tree(&oid, the_repository->index, get_index_file(), + flags, tree_prefix); switch (ret) { case 0: printf("%s\n", oid_to_hex(&oid)); |
