diff options
Diffstat (limited to 'builtin')
75 files changed, 1851 insertions, 782 deletions
diff --git a/builtin/add.c b/builtin/add.c index 8a155dd41e..9916498a29 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -40,7 +40,7 @@ static void chmod_pathspec(struct pathspec *pathspec, char flip) for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; - if (pathspec && !ce_path_match(ce, pathspec, NULL)) + if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL)) continue; if (chmod_cache_entry(ce, flip) < 0) @@ -135,7 +135,7 @@ static int renormalize_tracked_files(const struct pathspec *pathspec, int flags) 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(ce, pathspec, NULL)) + if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL)) continue; retval |= add_file_to_cache(ce->name, flags | HASH_RENORMALIZE); } @@ -155,7 +155,7 @@ 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(entry, pathspec, prefix, seen)) + if (dir_path_match(&the_index, entry, pathspec, prefix, seen)) *dst++ = entry; } dir->nr = dst - dir->entries; @@ -304,7 +304,8 @@ static struct option builtin_add_options[] = { OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")), OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")), OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")), - OPT_STRING( 0 , "chmod", &chmod_arg, N_("(+/-)x"), N_("override the executable bit of the listed files")), + OPT_STRING(0, "chmod", &chmod_arg, "(+|-)x", + N_("override the executable bit of the listed files")), OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo, N_("warn when adding an embedded repository")), OPT_END(), diff --git a/builtin/am.c b/builtin/am.c index 6273ea5195..5e866d17c7 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -32,6 +32,7 @@ #include "apply.h" #include "string-list.h" #include "packfile.h" +#include "repository.h" /** * Returns 1 if the file is empty or does not exist, 0 otherwise. @@ -1400,9 +1401,10 @@ static void write_index_patch(const struct am_state *state) FILE *fp; if (!get_oid_tree("HEAD", &head)) - tree = lookup_tree(&head); + tree = lookup_tree(the_repository, &head); else - tree = lookup_tree(the_hash_algo->empty_tree); + tree = lookup_tree(the_repository, + the_repository->hash_algo->empty_tree); fp = xfopen(am_path(state, "patch"), "w"); init_revisions(&rev_info, NULL); @@ -1462,7 +1464,7 @@ static int run_apply(const struct am_state *state, const char *index_file) int force_apply = 0; int options = 0; - if (init_apply_state(&apply_state, NULL)) + if (init_apply_state(&apply_state, the_repository, NULL)) BUG("init_apply_state() failed"); argv_array_push(&apply_opts, "apply"); @@ -1596,6 +1598,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa o.branch1 = "HEAD"; their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg); o.branch2 = their_tree_name; + o.detect_directory_renames = 0; if (state->quiet) o.verbosity = 0; @@ -1631,7 +1634,8 @@ static void do_commit(const struct am_state *state) if (!get_oid_commit("HEAD", &parent)) { old_oid = &parent; - commit_list_insert(lookup_commit(&parent), &parents); + commit_list_insert(lookup_commit(the_repository, &parent), + &parents); } else { old_oid = NULL; say(state, stderr, _("applying to an empty history")); @@ -1763,7 +1767,7 @@ static void am_run(struct am_state *state, int resume) refresh_and_write_cache(); - if (index_has_changes(&sb)) { + if (index_has_changes(&the_index, NULL, &sb)) { write_state_bool(state, "dirtyindex", 1); die(_("Dirty index: cannot apply patches (dirty: %s)"), sb.buf); } @@ -1820,7 +1824,8 @@ static void am_run(struct am_state *state, int resume) * Applying the patch to an earlier tree and merging * the result may have produced the same tree as ours. */ - if (!apply_status && !index_has_changes(NULL)) { + if (!apply_status && + !index_has_changes(&the_index, NULL, NULL)) { say(state, stdout, _("No changes -- Patch already applied.")); goto next; } @@ -1874,7 +1879,7 @@ static void am_resolve(struct am_state *state) say(state, stdout, _("Applying: %.*s"), linelen(state->msg), state->msg); - if (!index_has_changes(NULL)) { + if (!index_has_changes(&the_index, NULL, NULL)) { printf_ln(_("No changes - did you forget to use 'git add'?\n" "If there is nothing left to stage, chances are that something else\n" "already introduced the same changes; you might want to skip this patch.")); diff --git a/builtin/apply.c b/builtin/apply.c index 48d3989331..3f099b9605 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -16,7 +16,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix) int ret; struct apply_state state; - if (init_apply_state(&state, prefix)) + if (init_apply_state(&state, the_repository, prefix)) exit(128); argc = apply_parse_options(argc, argv, diff --git a/builtin/archive.c b/builtin/archive.c index 73971d0dd2..e74f675390 100644 --- a/builtin/archive.c +++ b/builtin/archive.c @@ -105,5 +105,5 @@ int cmd_archive(int argc, const char **argv, const char *prefix) setvbuf(stderr, NULL, _IOLBF, BUFSIZ); - return write_archive(argc, argv, prefix, output, 0); + return write_archive(argc, argv, prefix, the_repository, output, 0); } diff --git a/builtin/blame.c b/builtin/blame.c index 5a0388aaef..c2da673ac8 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -9,6 +9,7 @@ #include "config.h" #include "color.h" #include "builtin.h" +#include "repository.h" #include "commit.h" #include "diff.h" #include "revision.h" @@ -23,6 +24,7 @@ #include "line-log.h" #include "dir.h" #include "progress.h" +#include "object-store.h" #include "blame.h" #include "string-list.h" @@ -408,7 +410,7 @@ static void parse_color_fields(const char *s) } if (next == EXPECT_COLOR) - die (_("must end with a color")); + die(_("must end with a color")); colorfield[colorfield_nr].hop = TIME_MAX; string_list_clear(&l, 0); @@ -576,7 +578,7 @@ static int read_ancestry(const char *graft_file) /* The format is just "Commit Parent1 Parent2 ...\n" */ struct commit_graft *graft = read_graft_line(&buf); if (graft) - register_commit_graft(graft, 0); + register_commit_graft(the_repository, graft, 0); } fclose(fp); strbuf_release(&buf); @@ -986,6 +988,7 @@ parse_done: sb.revs = &revs; sb.contents_from = contents_from; sb.reverse = reverse; + sb.repo = the_repository; setup_scoreboard(&sb, path, &o); lno = sb.num_lines; @@ -1000,13 +1003,13 @@ parse_done: nth_line_cb, &sb, lno, anchor, &bottom, &top, sb.path)) usage(blame_usage); - if (lno < top || ((lno || bottom) && lno < bottom)) + if ((!lno && (top || bottom)) || lno < bottom) die(Q_("file %s has only %lu line", "file %s has only %lu lines", lno), path, lno); if (bottom < 1) bottom = 1; - if (top < 1) + if (top < 1 || lno < top) top = lno; bottom--; range_set_append_unsafe(&ranges, bottom, top); @@ -1069,7 +1072,9 @@ parse_done: find_alignment(&sb, &output_option); if (!*repeated_meta_color && (output_option & OUTPUT_COLOR_LINE)) - strcpy(repeated_meta_color, GIT_COLOR_CYAN); + xsnprintf(repeated_meta_color, + sizeof(repeated_meta_color), + "%s", GIT_COLOR_CYAN); } if (output_option & OUTPUT_ANNOTATE_COMPAT) output_option &= ~(OUTPUT_COLOR_LINE | OUTPUT_SHOW_AGE_WITH_COLOR); diff --git a/builtin/branch.c b/builtin/branch.c index 1876ca9e79..c396c41533 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -23,6 +23,7 @@ #include "ref-filter.h" #include "worktree.h" #include "help.h" +#include "commit-reach.h" static const char * const builtin_branch_usage[] = { N_("git branch [<options>] [-r | -a] [--merged | --no-merged]"), @@ -73,6 +74,14 @@ define_list_config_array(color_branch_slots); static int git_branch_config(const char *var, const char *value, void *cb) { const char *slot_name; + struct ref_sorting **sorting_tail = (struct ref_sorting **)cb; + + if (!strcmp(var, "branch.sort")) { + if (!value) + return config_error_nonbool(var); + parse_ref_sorting(sorting_tail, value); + return 0; + } if (starts_with(var, "column.")) return git_column_config(var, value, "branch", &colopts); @@ -121,7 +130,8 @@ static int branch_merged(int kind, const char *name, (reference_name = reference_name_to_free = resolve_refdup(upstream, RESOLVE_REF_READING, &oid, NULL)) != NULL) - reference_rev = lookup_commit_reference(&oid); + reference_rev = lookup_commit_reference(the_repository, + &oid); } if (!reference_rev) reference_rev = head_rev; @@ -154,7 +164,7 @@ static int check_branch_commit(const char *branchname, const char *refname, const struct object_id *oid, struct commit *head_rev, int kinds, int force) { - struct commit *rev = lookup_commit_reference(oid); + struct commit *rev = lookup_commit_reference(the_repository, oid); if (!rev) { error(_("Couldn't look up commit object for '%s'"), refname); return -1; @@ -208,7 +218,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, } if (!force) { - head_rev = lookup_commit_reference(&head_oid); + head_rev = lookup_commit_reference(the_repository, &head_oid); if (!head_rev) die(_("Couldn't look up commit object for HEAD")); } @@ -609,8 +619,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2), OPT_BIT('c', "copy", ©, N_("copy a branch and its reflog"), 1), OPT_BIT('C', NULL, ©, N_("copy a branch, even if target exists"), 2), - OPT_BOOL(0, "list", &list, N_("list branch names")), - OPT_BOOL('l', "create-reflog", &reflog, N_("create the branch's reflog")), + OPT_BOOL('l', "list", &list, N_("list branch names")), + OPT_BOOL(0, "create-reflog", &reflog, N_("create the branch's reflog")), OPT_BOOL(0, "edit-description", &edit_description, N_("edit the description for the branch")), OPT__FORCE(&force, N_("force creation, move/rename, deletion"), PARSE_OPT_NOCOMPLETE), @@ -637,7 +647,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(builtin_branch_usage, options); - git_config(git_branch_config, NULL); + git_config(git_branch_config, sorting_tail); track = git_branch_track; diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 665b581949..64ec1745ab 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -13,6 +13,7 @@ #include "tree-walk.h" #include "sha1-array.h" #include "packfile.h" +#include "object-store.h" struct batch_options { int enabled; @@ -20,6 +21,7 @@ struct batch_options { int print_contents; int buffer_output; int all_objects; + int unordered; int cmdmode; /* may be 'w' or 'c' for --filters or --textconv */ const char *format; }; @@ -38,7 +40,7 @@ static int filter_object(const char *path, unsigned mode, oid_to_hex(oid), path); if ((type == OBJ_BLOB) && S_ISREG(mode)) { struct strbuf strbuf = STRBUF_INIT; - if (convert_to_working_tree(path, *buf, *size, &strbuf)) { + if (convert_to_working_tree(&the_index, path, *buf, *size, &strbuf)) { free(*buf); *size = strbuf.len; *buf = strbuf_detach(&strbuf, NULL); @@ -336,11 +338,11 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d } } -static void batch_object_write(const char *obj_name, struct batch_options *opt, +static void batch_object_write(const char *obj_name, + struct strbuf *scratch, + struct batch_options *opt, struct expand_data *data) { - struct strbuf buf = STRBUF_INIT; - if (!data->skip_object_info && oid_object_info_extended(the_repository, &data->oid, &data->info, OBJECT_INFO_LOOKUP_REPLACE) < 0) { @@ -350,10 +352,10 @@ static void batch_object_write(const char *obj_name, struct batch_options *opt, return; } - strbuf_expand(&buf, opt->format, expand_format, data); - strbuf_addch(&buf, '\n'); - batch_write(opt, buf.buf, buf.len); - strbuf_release(&buf); + strbuf_reset(scratch); + strbuf_expand(scratch, opt->format, expand_format, data); + strbuf_addch(scratch, '\n'); + batch_write(opt, scratch->buf, scratch->len); if (opt->print_contents) { print_object_or_die(opt, data); @@ -361,7 +363,9 @@ static void batch_object_write(const char *obj_name, struct batch_options *opt, } } -static void batch_one_object(const char *obj_name, struct batch_options *opt, +static void batch_one_object(const char *obj_name, + struct strbuf *scratch, + struct batch_options *opt, struct expand_data *data) { struct object_context ctx; @@ -403,42 +407,70 @@ static void batch_one_object(const char *obj_name, struct batch_options *opt, return; } - batch_object_write(obj_name, opt, data); + batch_object_write(obj_name, scratch, opt, data); } struct object_cb_data { struct batch_options *opt; struct expand_data *expand; + struct oidset *seen; + struct strbuf *scratch; }; static int batch_object_cb(const struct object_id *oid, void *vdata) { struct object_cb_data *data = vdata; oidcpy(&data->expand->oid, oid); - batch_object_write(NULL, data->opt, data->expand); + batch_object_write(NULL, data->scratch, data->opt, data->expand); return 0; } -static int batch_loose_object(const struct object_id *oid, - const char *path, - void *data) +static int collect_loose_object(const struct object_id *oid, + const char *path, + void *data) { oid_array_append(data, oid); return 0; } -static int batch_packed_object(const struct object_id *oid, - struct packed_git *pack, - uint32_t pos, - void *data) +static int collect_packed_object(const struct object_id *oid, + struct packed_git *pack, + uint32_t pos, + void *data) { oid_array_append(data, oid); return 0; } +static int batch_unordered_object(const struct object_id *oid, void *vdata) +{ + struct object_cb_data *data = vdata; + + if (oidset_insert(data->seen, oid)) + return 0; + + return batch_object_cb(oid, data); +} + +static int batch_unordered_loose(const struct object_id *oid, + const char *path, + void *data) +{ + return batch_unordered_object(oid, data); +} + +static int batch_unordered_packed(const struct object_id *oid, + struct packed_git *pack, + uint32_t pos, + void *data) +{ + return batch_unordered_object(oid, data); +} + static int batch_objects(struct batch_options *opt) { - struct strbuf buf = STRBUF_INIT; + struct strbuf input = STRBUF_INIT; + struct strbuf output = STRBUF_INIT; struct expand_data data; int save_warning; int retval = 0; @@ -453,8 +485,9 @@ static int batch_objects(struct batch_options *opt) */ memset(&data, 0, sizeof(data)); data.mark_query = 1; - strbuf_expand(&buf, opt->format, expand_format, &data); + strbuf_expand(&output, opt->format, expand_format, &data); data.mark_query = 0; + strbuf_release(&output); if (opt->cmdmode) data.split_on_whitespace = 1; @@ -472,19 +505,37 @@ static int batch_objects(struct batch_options *opt) data.info.typep = &data.type; if (opt->all_objects) { - struct oid_array sa = OID_ARRAY_INIT; struct object_cb_data cb; - for_each_loose_object(batch_loose_object, &sa, 0); - for_each_packed_object(batch_packed_object, &sa, 0); if (repository_format_partial_clone) warning("This repository has extensions.partialClone set. Some objects may not be loaded."); cb.opt = opt; cb.expand = &data; - oid_array_for_each_unique(&sa, batch_object_cb, &cb); + cb.scratch = &output; + + if (opt->unordered) { + struct oidset seen = OIDSET_INIT; + + cb.seen = &seen; + + for_each_loose_object(batch_unordered_loose, &cb, 0); + for_each_packed_object(batch_unordered_packed, &cb, + FOR_EACH_OBJECT_PACK_ORDER); + + oidset_clear(&seen); + } else { + struct oid_array sa = OID_ARRAY_INIT; + + for_each_loose_object(collect_loose_object, &sa, 0); + for_each_packed_object(collect_packed_object, &sa, 0); + + oid_array_for_each_unique(&sa, batch_object_cb, &cb); + + oid_array_clear(&sa); + } - oid_array_clear(&sa); + strbuf_release(&output); return 0; } @@ -498,14 +549,14 @@ static int batch_objects(struct batch_options *opt) save_warning = warn_on_object_refname_ambiguity; warn_on_object_refname_ambiguity = 0; - while (strbuf_getline(&buf, stdin) != EOF) { + while (strbuf_getline(&input, stdin) != EOF) { if (data.split_on_whitespace) { /* * Split at first whitespace, tying off the beginning * of the string and saving the remainder (or NULL) in * data.rest. */ - char *p = strpbrk(buf.buf, " \t"); + char *p = strpbrk(input.buf, " \t"); if (p) { while (*p && strchr(" \t", *p)) *p++ = '\0'; @@ -513,10 +564,11 @@ static int batch_objects(struct batch_options *opt) data.rest = p; } - batch_one_object(buf.buf, opt, &data); + batch_one_object(input.buf, &output, opt, &data); } - strbuf_release(&buf); + strbuf_release(&input); + strbuf_release(&output); warn_on_object_refname_ambiguity = save_warning; return retval; } @@ -585,6 +637,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix) N_("follow in-tree symlinks (used with --batch or --batch-check)")), OPT_BOOL(0, "batch-all-objects", &batch.all_objects, N_("show all objects with --batch or --batch-check")), + OPT_BOOL(0, "unordered", &batch.unordered, + N_("do not order --batch-all-objects output")), OPT_END() }; diff --git a/builtin/check-attr.c b/builtin/check-attr.c index 91444dc044..c05573ff9c 100644 --- a/builtin/check-attr.c +++ b/builtin/check-attr.c @@ -63,9 +63,9 @@ static void check_attr(const char *prefix, prefix_path(prefix, prefix ? strlen(prefix) : 0, file); if (collect_all) { - git_all_attrs(full_path, check); + git_all_attrs(&the_index, full_path, check); } else { - if (git_check_attr(full_path, check)) + if (git_check_attr(&the_index, full_path, check)) die("git_check_attr died"); } output_attr(check, file); @@ -120,7 +120,7 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix) } if (cached_attrs) - git_attr_set_direction(GIT_ATTR_INDEX, NULL); + git_attr_set_direction(GIT_ATTR_INDEX); doubledash = -1; for (i = 0; doubledash < 0 && i < argc; i++) { diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index a730f6a1aa..88b86c8d9f 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -172,7 +172,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) N_("write the content to temporary files")), OPT_STRING(0, "prefix", &state.base_dir, N_("string"), N_("when creating files, prepend <string>")), - { OPTION_CALLBACK, 0, "stage", NULL, "1-3|all", + { OPTION_CALLBACK, 0, "stage", NULL, "(1|2|3|all)", N_("copy out the files from named stage"), PARSE_OPT_NONEG, option_parse_stage }, OPT_END() @@ -190,6 +190,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.force = force; state.quiet = quiet; state.not_new = not_new; diff --git a/builtin/checkout.c b/builtin/checkout.c index 4c41d8b4c8..67a83fb95b 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -4,6 +4,7 @@ #include "lockfile.h" #include "parse-options.h" #include "refs.h" +#include "object-store.h" #include "commit.h" #include "tree.h" #include "tree-walk.h" @@ -22,6 +23,9 @@ #include "resolve-undo.h" #include "submodule-config.h" #include "submodule.h" +#include "advice.h" + +static int checkout_optimize_new_branch; static const char * const checkout_usage[] = { N_("git checkout [<options>] <branch>"), @@ -40,6 +44,10 @@ struct checkout_opts { int ignore_skipworktree; int ignore_other_worktrees; int show_progress; + /* + * If new checkout options are added, skip_merge_working_tree + * should be updated accordingly. + */ const char *new_branch; const char *new_branch_force; @@ -77,7 +85,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base, return READ_TREE_RECURSIVE; len = base->len + strlen(pathname); - ce = xcalloc(1, cache_entry_size(len)); + ce = make_empty_cache_entry(&the_index, len); oidcpy(&ce->oid, oid); memcpy(ce->name, base->buf, base->len); memcpy(ce->name + base->len, pathname, len - base->len); @@ -96,7 +104,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base, if (ce->ce_mode == old->ce_mode && !oidcmp(&ce->oid, &old->oid)) { old->ce_flags |= CE_UPDATE; - free(ce); + discard_cache_entry(ce); return 0; } } @@ -230,11 +238,11 @@ static int checkout_merged(int pos, const struct checkout *state) if (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid)) die(_("Unable to add merge result for '%s'"), path); free(result_buf.ptr); - ce = make_cache_entry(mode, oid.hash, path, 2, 0); + ce = make_transient_cache_entry(mode, &oid, path, 2); if (!ce) die(_("make_cache_entry failed for path '%s'"), path); status = checkout_entry(ce, state, NULL); - free(ce); + discard_cache_entry(ce); return status; } @@ -316,7 +324,7 @@ static int checkout_paths(const struct checkout_opts *opts, * match_pathspec() for _all_ entries when * opts->source_tree != NULL. */ - if (ce_path_match(ce, &opts->pathspec, ps_matched)) + if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) ce->ce_flags |= CE_MATCHED; } @@ -378,7 +386,7 @@ static int checkout_paths(const struct checkout_opts *opts, die(_("unable to write new index file")); read_ref_full("HEAD", 0, &rev, NULL); - head = lookup_commit_reference_gently(&rev, 1); + head = lookup_commit_reference_gently(the_repository, &rev, 1); errs |= post_checkout_hook(head, head, 0); return errs; @@ -470,6 +478,98 @@ static void setup_branch_path(struct branch_info *branch) branch->path = strbuf_detach(&buf, NULL); } +/* + * Skip merging the trees, updating the index and working directory if and + * only if we are creating a new branch via "git checkout -b <new_branch>." + */ +static int skip_merge_working_tree(const struct checkout_opts *opts, + const struct branch_info *old_branch_info, + const struct branch_info *new_branch_info) +{ + /* + * Do the merge if sparse checkout is on and the user has not opted in + * to the optimized behavior + */ + if (core_apply_sparse_checkout && !checkout_optimize_new_branch) + return 0; + + /* + * We must do the merge if we are actually moving to a new commit. + */ + if (!old_branch_info->commit || !new_branch_info->commit || + oidcmp(&old_branch_info->commit->object.oid, &new_branch_info->commit->object.oid)) + return 0; + + /* + * opts->patch_mode cannot be used with switching branches so is + * not tested here + */ + + /* + * opts->quiet only impacts output so doesn't require a merge + */ + + /* + * Honor the explicit request for a three-way merge or to throw away + * local changes + */ + if (opts->merge || opts->force) + return 0; + + /* + * --detach is documented as "updating the index and the files in the + * working tree" but this optimization skips those steps so fall through + * to the regular code path. + */ + if (opts->force_detach) + return 0; + + /* + * opts->writeout_stage cannot be used with switching branches so is + * not tested here + */ + + /* + * Honor the explicit ignore requests + */ + if (!opts->overwrite_ignore || opts->ignore_skipworktree || + opts->ignore_other_worktrees) + return 0; + + /* + * opts->show_progress only impacts output so doesn't require a merge + */ + + /* + * If we aren't creating a new branch any changes or updates will + * happen in the existing branch. Since that could only be updating + * the index and working directory, we don't want to skip those steps + * or we've defeated any purpose in running the command. + */ + if (!opts->new_branch) + return 0; + + /* + * new_branch_force is defined to "create/reset and checkout a branch" + * so needs to go through the merge to do the reset + */ + if (opts->new_branch_force) + return 0; + + /* + * A new orphaned branch requrires the index and the working tree to be + * adjusted to <start_point> + */ + if (opts->new_orphan_branch) + return 0; + + /* + * Remaining variables are not checkout options but used to track state + */ + + return 1; +} + static int merge_working_tree(const struct checkout_opts *opts, struct branch_info *old_branch_info, struct branch_info *new_branch_info, @@ -829,7 +929,7 @@ static int switch_branches(const struct checkout_opts *opts, memset(&old_branch_info, 0, sizeof(old_branch_info)); old_branch_info.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag); if (old_branch_info.path) - old_branch_info.commit = lookup_commit_reference_gently(&rev, 1); + old_branch_info.commit = lookup_commit_reference_gently(the_repository, &rev, 1); if (!(flag & REF_ISSYMREF)) old_branch_info.path = NULL; @@ -844,10 +944,19 @@ static int switch_branches(const struct checkout_opts *opts, parse_commit_or_die(new_branch_info->commit); } - ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error); - if (ret) { - free(path_to_free); - return ret; + /* optimize the "checkout -b <new_branch> path */ + if (skip_merge_working_tree(opts, &old_branch_info, new_branch_info)) { + if (!checkout_optimize_new_branch && !opts->quiet) { + if (read_cache_preload(NULL) < 0) + return error(_("index file corrupt")); + show_local_changes(&new_branch_info->commit->object, &opts->diff_options); + } + } else { + ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error); + if (ret) { + free(path_to_free); + return ret; + } } if (!opts->quiet && !old_branch_info.path && old_branch_info.commit && new_branch_info->commit != old_branch_info.commit) @@ -862,6 +971,11 @@ static int switch_branches(const struct checkout_opts *opts, static int git_checkout_config(const char *var, const char *value, void *cb) { + if (!strcmp(var, "checkout.optimizenewbranch")) { + checkout_optimize_new_branch = git_config_bool(var, value); + return 0; + } + if (!strcmp(var, "diff.ignoresubmodules")) { struct checkout_opts *opts = cb; handle_ignore_submodules_arg(&opts->diff_options, value); @@ -878,7 +992,8 @@ static int parse_branchname_arg(int argc, const char **argv, int dwim_new_local_branch_ok, struct branch_info *new_branch_info, struct checkout_opts *opts, - struct object_id *rev) + struct object_id *rev, + int *dwim_remotes_matched) { struct tree **source_tree = &opts->source_tree; const char **new_branch = &opts->new_branch; @@ -910,8 +1025,10 @@ static int parse_branchname_arg(int argc, const char **argv, * (b) If <something> is _not_ a commit, either "--" is present * or <something> is not a path, no -t or -b was given, and * and there is a tracking branch whose name is <something> - * in one and only one remote, then this is a short-hand to - * fork local <something> from that remote-tracking branch. + * in one and only one remote (or if the branch exists on the + * remote named in checkout.defaultRemote), then this is a + * short-hand to fork local <something> from that + * remote-tracking branch. * * (c) Otherwise, if "--" is present, treat it like case (1). * @@ -972,7 +1089,8 @@ static int parse_branchname_arg(int argc, const char **argv, recover_with_dwim = 0; if (recover_with_dwim) { - const char *remote = unique_tracking_name(arg, rev); + const char *remote = unique_tracking_name(arg, rev, + dwim_remotes_matched); if (remote) { *new_branch = arg; arg = remote; @@ -1003,7 +1121,7 @@ static int parse_branchname_arg(int argc, const char **argv, else new_branch_info->path = NULL; /* not an existing branch */ - new_branch_info->commit = lookup_commit_reference_gently(rev, 1); + new_branch_info->commit = lookup_commit_reference_gently(the_repository, rev, 1); if (!new_branch_info->commit) { /* not a commit */ *source_tree = parse_tree_indirect(rev); @@ -1109,6 +1227,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) struct branch_info new_branch_info; char *conflict_style = NULL; int dwim_new_local_branch = 1; + int dwim_remotes_matched = 0; struct option options[] = { OPT__QUIET(&opts.quiet, N_("suppress progress reporting")), OPT_STRING('b', NULL, &opts.new_branch, N_("branch"), @@ -1191,12 +1310,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) if (opts.track != BRANCH_TRACK_UNSPECIFIED && !opts.new_branch) { const char *argv0 = argv[0]; if (!argc || !strcmp(argv0, "--")) - die (_("--track needs a branch name")); + die(_("--track needs a branch name")); skip_prefix(argv0, "refs/", &argv0); skip_prefix(argv0, "remotes/", &argv0); argv0 = strchr(argv0, '/'); if (!argv0 || !argv0[1]) - die (_("Missing branch name; try -b")); + die(_("missing branch name; try -b")); opts.new_branch = argv0 + 1; } @@ -1221,7 +1340,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) opts.track == BRANCH_TRACK_UNSPECIFIED && !opts.new_branch; int n = parse_branchname_arg(argc, argv, dwim_ok, - &new_branch_info, &opts, &rev); + &new_branch_info, &opts, &rev, + &dwim_remotes_matched); argv += n; argc -= n; } @@ -1263,8 +1383,26 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) } UNLEAK(opts); - if (opts.patch_mode || opts.pathspec.nr) - return checkout_paths(&opts, new_branch_info.name); - else + if (opts.patch_mode || opts.pathspec.nr) { + int ret = checkout_paths(&opts, new_branch_info.name); + if (ret && dwim_remotes_matched > 1 && + advice_checkout_ambiguous_remote_branch_name) + advise(_("'%s' matched more than one remote tracking branch.\n" + "We found %d remotes with a reference that matched. So we fell back\n" + "on trying to resolve the argument as a path, but failed there too!\n" + "\n" + "If you meant to check out a remote tracking branch on, e.g. 'origin',\n" + "you can do so by fully qualifying the name with the --track option:\n" + "\n" + " git checkout --track origin/<name>\n" + "\n" + "If you'd like to always have checkouts of an ambiguous <name> prefer\n" + "one remote, e.g. the 'origin' remote, consider setting\n" + "checkout.defaultRemote=origin in your config."), + argv[0], + dwim_remotes_matched); + return ret; + } else { return checkout_branch(&opts, &new_branch_info); + } } diff --git a/builtin/clean.c b/builtin/clean.c index ab402c204c..8d9a7dc206 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -976,7 +976,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) continue; if (pathspec.nr) - matches = dir_path_match(ent, &pathspec, 0, NULL); + matches = dir_path_match(&the_index, ent, &pathspec, 0, NULL); if (pathspec.nr && !matches) continue; diff --git a/builtin/clone.c b/builtin/clone.c index 74a804f2e8..15b142d646 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -15,6 +15,7 @@ #include "fetch-pack.h" #include "refs.h" #include "refspec.h" +#include "object-store.h" #include "tree.h" #include "tree-walk.h" #include "unpack-trees.h" @@ -695,7 +696,8 @@ static void update_head(const struct ref *our, const struct ref *remote, install_branch_config(0, head, option_origin, our->name); } } else if (our) { - struct commit *c = lookup_commit_reference(&our->old_oid); + struct commit *c = lookup_commit_reference(the_repository, + &our->old_oid); /* --branch specifies a non-branch (i.e. tags), detach HEAD */ update_ref(msg, "HEAD", &c->object.oid, NULL, REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR); @@ -746,6 +748,7 @@ static int checkout(int submodule_progress) memset(&opts, 0, sizeof opts); opts.update = 1; opts.merge = 1; + opts.clone = 1; opts.fn = oneway_merge; opts.verbose_update = (option_verbosity >= 0); opts.src_index = &the_index; @@ -895,7 +898,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) int err = 0, complete_refs_before_fetch = 1; int submodule_progress; - struct refspec_item refspec; + struct refspec rs = REFSPEC_INIT_FETCH; + struct argv_array ref_prefixes = ARGV_ARRAY_INIT; fetch_if_missing = 0; @@ -1077,7 +1081,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (option_required_reference.nr || option_optional_reference.nr) setup_reference(); - refspec_item_init_or_die(&refspec, value.buf, REFSPEC_FETCH); + refspec_append(&rs, value.buf); strbuf_reset(&value); @@ -1134,10 +1138,18 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (transport->smart_options && !deepen && !filter_options.choice) transport->smart_options->check_self_contained_and_connected = 1; - refs = transport_get_remote_refs(transport, NULL); + + argv_array_push(&ref_prefixes, "HEAD"); + refspec_ref_prefixes(&rs, &ref_prefixes); + if (option_branch) + expand_ref_prefix(&ref_prefixes, option_branch); + if (!option_no_tags) + argv_array_push(&ref_prefixes, "refs/tags/"); + + refs = transport_get_remote_refs(transport, &ref_prefixes); if (refs) { - mapped_refs = wanted_peer_refs(refs, &refspec); + mapped_refs = wanted_peer_refs(refs, &rs.items[0]); /* * transport_get_remote_refs() may return refs with null sha-1 * in mapped_refs (see struct transport->get_refs_list @@ -1201,7 +1213,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) update_remote_refs(refs, mapped_refs, remote_head_points_at, branch_top.buf, reflog_msg.buf, transport, - !is_local && !filter_options.choice); + !is_local); update_head(our_head_points_at, remote_head, reflog_msg.buf); @@ -1231,6 +1243,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) strbuf_release(&value); junk_mode = JUNK_LEAVE_ALL; - refspec_item_clear(&refspec); + refspec_clear(&rs); + argv_array_clear(&ref_prefixes); return err; } diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c index 37420ae0fd..0bf0c48657 100644 --- a/builtin/commit-graph.c +++ b/builtin/commit-graph.c @@ -3,12 +3,19 @@ #include "dir.h" #include "lockfile.h" #include "parse-options.h" +#include "repository.h" #include "commit-graph.h" static char const * const builtin_commit_graph_usage[] = { N_("git commit-graph [--object-dir <objdir>]"), N_("git commit-graph read [--object-dir <objdir>]"), - N_("git commit-graph write [--object-dir <objdir>] [--append] [--stdin-packs|--stdin-commits]"), + N_("git commit-graph verify [--object-dir <objdir>]"), + N_("git commit-graph write [--object-dir <objdir>] [--append] [--reachable|--stdin-packs|--stdin-commits]"), + NULL +}; + +static const char * const builtin_commit_graph_verify_usage[] = { + N_("git commit-graph verify [--object-dir <objdir>]"), NULL }; @@ -18,17 +25,48 @@ static const char * const builtin_commit_graph_read_usage[] = { }; static const char * const builtin_commit_graph_write_usage[] = { - N_("git commit-graph write [--object-dir <objdir>] [--append] [--stdin-packs|--stdin-commits]"), + N_("git commit-graph write [--object-dir <objdir>] [--append] [--reachable|--stdin-packs|--stdin-commits]"), NULL }; static struct opts_commit_graph { const char *obj_dir; + int reachable; int stdin_packs; int stdin_commits; int append; } opts; + +static int graph_verify(int argc, const char **argv) +{ + struct commit_graph *graph = NULL; + char *graph_name; + + static struct option builtin_commit_graph_verify_options[] = { + OPT_STRING(0, "object-dir", &opts.obj_dir, + N_("dir"), + N_("The object directory to store the graph")), + OPT_END(), + }; + + argc = parse_options(argc, argv, NULL, + builtin_commit_graph_verify_options, + builtin_commit_graph_verify_usage, 0); + + if (!opts.obj_dir) + opts.obj_dir = get_object_directory(); + + graph_name = get_commit_graph_filename(opts.obj_dir); + graph = load_commit_graph_one(graph_name); + FREE_AND_NULL(graph_name); + + if (!graph) + return 0; + + return verify_commit_graph(the_repository, graph); +} + static int graph_read(int argc, const char **argv) { struct commit_graph *graph = NULL; @@ -51,8 +89,11 @@ static int graph_read(int argc, const char **argv) graph_name = get_commit_graph_filename(opts.obj_dir); graph = load_commit_graph_one(graph_name); - if (!graph) + if (!graph) { + UNLEAK(graph_name); die("graph file %s does not exist", graph_name); + } + FREE_AND_NULL(graph_name); printf("header: %08x %d %d %d %d\n", @@ -74,23 +115,23 @@ static int graph_read(int argc, const char **argv) printf(" large_edges"); printf("\n"); + free_commit_graph(graph); + return 0; } static int graph_write(int argc, const char **argv) { - const char **pack_indexes = NULL; - int packs_nr = 0; - const char **commit_hex = NULL; - int commits_nr = 0; - const char **lines = NULL; - int lines_nr = 0; - int lines_alloc = 0; + struct string_list *pack_indexes = NULL; + struct string_list *commit_hex = NULL; + struct string_list lines; static struct option builtin_commit_graph_write_options[] = { OPT_STRING(0, "object-dir", &opts.obj_dir, N_("dir"), N_("The object directory to store the graph")), + OPT_BOOL(0, "reachable", &opts.reachable, + N_("start walk at all refs")), OPT_BOOL(0, "stdin-packs", &opts.stdin_packs, N_("scan pack-indexes listed by stdin for commits")), OPT_BOOL(0, "stdin-commits", &opts.stdin_commits, @@ -104,39 +145,35 @@ static int graph_write(int argc, const char **argv) builtin_commit_graph_write_options, builtin_commit_graph_write_usage, 0); - if (opts.stdin_packs && opts.stdin_commits) - die(_("cannot use both --stdin-commits and --stdin-packs")); + if (opts.reachable + opts.stdin_packs + opts.stdin_commits > 1) + die(_("use at most one of --reachable, --stdin-commits, or --stdin-packs")); if (!opts.obj_dir) opts.obj_dir = get_object_directory(); + if (opts.reachable) { + write_commit_graph_reachable(opts.obj_dir, opts.append); + return 0; + } + + string_list_init(&lines, 0); if (opts.stdin_packs || opts.stdin_commits) { struct strbuf buf = STRBUF_INIT; - lines_nr = 0; - lines_alloc = 128; - ALLOC_ARRAY(lines, lines_alloc); - - while (strbuf_getline(&buf, stdin) != EOF) { - ALLOC_GROW(lines, lines_nr + 1, lines_alloc); - lines[lines_nr++] = strbuf_detach(&buf, NULL); - } - - if (opts.stdin_packs) { - pack_indexes = lines; - packs_nr = lines_nr; - } - if (opts.stdin_commits) { - commit_hex = lines; - commits_nr = lines_nr; - } + + while (strbuf_getline(&buf, stdin) != EOF) + string_list_append(&lines, strbuf_detach(&buf, NULL)); + + if (opts.stdin_packs) + pack_indexes = &lines; + if (opts.stdin_commits) + commit_hex = &lines; } write_commit_graph(opts.obj_dir, pack_indexes, - packs_nr, commit_hex, - commits_nr, opts.append); + string_list_clear(&lines, 0); return 0; } @@ -162,6 +199,8 @@ int cmd_commit_graph(int argc, const char **argv, const char *prefix) if (argc > 0) { if (!strcmp(argv[0], "read")) return graph_read(argc, argv); + if (!strcmp(argv[0], "verify")) + return graph_verify(argc, argv); if (!strcmp(argv[0], "write")) return graph_write(argc, argv); } diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index ecf42191da..9ec36a82b6 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -5,6 +5,8 @@ */ #include "cache.h" #include "config.h" +#include "object-store.h" +#include "repository.h" #include "commit.h" #include "tree.h" #include "builtin.h" @@ -59,7 +61,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) if (get_oid_commit(argv[i], &oid)) die("Not a valid object name %s", argv[i]); assert_oid_type(&oid, OBJ_COMMIT); - new_parent(lookup_commit(&oid), &parents); + new_parent(lookup_commit(the_repository, &oid), + &parents); continue; } diff --git a/builtin/commit.c b/builtin/commit.c index 9bcbb0c25c..fa3e53232d 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -33,6 +33,7 @@ #include "sequencer.h" #include "mailmap.h" #include "help.h" +#include "commit-reach.h" static const char * const builtin_commit_usage[] = { N_("git commit [<options>] [--] <pathspec>..."), @@ -168,9 +169,9 @@ static int opt_parse_rename_score(const struct option *opt, const char *arg, int static void determine_whence(struct wt_status *s) { - if (file_exists(git_path_merge_head())) + if (file_exists(git_path_merge_head(the_repository))) whence = FROM_MERGE; - else if (file_exists(git_path_cherry_pick_head())) { + else if (file_exists(git_path_cherry_pick_head(the_repository))) { whence = FROM_CHERRY_PICK; if (file_exists(git_path_seq_dir())) sequencer_in_use = 1; @@ -251,7 +252,7 @@ static int list_paths(struct string_list *list, const char *with_tree, if (ce->ce_flags & CE_UPDATE) continue; - if (!ce_path_match(ce, pattern, m)) + if (!ce_path_match(&the_index, ce, pattern, m)) continue; item = string_list_insert(list, ce->name); if (ce_skip_worktree(ce)) @@ -718,21 +719,21 @@ static int prepare_to_commit(const char *index_file, const char *prefix, if (have_option_m) strbuf_addbuf(&sb, &message); hook_arg1 = "message"; - } else if (!stat(git_path_merge_msg(), &statbuf)) { + } else if (!stat(git_path_merge_msg(the_repository), &statbuf)) { /* * prepend SQUASH_MSG here if it exists and a * "merge --squash" was originally performed */ - if (!stat(git_path_squash_msg(), &statbuf)) { - if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0) + if (!stat(git_path_squash_msg(the_repository), &statbuf)) { + if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0) die_errno(_("could not read SQUASH_MSG")); hook_arg1 = "squash"; } else hook_arg1 = "merge"; - if (strbuf_read_file(&sb, git_path_merge_msg(), 0) < 0) + if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0) die_errno(_("could not read MERGE_MSG")); - } else if (!stat(git_path_squash_msg(), &statbuf)) { - if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0) + } else if (!stat(git_path_squash_msg(the_repository), &statbuf)) { + if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0) die_errno(_("could not read SQUASH_MSG")); hook_arg1 = "squash"; } else if (template_file) { @@ -813,8 +814,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix, " %s\n" "and try again.\n"), whence == FROM_MERGE ? - git_path_merge_head() : - git_path_cherry_pick_head()); + git_path_merge_head(the_repository) : + git_path_cherry_pick_head(the_repository)); } fprintf(s->fp, "\n"); @@ -1564,7 +1565,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (!reflog_msg) reflog_msg = "commit (merge)"; pptr = commit_list_append(current_head, pptr); - fp = xfopen(git_path_merge_head(), "r"); + fp = xfopen(git_path_merge_head(the_repository), "r"); while (strbuf_getline_lf(&m, fp) != EOF) { struct commit *parent; @@ -1575,8 +1576,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) } fclose(fp); strbuf_release(&m); - if (!stat(git_path_merge_mode(), &statbuf)) { - if (strbuf_read_file(&sb, git_path_merge_mode(), 0) < 0) + if (!stat(git_path_merge_mode(the_repository), &statbuf)) { + if (strbuf_read_file(&sb, git_path_merge_mode(the_repository), 0) < 0) die_errno(_("could not read MERGE_MODE")); if (!strcmp(sb.buf, "no-ff")) allow_fast_forward = 0; @@ -1639,17 +1640,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix) die("%s", err.buf); } - unlink(git_path_cherry_pick_head()); - unlink(git_path_revert_head()); - unlink(git_path_merge_head()); - unlink(git_path_merge_msg()); - unlink(git_path_merge_mode()); - unlink(git_path_squash_msg()); + unlink(git_path_cherry_pick_head(the_repository)); + unlink(git_path_revert_head(the_repository)); + unlink(git_path_merge_head(the_repository)); + unlink(git_path_merge_msg(the_repository)); + unlink(git_path_merge_mode(the_repository)); + unlink(git_path_squash_msg(the_repository)); if (commit_index_files()) - die (_("Repository has been updated, but unable to write\n" - "new_index file. Check that disk is not full and quota is\n" - "not exceeded, and then \"git reset HEAD\" to recover.")); + die(_("repository has been updated, but unable to write\n" + "new_index file. Check that disk is not full and quota is\n" + "not exceeded, and then \"git reset HEAD\" to recover.")); rerere(0); run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); diff --git a/builtin/config.c b/builtin/config.c index b29d26dede..97b58c4aea 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -67,7 +67,7 @@ static int show_origin; { OPTION_CALLBACK, (s), (l), (v), NULL, (h), PARSE_OPT_NOARG | \ PARSE_OPT_NONEG, option_parse_type, (i) } -static struct option builtin_config_options[]; +static NORETURN void usage_builtin_config(void); static int option_parse_type(const struct option *opt, const char *arg, int unset) @@ -110,9 +110,8 @@ static int option_parse_type(const struct option *opt, const char *arg, * --int' and '--type=bool * --type=int'. */ - error("only one type at a time."); - usage_with_options(builtin_config_usage, - builtin_config_options); + error(_("only one type at a time")); + usage_builtin_config(); } *to_type = new_type; @@ -157,11 +156,20 @@ static struct option builtin_config_options[] = { 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) return; - error("wrong number of arguments"); - usage_with_options(builtin_config_usage, builtin_config_options); + if (min == max) + error(_("wrong number of arguments, should be %d"), min); + else + error(_("wrong number of arguments, should be from %d to %d"), + min, max); + usage_builtin_config(); } static void show_config_origin(struct strbuf *buf) @@ -293,7 +301,7 @@ static int get_value(const char *key_, const char *regex_) key_regexp = (regex_t*)xmalloc(sizeof(regex_t)); if (regcomp(key_regexp, key, REG_EXTENDED)) { - error("invalid key pattern: %s", key_); + error(_("invalid key pattern: %s"), key_); FREE_AND_NULL(key_regexp); ret = CONFIG_INVALID_PATTERN; goto free_strings; @@ -313,7 +321,7 @@ static int get_value(const char *key_, const char *regex_) regexp = (regex_t*)xmalloc(sizeof(regex_t)); if (regcomp(regexp, regex_, REG_EXTENDED)) { - error("invalid pattern: %s", regex_); + error(_("invalid pattern: %s"), regex_); FREE_AND_NULL(regexp); ret = CONFIG_INVALID_PATTERN; goto free_strings; @@ -386,7 +394,7 @@ static char *normalize_value(const char *key, const char *value) if (type == TYPE_COLOR) { char v[COLOR_MAXLEN]; if (git_config_color(v, key, value)) - die("cannot parse color '%s'", value); + die(_("cannot parse color '%s'"), value); /* * The contents of `v` now contain an ANSI escape @@ -481,13 +489,13 @@ static int get_colorbool(const char *var, int print) static void check_write(void) { if (!given_config_source.file && !startup_info->have_repository) - die("not in a git directory"); + die(_("not in a git directory")); if (given_config_source.use_stdin) - die("writing to stdin is not supported"); + die(_("writing to stdin is not supported")); if (given_config_source.blob) - die("writing config blobs is not supported"); + die(_("writing config blobs is not supported")); } struct urlmatch_current_candidate_value { @@ -595,8 +603,8 @@ int cmd_config(int argc, const char **argv, const char *prefix) if (use_global_config + use_system_config + use_local_config + !!given_config_source.file + !!given_config_source.blob > 1) { - error("only one config file at a time."); - usage_with_options(builtin_config_usage, builtin_config_options); + error(_("only one config file at a time")); + usage_builtin_config(); } if (use_local_config && nongit) @@ -622,7 +630,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) * location; error out even if XDG_CONFIG_HOME * is set and points at a sane location. */ - die("$HOME not set"); + die(_("$HOME not set")); if (access_or_warn(user_config, R_OK, 0) && xdg_config && !access_or_warn(xdg_config, R_OK, 0)) { @@ -659,13 +667,13 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && type) { - error("--get-color and variable type are incoherent"); - usage_with_options(builtin_config_usage, builtin_config_options); + error(_("--get-color and variable type are incoherent")); + usage_builtin_config(); } if (HAS_MULTI_BITS(actions)) { - error("only one action at a time."); - usage_with_options(builtin_config_usage, builtin_config_options); + error(_("only one action at a time")); + usage_builtin_config(); } if (actions == 0) switch (argc) { @@ -673,25 +681,24 @@ int cmd_config(int argc, const char **argv, const char *prefix) case 2: actions = ACTION_SET; break; case 3: actions = ACTION_SET_ALL; break; default: - usage_with_options(builtin_config_usage, builtin_config_options); + usage_builtin_config(); } if (omit_values && !(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) { - error("--name-only is only applicable to --list or --get-regexp"); - usage_with_options(builtin_config_usage, builtin_config_options); + error(_("--name-only is only applicable to --list or --get-regexp")); + usage_builtin_config(); } if (show_origin && !(actions & (ACTION_GET|ACTION_GET_ALL|ACTION_GET_REGEXP|ACTION_LIST))) { - error("--show-origin is only applicable to --get, --get-all, " - "--get-regexp, and --list."); - usage_with_options(builtin_config_usage, builtin_config_options); + error(_("--show-origin is only applicable to --get, --get-all, " + "--get-regexp, and --list")); + usage_builtin_config(); } if (default_value && !(actions & ACTION_GET)) { - error("--default is only applicable to --get"); - usage_with_options(builtin_config_usage, - builtin_config_options); + error(_("--default is only applicable to --get")); + usage_builtin_config(); } if (actions & PAGING_ACTIONS) @@ -703,10 +710,10 @@ int cmd_config(int argc, const char **argv, const char *prefix) &given_config_source, &config_options) < 0) { if (given_config_source.file) - die_errno("unable to read config file '%s'", + die_errno(_("unable to read config file '%s'"), given_config_source.file); else - die("error processing config file(s)"); + die(_("error processing config file(s)")); } } else if (actions == ACTION_EDIT) { @@ -714,11 +721,11 @@ int cmd_config(int argc, const char **argv, const char *prefix) check_argc(argc, 0, 0); if (!given_config_source.file && nongit) - die("not in a git directory"); + die(_("not in a git directory")); if (given_config_source.use_stdin) - die("editing stdin is not supported"); + die(_("editing stdin is not supported")); if (given_config_source.blob) - die("editing blobs is not supported"); + die(_("editing blobs is not supported")); git_config(git_default_config, NULL); config_file = given_config_source.file ? xstrdup(given_config_source.file) : @@ -819,7 +826,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) if (ret < 0) return ret; if (ret == 0) - die("No such section!"); + die(_("no such section: %s"), argv[0]); } else if (actions == ACTION_REMOVE_SECTION) { int ret; @@ -830,7 +837,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) if (ret < 0) return ret; if (ret == 0) - die("No such section!"); + die(_("no such section: %s"), argv[0]); } else if (actions == ACTION_GET_COLOR) { check_argc(argc, 1, 2); diff --git a/builtin/count-objects.c b/builtin/count-objects.c index d51e2ce1ec..a7cad052c6 100644 --- a/builtin/count-objects.c +++ b/builtin/count-objects.c @@ -123,7 +123,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix) struct strbuf pack_buf = STRBUF_INIT; struct strbuf garbage_buf = STRBUF_INIT; - for (p = get_packed_git(the_repository); p; p = p->next) { + for (p = get_all_packs(the_repository); p; p = p->next) { if (!p->pack_local) continue; if (open_pack_index(p)) diff --git a/builtin/describe.c b/builtin/describe.c index bec2513b66..41606c8a90 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -13,6 +13,7 @@ #include "hashmap.h" #include "argv-array.h" #include "run-command.h" +#include "object-store.h" #include "revision.h" #include "list-objects.h" #include "commit-slab.h" @@ -92,13 +93,13 @@ static int replace_name(struct commit_name *e, struct tag *t; if (!e->tag) { - t = lookup_tag(&e->oid); + t = lookup_tag(the_repository, &e->oid); if (!t || parse_tag(t)) return 1; e->tag = t; } - t = lookup_tag(oid); + t = lookup_tag(the_repository, oid); if (!t || parse_tag(t)) return 0; *tag = t; @@ -266,7 +267,7 @@ static unsigned long finish_depth_computation( static void append_name(struct commit_name *n, struct strbuf *dst) { if (n->prio == 2 && !n->tag) { - n->tag = lookup_tag(&n->oid); + n->tag = lookup_tag(the_repository, &n->oid); if (!n->tag || parse_tag(n->tag)) die(_("annotated tag %s not available"), n->path); } @@ -302,7 +303,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst) unsigned long seen_commits = 0; unsigned int unannotated_cnt = 0; - cmit = lookup_commit_reference(oid); + cmit = lookup_commit_reference(the_repository, oid); n = find_commit_name(&cmit->object.oid); if (n && (tags || all || n->prio == 2)) { @@ -330,7 +331,8 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst) init_commit_names(&commit_names); n = hashmap_iter_first(&names, &iter); for (; n; n = hashmap_iter_next(&iter)) { - c = lookup_commit_reference_gently(&n->peeled, 1); + c = lookup_commit_reference_gently(the_repository, + &n->peeled, 1); if (c) *commit_names_at(&commit_names, c) = n; } @@ -508,7 +510,7 @@ static void describe(const char *arg, int last_one) if (get_oid(arg, &oid)) die(_("Not a valid object name %s"), arg); - cmit = lookup_commit_reference_gently(&oid, 1); + cmit = lookup_commit_reference_gently(the_repository, &oid, 1); if (cmit) describe_commit(&oid, &sb); diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index 473615117e..d07bf2e4c4 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -5,12 +5,13 @@ #include "log-tree.h" #include "builtin.h" #include "submodule.h" +#include "repository.h" static struct rev_info log_tree_opt; static int diff_tree_commit_oid(const struct object_id *oid) { - struct commit *commit = lookup_commit_reference(oid); + struct commit *commit = lookup_commit_reference(the_repository, oid); if (!commit) return -1; return log_tree_commit(&log_tree_opt, commit); @@ -24,7 +25,7 @@ static int stdin_diff_commit(struct commit *commit, const char *p) /* Graft the fake parents locally to the commit */ while (isspace(*p++) && !parse_oid_hex(p, &oid, &p)) { - struct commit *parent = lookup_commit(&oid); + struct commit *parent = lookup_commit(the_repository, &oid); if (!pptr) { /* Free the real parent list */ free_commit_list(commit->parents); @@ -45,7 +46,7 @@ static int stdin_diff_trees(struct tree *tree1, const char *p) struct tree *tree2; if (!isspace(*p++) || parse_oid_hex(p, &oid, &p) || *p) return error("Need exactly two trees, separated by a space"); - tree2 = lookup_tree(&oid); + tree2 = lookup_tree(the_repository, &oid); if (!tree2 || parse_tree(tree2)) return -1; printf("%s %s\n", oid_to_hex(&tree1->object.oid), @@ -68,7 +69,7 @@ static int diff_tree_stdin(char *line) line[len-1] = 0; if (parse_oid_hex(line, &oid, &p)) return -1; - obj = parse_object(&oid); + obj = parse_object(the_repository, &oid); if (!obj) return -1; if (obj->type == OBJ_COMMIT) @@ -162,9 +163,11 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) int saved_nrl = 0; int saved_dcctc = 0; - if (opt->diffopt.detect_rename) - opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE | - DIFF_SETUP_USE_CACHE); + if (opt->diffopt.detect_rename) { + if (!the_index.cache) + read_index(&the_index); + opt->diffopt.setup |= DIFF_SETUP_USE_SIZE_CACHE; + } while (fgets(line, sizeof(line), stdin)) { struct object_id oid; diff --git a/builtin/diff.c b/builtin/diff.c index b709b6e984..361a3c3ed3 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -386,7 +386,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix) add_head_to_pending(&rev); if (!rev.pending.nr) { struct tree *tree; - tree = lookup_tree(the_hash_algo->empty_tree); + tree = lookup_tree(the_repository, + the_repository->hash_algo->empty_tree); add_pending_object(&rev, &tree->object, "HEAD"); } break; @@ -400,8 +401,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix) const char *name = entry->name; int flags = (obj->flags & UNINTERESTING); if (!obj->parsed) - obj = parse_object(&obj->oid); - obj = deref_tag(obj, NULL, 0); + obj = parse_object(the_repository, &obj->oid); + obj = deref_tag(the_repository, obj, NULL, 0); if (!obj) die(_("invalid object '%s' given."), name); if (obj->type == OBJ_COMMIT) diff --git a/builtin/difftool.c b/builtin/difftool.c index bc97d4aef2..cdd585ca76 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -20,6 +20,7 @@ #include "argv-array.h" #include "strbuf.h" #include "lockfile.h" +#include "object-store.h" #include "dir.h" static char *diff_gui_tool; @@ -321,10 +322,10 @@ static int checkout_path(unsigned mode, struct object_id *oid, struct cache_entry *ce; int ret; - ce = make_cache_entry(mode, oid->hash, path, 0, 0); + ce = make_transient_cache_entry(mode, oid, path, 0); ret = checkout_entry(ce, state, NULL); - free(ce); + discard_cache_entry(ce); return ret; } @@ -488,7 +489,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, * index. */ struct cache_entry *ce2 = - make_cache_entry(rmode, roid.hash, + make_cache_entry(&wtindex, rmode, &roid, dst_path, 0, 0); add_index_entry(&wtindex, ce2, @@ -702,7 +703,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix) 1, PARSE_OPT_NONEG | PARSE_OPT_HIDDEN), OPT_BOOL(0, "symlinks", &symlinks, N_("use symlinks in dir-diff mode")), - OPT_STRING('t', "tool", &difftool_cmd, N_("<tool>"), + OPT_STRING('t', "tool", &difftool_cmd, N_("tool"), N_("use the specified diff tool")), OPT_BOOL(0, "tool-help", &tool_help, N_("print a list of diff tools that may be used with " @@ -710,7 +711,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "trust-exit-code", &trust_exit_code, N_("make 'git-difftool' exit when an invoked diff " "tool returns a non - zero exit code")), - OPT_STRING('x', "extcmd", &extcmd, N_("<command>"), + OPT_STRING('x', "extcmd", &extcmd, N_("command"), N_("specify a custom command for viewing diffs")), OPT_END() }; diff --git a/builtin/fast-export.c b/builtin/fast-export.c index 73d12c1020..9bd8a14b57 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -8,6 +8,7 @@ #include "config.h" #include "refs.h" #include "refspec.h" +#include "object-store.h" #include "commit.h" #include "object.h" #include "tag.h" @@ -229,21 +230,22 @@ static void export_blob(const struct object_id *oid) if (is_null_oid(oid)) return; - object = lookup_object(oid->hash); + object = lookup_object(the_repository, oid->hash); if (object && object->flags & SHOWN) return; if (anonymize) { buf = anonymize_blob(&size); - object = (struct object *)lookup_blob(oid); + object = (struct object *)lookup_blob(the_repository, oid); eaten = 0; } else { buf = read_object_file(oid, &type, &size); if (!buf) - die ("Could not read blob %s", oid_to_hex(oid)); + die("could not read blob %s", oid_to_hex(oid)); if (check_object_signature(oid, buf, size, type_name(type)) < 0) die("sha1 mismatch in blob %s", oid_to_hex(oid)); - object = parse_object_buffer(oid, type, size, buf, &eaten); + object = parse_object_buffer(the_repository, oid, type, + size, buf, &eaten); } if (!object) @@ -253,7 +255,7 @@ static void export_blob(const struct object_id *oid) printf("blob\nmark :%"PRIu32"\ndata %lu\n", last_idnum, size); if (size && fwrite(buf, size, 1, stdout) != 1) - die_errno ("Could not write blob '%s'", oid_to_hex(oid)); + die_errno("could not write blob '%s'", oid_to_hex(oid)); printf("\n"); show_progress(); @@ -401,7 +403,8 @@ static void show_filemodify(struct diff_queue_struct *q, anonymize_sha1(&spec->oid) : spec->oid.hash)); else { - struct object *object = lookup_object(spec->oid.hash); + struct object *object = lookup_object(the_repository, + spec->oid.hash); printf("M %06o :%d ", spec->mode, get_object_mark(object)); } @@ -560,14 +563,14 @@ static void handle_commit(struct commit *commit, struct rev_info *rev, commit_buffer = get_commit_buffer(commit, NULL); author = strstr(commit_buffer, "\nauthor "); if (!author) - die ("Could not find author in commit %s", - oid_to_hex(&commit->object.oid)); + die("could not find author in commit %s", + oid_to_hex(&commit->object.oid)); author++; author_end = strchrnul(author, '\n'); committer = strstr(author_end, "\ncommitter "); if (!committer) - die ("Could not find committer in commit %s", - oid_to_hex(&commit->object.oid)); + die("could not find committer in commit %s", + oid_to_hex(&commit->object.oid)); committer++; committer_end = strchrnul(committer, '\n'); message = strstr(committer_end, "\n\n"); @@ -688,7 +691,7 @@ static void handle_tag(const char *name, struct tag *tag) buf = read_object_file(&tag->object.oid, &type, &size); if (!buf) - die ("Could not read tag %s", oid_to_hex(&tag->object.oid)); + die("could not read tag %s", oid_to_hex(&tag->object.oid)); message = memmem(buf, size, "\n\n", 2); if (message) { message += 2; @@ -725,18 +728,18 @@ static void handle_tag(const char *name, struct tag *tag) if (signature) switch(signed_tag_mode) { case ABORT: - die ("Encountered signed tag %s; use " - "--signed-tags=<mode> to handle it.", - oid_to_hex(&tag->object.oid)); + die("encountered signed tag %s; use " + "--signed-tags=<mode> to handle it", + oid_to_hex(&tag->object.oid)); case WARN: - warning ("Exporting signed tag %s", - oid_to_hex(&tag->object.oid)); + warning("exporting signed tag %s", + oid_to_hex(&tag->object.oid)); /* fallthru */ case VERBATIM: break; case WARN_STRIP: - warning ("Stripping signature from tag %s", - oid_to_hex(&tag->object.oid)); + warning("stripping signature from tag %s", + oid_to_hex(&tag->object.oid)); /* fallthru */ case STRIP: message_size = signature + 1 - message; @@ -750,18 +753,18 @@ static void handle_tag(const char *name, struct tag *tag) if (!tagged_mark) { switch(tag_of_filtered_mode) { case ABORT: - die ("Tag %s tags unexported object; use " - "--tag-of-filtered-object=<mode> to handle it.", - oid_to_hex(&tag->object.oid)); + die("tag %s tags unexported object; use " + "--tag-of-filtered-object=<mode> to handle it", + oid_to_hex(&tag->object.oid)); case DROP: /* Ignore this tag altogether */ free(buf); return; case REWRITE: if (tagged->type != OBJ_COMMIT) { - die ("Tag %s tags unexported %s!", - oid_to_hex(&tag->object.oid), - type_name(tagged->type)); + die("tag %s tags unexported %s!", + oid_to_hex(&tag->object.oid), + type_name(tagged->type)); } p = (struct commit *)tagged; for (;;) { @@ -772,7 +775,7 @@ static void handle_tag(const char *name, struct tag *tag) if (!(p->object.flags & TREESAME)) break; if (!p->parents) - die ("Can't find replacement commit for tag %s\n", + die("can't find replacement commit for tag %s", oid_to_hex(&tag->object.oid)); p = p->parents->item; } @@ -800,7 +803,7 @@ static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name) /* handle nested tags */ while (tag && tag->object.type == OBJ_TAG) { - parse_object(&tag->object.oid); + parse_object(the_repository, &tag->object.oid); string_list_append(&extra_refs, full_name)->util = tag; tag = (struct tag *)tag->tagged; } @@ -960,7 +963,7 @@ static void import_marks(char *input_file) /* only commits */ continue; - commit = lookup_commit(&oid); + commit = lookup_commit(the_repository, &oid); if (!commit) die("not a commit? can't happen: %s", oid_to_hex(&oid)); diff --git a/builtin/fetch.c b/builtin/fetch.c index ea5b9669ad..eed15c7813 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -6,6 +6,7 @@ #include "repository.h" #include "refs.h" #include "refspec.h" +#include "object-store.h" #include "commit.h" #include "builtin.h" #include "string-list.h" @@ -21,6 +22,7 @@ #include "utf8.h" #include "packfile.h" #include "list-objects-filter-options.h" +#include "commit-reach.h" static const char * const builtin_fetch_usage[] = { N_("git fetch [<options>] [<repository> [<refspec>...]]"), @@ -63,6 +65,7 @@ static int shown_url = 0; static struct refspec refmap = REFSPEC_INIT_FETCH; static struct list_objects_filter_options filter_options; static struct string_list server_options = STRING_LIST_INIT_DUP; +static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP; static int git_fetch_config(const char *k, const char *v, void *cb) { @@ -93,19 +96,6 @@ static int git_fetch_config(const char *k, const char *v, void *cb) return git_default_config(k, v, cb); } -static int gitmodules_fetch_config(const char *var, const char *value, void *cb) -{ - if (!strcmp(var, "submodule.fetchjobs")) { - max_children = parse_submodule_fetchjobs(var, value); - return 0; - } else if (!strcmp(var, "fetch.recursesubmodules")) { - recurse_submodules = parse_fetch_recurse_submodules_arg(var, value); - return 0; - } - - return 0; -} - static int parse_refmap_arg(const struct option *opt, const char *arg, int unset) { /* @@ -174,6 +164,8 @@ static struct option builtin_fetch_options[] = { TRANSPORT_FAMILY_IPV4), OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"), TRANSPORT_FAMILY_IPV6), + OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"), + N_("report that we have only objects reachable from this object")), OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options), OPT_END() }; @@ -254,9 +246,9 @@ static int will_fetch(struct ref **head, const unsigned char *sha1) return 0; } -static void find_non_local_tags(struct transport *transport, - struct ref **head, - struct ref ***tail) +static void find_non_local_tags(const struct ref *refs, + struct ref **head, + struct ref ***tail) { struct string_list existing_refs = STRING_LIST_INIT_DUP; struct string_list remote_refs = STRING_LIST_INIT_NODUP; @@ -264,7 +256,7 @@ static void find_non_local_tags(struct transport *transport, struct string_list_item *item = NULL; for_each_ref(add_existing, &existing_refs); - for (ref = transport_get_remote_refs(transport, NULL); ref; ref = ref->next) { + for (ref = refs; ref; ref = ref->next) { if (!starts_with(ref->name, "refs/tags/")) continue; @@ -338,7 +330,8 @@ static void find_non_local_tags(struct transport *transport, string_list_clear(&remote_refs, 0); } -static struct ref *get_ref_map(struct transport *transport, +static struct ref *get_ref_map(struct remote *remote, + const struct ref *remote_refs, struct refspec *rs, int tags, int *autotags) { @@ -346,26 +339,11 @@ static struct ref *get_ref_map(struct transport *transport, struct ref *rm; struct ref *ref_map = NULL; struct ref **tail = &ref_map; - struct argv_array ref_prefixes = ARGV_ARRAY_INIT; /* opportunistically-updated references: */ struct ref *orefs = NULL, **oref_tail = &orefs; - const struct ref *remote_refs; - - if (rs->nr) - refspec_ref_prefixes(rs, &ref_prefixes); - else if (transport->remote && transport->remote->fetch.nr) - refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes); - - if (ref_prefixes.argc && - (tags == TAGS_SET || (tags == TAGS_DEFAULT && !rs->nr))) { - argv_array_push(&ref_prefixes, "refs/tags/"); - } - - remote_refs = transport_get_remote_refs(transport, &ref_prefixes); - - argv_array_clear(&ref_prefixes); + struct string_list existing_refs = STRING_LIST_INIT_DUP; if (rs->nr) { struct refspec *fetch_refspec; @@ -402,7 +380,7 @@ static struct ref *get_ref_map(struct transport *transport, if (refmap.nr) fetch_refspec = &refmap; else - fetch_refspec = &transport->remote->fetch; + fetch_refspec = &remote->fetch; for (i = 0; i < fetch_refspec->nr; i++) get_fetch_map(ref_map, &fetch_refspec->items[i], &oref_tail, 1); @@ -410,7 +388,6 @@ static struct ref *get_ref_map(struct transport *transport, die("--refmap option is only meaningful with command-line refspec(s)."); } else { /* Use the defaults */ - struct remote *remote = transport->remote; struct branch *branch = branch_get(NULL); int has_merge = branch_has_merge_config(branch); if (remote && @@ -449,7 +426,7 @@ static struct ref *get_ref_map(struct transport *transport, /* also fetch all tags */ get_fetch_map(remote_refs, tag_refspec, &tail, 0); else if (tags == TAGS_DEFAULT && *autotags) - find_non_local_tags(transport, &ref_map, &tail); + find_non_local_tags(remote_refs, &ref_map, &tail); /* Now append any refs to be updated opportunistically: */ *tail = orefs; @@ -458,7 +435,23 @@ static struct ref *get_ref_map(struct transport *transport, tail = &rm->next; } - return ref_remove_duplicates(ref_map); + ref_map = ref_remove_duplicates(ref_map); + + for_each_ref(add_existing, &existing_refs); + for (rm = ref_map; rm; rm = rm->next) { + if (rm->peer_ref) { + struct string_list_item *peer_item = + string_list_lookup(&existing_refs, + rm->peer_ref->name); + if (peer_item) { + struct object_id *old_oid = peer_item->util; + oidcpy(&rm->peer_ref->old_oid, old_oid); + } + } + } + string_list_clear(&existing_refs, 1); + + return ref_map; } #define STORE_REF_ERROR_OTHER 1 @@ -683,8 +676,10 @@ static int update_local_ref(struct ref *ref, return r; } - current = lookup_commit_reference_gently(&ref->old_oid, 1); - updated = lookup_commit_reference_gently(&ref->new_oid, 1); + current = lookup_commit_reference_gently(the_repository, + &ref->old_oid, 1); + updated = lookup_commit_reference_gently(the_repository, + &ref->new_oid, 1); if (!current || !updated) { const char *msg; const char *what; @@ -768,7 +763,7 @@ static int iterate_ref_map(void *cb_data, struct object_id *oid) } static int store_updated_refs(const char *raw_url, const char *remote_name, - struct ref *ref_map) + int connectivity_checked, struct ref *ref_map) { FILE *fp; struct commit *commit; @@ -777,7 +772,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name, const char *what, *kind; struct ref *rm; char *url; - const char *filename = dry_run ? "/dev/null" : git_path_fetch_head(); + const char *filename = dry_run ? "/dev/null" : git_path_fetch_head(the_repository); int want_status; int summary_width = transport_summary_width(ref_map); @@ -790,10 +785,12 @@ static int store_updated_refs(const char *raw_url, const char *remote_name, else url = xstrdup("foreign"); - rm = ref_map; - if (check_connected(iterate_ref_map, &rm, NULL)) { - rc = error(_("%s did not send all necessary objects\n"), url); - goto abort; + if (!connectivity_checked) { + rm = ref_map; + if (check_connected(iterate_ref_map, &rm, NULL)) { + rc = error(_("%s did not send all necessary objects\n"), url); + goto abort; + } } prepare_format_display(ref_map); @@ -817,7 +814,8 @@ static int store_updated_refs(const char *raw_url, const char *remote_name, continue; } - commit = lookup_commit_reference_gently(&rm->old_oid, + commit = lookup_commit_reference_gently(the_repository, + &rm->old_oid, 1); if (!commit) rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE; @@ -951,9 +949,24 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map) if (ret) ret = transport_fetch_refs(transport, ref_map); if (!ret) - ret |= store_updated_refs(transport->url, - transport->remote->name, - ref_map); + /* + * Keep the new pack's ".keep" file around to allow the caller + * time to update refs to reference the new objects. + */ + return 0; + transport_unlock_pack(transport); + return ret; +} + +/* Update local refs based on the ref values fetched from a remote */ +static int consume_refs(struct transport *transport, struct ref *ref_map) +{ + int connectivity_checked = transport->smart_options + ? transport->smart_options->connectivity_checked : 0; + int ret = store_updated_refs(transport->url, + transport->remote->name, + connectivity_checked, + ref_map); transport_unlock_pack(transport); return ret; } @@ -1029,7 +1042,7 @@ static void check_not_current_branch(struct ref *ref_map) static int truncate_fetch_head(void) { - const char *filename = git_path_fetch_head(); + const char *filename = git_path_fetch_head(the_repository); FILE *fp = fopen_for_writing(filename); if (!fp) @@ -1049,6 +1062,40 @@ static void set_option(struct transport *transport, const char *name, const char name, transport->url); } + +static int add_oid(const char *refname, const struct object_id *oid, int flags, + void *cb_data) +{ + struct oid_array *oids = cb_data; + + oid_array_append(oids, oid); + return 0; +} + +static void add_negotiation_tips(struct git_transport_options *smart_options) +{ + struct oid_array *oids = xcalloc(1, sizeof(*oids)); + int i; + + for (i = 0; i < negotiation_tip.nr; i++) { + const char *s = negotiation_tip.items[i].string; + int old_nr; + if (!has_glob_specials(s)) { + struct object_id oid; + if (get_oid(s, &oid)) + die("%s is not a valid object", s); + oid_array_append(oids, &oid); + continue; + } + old_nr = oids->nr; + for_each_glob_ref(add_oid, s, oids); + if (old_nr == oids->nr) + warning("Ignoring --negotiation-tip=%s because it does not match any refs", + s); + } + smart_options->negotiation_tips = oids; +} + static struct transport *prepare_transport(struct remote *remote, int deepen) { struct transport *transport; @@ -1075,6 +1122,12 @@ static struct transport *prepare_transport(struct remote *remote, int deepen) filter_options.filter_spec); set_option(transport, TRANS_OPT_FROM_PROMISOR, "1"); } + if (negotiation_tip.nr) { + if (transport->smart_options) + add_negotiation_tips(transport->smart_options); + else + warning("Ignoring --negotiation-tip because the protocol does not support it."); + } return transport; } @@ -1099,7 +1152,8 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map) transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL); transport_set_option(transport, TRANS_OPT_DEPTH, "0"); transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL); - fetch_refs(transport, ref_map); + if (!fetch_refs(transport, ref_map)) + consume_refs(transport, ref_map); if (gsecondary) { transport_disconnect(gsecondary); @@ -1110,13 +1164,11 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map) static int do_fetch(struct transport *transport, struct refspec *rs) { - struct string_list existing_refs = STRING_LIST_INIT_DUP; struct ref *ref_map; - struct ref *rm; int autotags = (transport->remote->fetch_tags == 1); int retcode = 0; - - for_each_ref(add_existing, &existing_refs); + const struct ref *remote_refs; + struct argv_array ref_prefixes = ARGV_ARRAY_INIT; if (tags == TAGS_DEFAULT) { if (transport->remote->fetch_tags == 2) @@ -1132,22 +1184,24 @@ static int do_fetch(struct transport *transport, goto cleanup; } - ref_map = get_ref_map(transport, rs, tags, &autotags); - if (!update_head_ok) - check_not_current_branch(ref_map); + if (rs->nr) + refspec_ref_prefixes(rs, &ref_prefixes); + else if (transport->remote && transport->remote->fetch.nr) + refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes); - for (rm = ref_map; rm; rm = rm->next) { - if (rm->peer_ref) { - struct string_list_item *peer_item = - string_list_lookup(&existing_refs, - rm->peer_ref->name); - if (peer_item) { - struct object_id *old_oid = peer_item->util; - oidcpy(&rm->peer_ref->old_oid, old_oid); - } - } + if (ref_prefixes.argc && + (tags == TAGS_SET || (tags == TAGS_DEFAULT))) { + argv_array_push(&ref_prefixes, "refs/tags/"); } + remote_refs = transport_get_remote_refs(transport, &ref_prefixes); + argv_array_clear(&ref_prefixes); + + ref_map = get_ref_map(transport->remote, remote_refs, rs, + tags, &autotags); + if (!update_head_ok) + check_not_current_branch(ref_map); + if (tags == TAGS_DEFAULT && autotags) transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1"); if (prune) { @@ -1164,7 +1218,7 @@ static int do_fetch(struct transport *transport, transport->url); } } - if (fetch_refs(transport, ref_map)) { + if (fetch_refs(transport, ref_map) || consume_refs(transport, ref_map)) { free_refs(ref_map); retcode = 1; goto cleanup; @@ -1176,14 +1230,13 @@ static int do_fetch(struct transport *transport, if (tags == TAGS_DEFAULT && autotags) { struct ref **tail = &ref_map; ref_map = NULL; - find_non_local_tags(transport, &ref_map, &tail); + find_non_local_tags(remote_refs, &ref_map, &tail); if (ref_map) backfill_tags(transport, ref_map); free_refs(ref_map); } cleanup: - string_list_clear(&existing_refs, 1); return retcode; } @@ -1433,7 +1486,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) for (i = 1; i < argc; i++) strbuf_addf(&default_rla, " %s", argv[i]); - config_from_gitmodules(gitmodules_fetch_config, NULL); + fetch_config_from_gitmodules(&max_children, &recurse_submodules); git_config(git_fetch_config, NULL); argc = parse_options(argc, argv, prefix, @@ -1449,7 +1502,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) if (unshallow) { if (depth) die(_("--depth and --unshallow cannot be used together")); - else if (!is_repository_shallow()) + else if (!is_repository_shallow(the_repository)) die(_("--unshallow on a complete repository does not make sense")); else depth = xstrfmt("%d", INFINITE_DEPTH); diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index bd680be687..e5668f27d8 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -2,6 +2,7 @@ #include "cache.h" #include "config.h" #include "refs.h" +#include "object-store.h" #include "commit.h" #include "diff.h" #include "revision.h" @@ -10,6 +11,8 @@ #include "branch.h" #include "fmt-merge-msg.h" #include "gpg-interface.h" +#include "repository.h" +#include "commit-reach.h" static const char * const fmt_merge_msg_usage[] = { N_("git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"), @@ -108,14 +111,15 @@ static int handle_line(char *line, struct merge_parents *merge_parents) struct string_list_item *item; int pulling_head = 0; struct object_id oid; + const unsigned hexsz = the_hash_algo->hexsz; - if (len < GIT_SHA1_HEXSZ + 3 || line[GIT_SHA1_HEXSZ] != '\t') + if (len < hexsz + 3 || line[hexsz] != '\t') return 1; - if (starts_with(line + GIT_SHA1_HEXSZ + 1, "not-for-merge")) + if (starts_with(line + hexsz + 1, "not-for-merge")) return 0; - if (line[GIT_SHA1_HEXSZ + 1] != '\t') + if (line[hexsz + 1] != '\t') return 2; i = get_oid_hex(line, &oid); @@ -130,7 +134,7 @@ static int handle_line(char *line, struct merge_parents *merge_parents) if (line[len - 1] == '\n') line[len - 1] = 0; - line += GIT_SHA1_HEXSZ + 2; + line += hexsz + 2; /* * At this point, line points at the beginning of comment e.g. @@ -342,7 +346,9 @@ static void shortlog(const char *name, const struct object_id *oid = &origin_data->oid; int limit = opts->shortlog_len; - branch = deref_tag(parse_object(oid), oid_to_hex(oid), GIT_SHA1_HEXSZ); + branch = deref_tag(the_repository, parse_object(the_repository, oid), + oid_to_hex(oid), + the_hash_algo->hexsz); if (!branch || branch->type != OBJ_COMMIT) return; @@ -545,6 +551,7 @@ static void find_merge_parents(struct merge_parents *result, int len; char *p = in->buf + pos; char *newline = strchr(p, '\n'); + const char *q; struct object_id oid; struct commit *parent; struct object *obj; @@ -552,24 +559,23 @@ static void find_merge_parents(struct merge_parents *result, len = newline ? newline - p : strlen(p); pos += len + !!newline; - if (len < GIT_SHA1_HEXSZ + 3 || - get_oid_hex(p, &oid) || - p[GIT_SHA1_HEXSZ] != '\t' || - p[GIT_SHA1_HEXSZ + 1] != '\t') + if (parse_oid_hex(p, &oid, &q) || + q[0] != '\t' || + q[1] != '\t') continue; /* skip not-for-merge */ /* * Do not use get_merge_parent() here; we do not have * "name" here and we do not want to contaminate its * util field yet. */ - obj = parse_object(&oid); + obj = parse_object(the_repository, &oid); parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT); if (!parent) continue; commit_list_insert(parent, &parents); add_merge_parent(result, &obj->oid, &parent->object.oid); } - head_commit = lookup_commit(head); + head_commit = lookup_commit(the_repository, head); if (head_commit) commit_list_insert(head_commit, &parents); reduce_heads_replace(&parents); @@ -623,7 +629,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out, i++; p[len] = 0; if (handle_line(p, &merge_parents)) - die ("Error in line %d: %.*s", i, len, p); + die("error in line %d: %.*s", i, len, p); } if (opts->add_title && srcs.nr) diff --git a/builtin/fsck.c b/builtin/fsck.c index 3ad4f160f9..63c8578cc1 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -18,6 +18,7 @@ #include "decorate.h" #include "packfile.h" #include "object-store.h" +#include "run-command.h" #define REACHABLE 0x0001 #define SEEN 0x0002 @@ -47,6 +48,7 @@ static int name_objects; #define ERROR_REACHABLE 02 #define ERROR_PACK 04 #define ERROR_REFS 010 +#define ERROR_COMMIT_GRAPH 020 static const char *describe_object(struct object *obj) { @@ -70,7 +72,7 @@ static const char *printable_type(struct object *obj) enum object_type type = oid_object_info(the_repository, &obj->oid, NULL); if (type > 0) - object_as_type(obj, type, 0); + object_as_type(the_repository, obj, type, 0); } ret = type_name(obj->type); @@ -392,7 +394,8 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type, * verify_packfile(), data_valid variable for details. */ struct object *obj; - obj = parse_object_buffer(oid, type, size, buffer, eaten); + obj = parse_object_buffer(the_repository, oid, type, size, buffer, + eaten); if (!obj) { errors_found |= ERROR_OBJECT; return error("%s: object corrupt or missing", oid_to_hex(oid)); @@ -410,7 +413,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid, struct object *obj; if (!is_null_oid(oid)) { - obj = lookup_object(oid->hash); + obj = lookup_object(the_repository, oid->hash); if (obj && (obj->flags & HAS_OBJ)) { if (timestamp && name_objects) add_decoration(fsck_walk_options.object_names, @@ -452,7 +455,7 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid, { struct object *obj; - obj = parse_object(oid); + obj = parse_object(the_repository, oid); if (!obj) { if (is_promisor_object(oid)) { /* @@ -525,7 +528,9 @@ static int fsck_loose(const struct object_id *oid, const char *path, void *data) if (!contents && type != OBJ_BLOB) BUG("read_loose_object streamed a non-blob"); - obj = parse_object_buffer(oid, type, size, contents, &eaten); + obj = parse_object_buffer(the_repository, oid, type, size, + contents, &eaten); + if (!obj) { errors_found |= ERROR_OBJECT; error("%s: object could not be parsed: %s", @@ -614,7 +619,7 @@ static int fsck_cache_tree(struct cache_tree *it) fprintf(stderr, "Checking cache tree\n"); if (0 <= it->entry_count) { - struct object *obj = parse_object(&it->oid); + struct object *obj = parse_object(the_repository, &it->oid); if (!obj) { error("%s: invalid sha1 pointer in cache-tree", oid_to_hex(&it->oid)); @@ -689,7 +694,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) fetch_if_missing = 0; errors_found = 0; - check_replace_refs = 0; + read_replace_refs = 0; argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0); @@ -735,7 +740,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) struct progress *progress = NULL; if (show_progress) { - for (p = get_packed_git(the_repository); p; + for (p = get_all_packs(the_repository); p; p = p->next) { if (open_pack_index(p)) continue; @@ -744,7 +749,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) progress = start_progress(_("Checking objects"), total); } - for (p = get_packed_git(the_repository); p; + for (p = get_all_packs(the_repository); p; p = p->next) { /* verify gives error messages itself */ if (verify_pack(p, fsck_obj_buffer, @@ -763,7 +768,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) const char *arg = argv[i]; struct object_id oid; if (!get_oid(arg, &oid)) { - struct object *obj = lookup_object(oid.hash); + struct object *obj = lookup_object(the_repository, + oid.hash); if (!obj || !(obj->flags & HAS_OBJ)) { if (is_promisor_object(&oid)) @@ -806,7 +812,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) mode = active_cache[i]->ce_mode; if (S_ISGITLINK(mode)) continue; - blob = lookup_blob(&active_cache[i]->oid); + blob = lookup_blob(the_repository, + &active_cache[i]->oid); if (!blob) continue; obj = &blob->object; @@ -822,5 +829,24 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) } check_connectivity(); + + if (!git_config_get_bool("core.commitgraph", &i) && i) { + struct child_process commit_graph_verify = CHILD_PROCESS_INIT; + const char *verify_argv[] = { "commit-graph", "verify", NULL, NULL, NULL }; + + commit_graph_verify.argv = verify_argv; + commit_graph_verify.git_cmd = 1; + if (run_command(&commit_graph_verify)) + errors_found |= ERROR_COMMIT_GRAPH; + + prepare_alt_odb(the_repository); + for (alt = the_repository->objects->alt_odb_list; alt; alt = alt->next) { + verify_argv[2] = "--object-dir"; + verify_argv[3] = alt->path; + if (run_command(&commit_graph_verify)) + errors_found |= ERROR_COMMIT_GRAPH; + } + } + return errors_found; } diff --git a/builtin/gc.c b/builtin/gc.c index ccfb1ceaeb..2b592260e9 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -20,6 +20,7 @@ #include "sigchain.h" #include "argv-array.h" #include "commit.h" +#include "commit-graph.h" #include "packfile.h" #include "object-store.h" #include "pack.h" @@ -40,6 +41,7 @@ static int aggressive_depth = 50; static int aggressive_window = 250; static int gc_auto_threshold = 6700; static int gc_auto_pack_limit = 50; +static int gc_write_commit_graph; static int detach_auto = 1; static timestamp_t gc_log_expire_time; static const char *gc_log_expire = "1.day.ago"; @@ -129,6 +131,7 @@ static void gc_config(void) git_config_get_int("gc.aggressivedepth", &aggressive_depth); git_config_get_int("gc.auto", &gc_auto_threshold); git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit); + git_config_get_bool("gc.writecommitgraph", &gc_write_commit_graph); git_config_get_bool("gc.autodetach", &detach_auto); git_config_get_expiry("gc.pruneexpire", &prune_expire); git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire); @@ -180,7 +183,7 @@ static struct packed_git *find_base_packs(struct string_list *packs, { struct packed_git *p, *base = NULL; - for (p = get_packed_git(the_repository); p; p = p->next) { + for (p = get_all_packs(the_repository); p; p = p->next) { if (!p->pack_local) continue; if (limit) { @@ -205,7 +208,7 @@ static int too_many_packs(void) if (gc_auto_pack_limit <= 0) return 0; - for (cnt = 0, p = get_packed_git(the_repository); p; p = p->next) { + for (cnt = 0, p = get_all_packs(the_repository); p; p = p->next) { if (!p->pack_local) continue; if (p->pack_keep) @@ -612,6 +615,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix) return -1; if (!repository_format_precious_objects) { + close_all_packs(the_repository->objects); if (run_command_v_opt(repack.argv, RUN_GIT_CMD)) return error(FAILED_RUN, repack.argv[0]); @@ -641,6 +645,9 @@ int cmd_gc(int argc, const char **argv, const char *prefix) if (pack_garbage.nr > 0) clean_pack_garbage(); + if (gc_write_commit_graph) + write_commit_graph_reachable(get_object_directory(), 0); + if (auto_gc && too_many_loose_objects()) warning(_("There are too many unreachable loose objects; " "run 'git prune' to remove them.")); diff --git a/builtin/grep.c b/builtin/grep.c index ee753a403e..601f801158 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -489,7 +489,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo, } if (repo_read_index(repo) < 0) - die("index file corrupt"); + die(_("index file corrupt")); for (nr = 0; nr < repo->index->cache_nr; nr++) { const struct cache_entry *ce = repo->index->cache[nr]; @@ -497,7 +497,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo, strbuf_addstr(&name, ce->name); if (S_ISREG(ce->ce_mode) && - match_pathspec(pathspec, name.buf, name.len, 0, NULL, + match_pathspec(repo->index, pathspec, name.buf, name.len, 0, NULL, S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode))) { /* @@ -515,7 +515,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo, hit |= grep_file(opt, name.buf); } } else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) && - submodule_path_match(pathspec, name.buf, NULL)) { + submodule_path_match(repo->index, pathspec, name.buf, NULL)) { hit |= grep_submodule(opt, repo, pathspec, NULL, ce->name, ce->name); } else { continue; @@ -647,7 +647,8 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, for (i = 0; i < nr; i++) { struct object *real_obj; - real_obj = deref_tag(list->objects[i].item, NULL, 0); + real_obj = deref_tag(the_repository, list->objects[i].item, + NULL, 0); /* load the gitmodules file for this rev */ if (recurse_submodules) { @@ -678,7 +679,7 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec, fill_directory(&dir, &the_index, pathspec); for (i = 0; i < dir.nr; i++) { - if (!dir_path_match(dir.entries[i], pathspec, 0, NULL)) + if (!dir_path_match(&the_index, dir.entries[i], pathspec, 0, NULL)) continue; hit |= grep_file(opt, dir.entries[i]->name); if (hit && opt->status_only) @@ -828,6 +829,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) GREP_PATTERN_TYPE_PCRE), OPT_GROUP(""), OPT_BOOL('n', "line-number", &opt.linenum, N_("show line numbers")), + OPT_BOOL(0, "column", &opt.columnnum, N_("show column number of first match")), OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1), OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1), OPT_NEGBIT(0, "full-name", &opt.relative, @@ -842,6 +844,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOL_F('z', "null", &opt.null_following_name, N_("print NUL after filenames"), PARSE_OPT_NOCOMPLETE), + OPT_BOOL('o', "only-matching", &opt.only_matching, + N_("show only matching parts of a line")), OPT_BOOL('c', "count", &opt.count, N_("show the number of matches instead of matching lines")), OPT__COLOR(&opt.color, N_("highlight matches")), @@ -959,7 +963,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (!opt.pattern_list) - die(_("no pattern given.")); + die(_("no pattern given")); + + /* --only-matching has no effect with --invert. */ + if (opt.invert) + opt.only_matching = 0; /* * We have to find "--" in a separate pass, because its presence @@ -1085,19 +1093,19 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (recurse_submodules && (!use_index || untracked)) - die(_("option not supported with --recurse-submodules.")); + die(_("option not supported with --recurse-submodules")); if (!show_in_pager && !opt.status_only) setup_pager(); if (!use_index && (untracked || cached)) - die(_("--cached or --untracked cannot be used with --no-index.")); + die(_("--cached or --untracked cannot be used with --no-index")); if (!use_index || untracked) { int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude; hit = grep_directory(&opt, &pathspec, use_exclude, use_index); } else if (0 <= opt_exclude) { - die(_("--[no-]exclude-standard cannot be used for tracked contents.")); + die(_("--[no-]exclude-standard cannot be used for tracked contents")); } else if (!list.nr) { if (!cached) setup_work_tree(); @@ -1105,7 +1113,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) hit = grep_cache(&opt, the_repository, &pathspec, cached); } else { if (cached) - die(_("both --cached and trees are given.")); + die(_("both --cached and trees are given")); hit = grep_objects(&opt, &pathspec, &list); } diff --git a/builtin/hash-object.c b/builtin/hash-object.c index a9a3a198c3..9ada4f4dfd 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -6,6 +6,7 @@ */ #include "builtin.h" #include "config.h" +#include "object-store.h" #include "blob.h" #include "quote.h" #include "parse-options.h" diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 74fe2973e1..9582ead950 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -832,7 +832,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, if (strict || do_fsck_object) { read_lock(); if (type == OBJ_BLOB) { - struct blob *blob = lookup_blob(oid); + struct blob *blob = lookup_blob(the_repository, oid); if (blob) blob->object.flags |= FLAG_CHECKED; else @@ -851,7 +851,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, * we do not need to free the memory here, as the * buf is deleted by the caller. */ - obj = parse_object_buffer(oid, type, size, buf, + obj = parse_object_buffer(the_repository, oid, type, + size, buf, &eaten); if (!obj) die(_("invalid %s"), type_name(type)); @@ -1679,7 +1680,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) if (argc == 2 && !strcmp(argv[1], "-h")) usage(index_pack_usage); - check_replace_refs = 0; + read_replace_refs = 0; fsck_options.walk = mark_link; reset_pack_idx_option(&opts); diff --git a/builtin/init-db.c b/builtin/init-db.c index 4ecf909368..12ddda7e7b 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -73,7 +73,8 @@ static void copy_templates_1(struct strbuf *path, struct strbuf *template_path, continue; else if (S_ISLNK(st_template.st_mode)) { struct strbuf lnk = STRBUF_INIT; - if (strbuf_readlink(&lnk, template_path->buf, 0) < 0) + if (strbuf_readlink(&lnk, template_path->buf, + st_template.st_size) < 0) die_errno(_("cannot readlink '%s'"), template_path->buf); if (symlink(lnk.buf, path->buf)) die_errno(_("cannot symlink '%s' '%s'"), diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c index b742539d4d..4b87e0dd2e 100644 --- a/builtin/interpret-trailers.c +++ b/builtin/interpret-trailers.c @@ -104,6 +104,7 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "unfold", &opts.unfold, N_("join whitespace-continued values")), { OPTION_CALLBACK, 0, "parse", &opts, NULL, N_("set parsing options"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, parse_opt_parse }, + OPT_BOOL(0, "no-divider", &opts.no_divider, N_("do not treat --- specially")), OPT_CALLBACK(0, "trailer", &trailers, N_("trailer"), N_("trailer(s) to add"), option_parse_trailer), OPT_END() diff --git a/builtin/log.c b/builtin/log.c index 0583f7f383..f09a5789f8 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -7,6 +7,7 @@ #include "cache.h" #include "config.h" #include "refs.h" +#include "object-store.h" #include "color.h" #include "commit.h" #include "diff.h" @@ -29,6 +30,10 @@ #include "gpg-interface.h" #include "progress.h" #include "commit-slab.h" +#include "repository.h" +#include "commit-reach.h" +#include "interdiff.h" +#include "range-diff.h" #define MAIL_DEFAULT_WRAP 72 @@ -618,7 +623,7 @@ int cmd_show(int argc, const char **argv, const char *prefix) rev.shown_one = 1; if (ret) break; - o = parse_object(&t->tagged->oid); + o = parse_object(the_repository, &t->tagged->oid); if (!o) ret = error(_("Could not read object %s"), oid_to_hex(&t->tagged->oid)); @@ -905,8 +910,8 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids) o2 = rev->pending.objects[1].item; flags1 = o1->flags; flags2 = o2->flags; - c1 = lookup_commit_reference(&o1->oid); - c2 = lookup_commit_reference(&o2->oid); + c1 = lookup_commit_reference(the_repository, &o1->oid); + c2 = lookup_commit_reference(the_repository, &o2->oid); if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING)) die(_("Not a range.")); @@ -996,6 +1001,26 @@ static char *find_branch_name(struct rev_info *rev) return branch; } +static void show_diffstat(struct rev_info *rev, + struct commit *origin, struct commit *head) +{ + struct diff_options opts; + + memcpy(&opts, &rev->diffopt, sizeof(opts)); + opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; + opts.stat_width = MAIL_DEFAULT_WRAP; + + diff_setup_done(&opts); + + diff_tree_oid(get_commit_tree_oid(origin), + get_commit_tree_oid(head), + "", &opts); + diffcore_std(&opts); + diff_flush(&opts); + + fprintf(rev->diffopt.file, "\n"); +} + static void make_cover_letter(struct rev_info *rev, int use_stdout, struct commit *origin, int nr, struct commit **list, @@ -1009,7 +1034,6 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, struct strbuf sb = STRBUF_INIT; int i; const char *encoding = "UTF-8"; - struct diff_options opts; int need_8bit_cte = 0; struct pretty_print_context pp = {0}; struct commit *head = list[0]; @@ -1059,25 +1083,20 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, shortlog_output(&log); - /* - * We can only do diffstat with a unique reference point - */ - if (!origin) - return; - - memcpy(&opts, &rev->diffopt, sizeof(opts)); - opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; - opts.stat_width = MAIL_DEFAULT_WRAP; - - diff_setup_done(&opts); + /* We can only do diffstat with a unique reference point */ + if (origin) + show_diffstat(rev, origin, head); - diff_tree_oid(get_commit_tree_oid(origin), - get_commit_tree_oid(head), - "", &opts); - diffcore_std(&opts); - diff_flush(&opts); + if (rev->idiff_oid1) { + fprintf_ln(rev->diffopt.file, "%s", rev->idiff_title); + show_interdiff(rev, 0); + } - fprintf(rev->diffopt.file, "\n"); + if (rev->rdiff1) { + fprintf_ln(rev->diffopt.file, "%s", rev->rdiff_title); + show_range_diff(rev->rdiff1, rev->rdiff2, + rev->creation_factor, 1, &rev->diffopt); + } } static const char *clean_message_id(const char *msg_id) @@ -1417,6 +1436,36 @@ static void print_bases(struct base_tree_info *bases, FILE *file) oidclr(&bases->base_commit); } +static const char *diff_title(struct strbuf *sb, int reroll_count, + const char *generic, const char *rerolled) +{ + if (reroll_count <= 0) + strbuf_addstr(sb, generic); + else /* RFC may be v0, so allow -v1 to diff against v0 */ + strbuf_addf(sb, rerolled, reroll_count - 1); + return sb->buf; +} + +static void infer_range_diff_ranges(struct strbuf *r1, + struct strbuf *r2, + const char *prev, + struct commit *origin, + struct commit *head) +{ + const char *head_oid = oid_to_hex(&head->object.oid); + + if (!strstr(prev, "..")) { + strbuf_addf(r1, "%s..%s", head_oid, prev); + strbuf_addf(r2, "%s..%s", prev, head_oid); + } else if (!origin) { + die(_("failed to infer range-diff ranges")); + } else { + strbuf_addstr(r1, prev); + strbuf_addf(r2, "%s..%s", + oid_to_hex(&origin->object.oid), head_oid); + } +} + int cmd_format_patch(int argc, const char **argv, const char *prefix) { struct commit *commit; @@ -1444,6 +1493,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) struct base_tree_info bases; int show_progress = 0; struct progress *progress = NULL; + struct oid_array idiff_prev = OID_ARRAY_INIT; + struct strbuf idiff_title = STRBUF_INIT; + const char *rdiff_prev = NULL; + struct strbuf rdiff1 = STRBUF_INIT; + struct strbuf rdiff2 = STRBUF_INIT; + struct strbuf rdiff_title = STRBUF_INIT; + int creation_factor = -1; const struct option builtin_format_patch_options[] = { { OPTION_CALLBACK, 'n', "numbered", &numbered, NULL, @@ -1517,6 +1573,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) OPT__QUIET(&quiet, N_("don't print the patch filenames")), OPT_BOOL(0, "progress", &show_progress, N_("show progress while generating patches")), + OPT_CALLBACK(0, "interdiff", &idiff_prev, N_("rev"), + N_("show changes against <rev> in cover letter or single patch"), + parse_opt_object_name), + OPT_STRING(0, "range-diff", &rdiff_prev, N_("refspec"), + N_("show changes against <refspec> in cover letter or single patch")), + OPT_INTEGER(0, "creation-factor", &creation_factor, + N_("percentage by which creation is weighted")), OPT_END() }; @@ -1606,14 +1669,14 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) numbered = 0; if (numbered && keep_subject) - die (_("-n and -k are mutually exclusive.")); + die(_("-n and -k are mutually exclusive")); if (keep_subject && subject_prefix) - die (_("--subject-prefix/--rfc and -k are mutually exclusive.")); + die(_("--subject-prefix/--rfc and -k are mutually exclusive")); rev.preserve_subject = keep_subject; argc = setup_revisions(argc, argv, &rev, &s_r_opt); if (argc > 1) - die (_("unrecognized argument: %s"), argv[1]); + die(_("unrecognized argument: %s"), argv[1]); if (rev.diffopt.output_format & DIFF_FORMAT_NAME) die(_("--name-only does not make sense")); @@ -1702,7 +1765,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (rev.pending.nr == 2) { struct object_array_entry *o = rev.pending.objects; if (oidcmp(&o[0].item->oid, &o[1].item->oid) == 0) - return 0; + goto done; } get_patch_ids(&rev, &ids); } @@ -1726,7 +1789,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } if (nr == 0) /* nothing to do */ - return 0; + goto done; total = nr; if (cover_letter == -1) { if (config_cover_letter == COVER_AUTO) @@ -1739,6 +1802,35 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (numbered) rev.total = total + start_number - 1; + if (idiff_prev.nr) { + if (!cover_letter && total != 1) + die(_("--interdiff requires --cover-letter or single patch")); + rev.idiff_oid1 = &idiff_prev.oid[idiff_prev.nr - 1]; + rev.idiff_oid2 = get_commit_tree_oid(list[0]); + rev.idiff_title = diff_title(&idiff_title, reroll_count, + _("Interdiff:"), + _("Interdiff against v%d:")); + } + + if (creation_factor < 0) + creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT; + else if (!rdiff_prev) + die(_("--creation-factor requires --range-diff")); + + if (rdiff_prev) { + if (!cover_letter && total != 1) + die(_("--range-diff requires --cover-letter or single patch")); + + infer_range_diff_ranges(&rdiff1, &rdiff2, rdiff_prev, + origin, list[0]); + rev.rdiff1 = rdiff1.buf; + rev.rdiff2 = rdiff2.buf; + rev.creation_factor = creation_factor; + rev.rdiff_title = diff_title(&rdiff_title, reroll_count, + _("Range-diff:"), + _("Range-diff against v%d:")); + } + if (!signature) { ; /* --no-signature inhibits all signatures */ } else if (signature && signature != git_version_string) { @@ -1755,6 +1847,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (base_commit || base_auto) { struct commit *base = get_base_commit(base_commit, list, nr); reset_revision_walk(); + clear_object_flags(UNINTERESTING); prepare_bases(&bases, base, list, nr); } @@ -1775,6 +1868,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) print_signature(rev.diffopt.file); total++; start_number--; + /* interdiff/range-diff in cover-letter; omit from patches */ + rev.idiff_oid1 = NULL; + rev.rdiff1 = NULL; } rev.add_signoff = do_signoff; @@ -1855,6 +1951,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) string_list_clear(&extra_hdr, 0); if (ignore_if_in_upstream) free_patch_ids(&ids); + +done: + oid_array_clear(&idiff_prev); + strbuf_release(&idiff_title); + strbuf_release(&rdiff1); + strbuf_release(&rdiff2); + strbuf_release(&rdiff_title); return 0; } @@ -1862,7 +1965,8 @@ static int add_pending_commit(const char *arg, struct rev_info *revs, int flags) { struct object_id oid; if (get_oid(arg, &oid) == 0) { - struct commit *commit = lookup_commit_reference(&oid); + struct commit *commit = lookup_commit_reference(the_repository, + &oid); if (commit) { commit->object.flags |= flags; add_pending_object(revs, &commit->object, arg); diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 88bb2019ad..7f9919a362 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -63,7 +63,7 @@ static void write_eolinfo(const struct index_state *istate, struct stat st; const char *i_txt = ""; const char *w_txt = ""; - const char *a_txt = get_convert_attr_ascii(path); + const char *a_txt = get_convert_attr_ascii(istate, path); if (ce && S_ISREG(ce->ce_mode)) i_txt = get_cached_convert_stats_ascii(istate, ce->name); @@ -121,18 +121,19 @@ static void print_debug(const struct cache_entry *ce) } } -static void show_dir_entry(const char *tag, struct dir_entry *ent) +static void show_dir_entry(const struct index_state *istate, + const char *tag, struct dir_entry *ent) { int len = max_prefix_len; if (len > ent->len) die("git ls-files: internal error - directory entry not superset of prefix"); - if (!dir_path_match(ent, &pathspec, len, ps_matched)) + if (!dir_path_match(istate, ent, &pathspec, len, ps_matched)) return; fputs(tag, stdout); - write_eolinfo(NULL, NULL, ent->name); + write_eolinfo(istate, NULL, ent->name); write_name(ent->name); } @@ -145,7 +146,7 @@ static void show_other_files(const struct index_state *istate, struct dir_entry *ent = dir->entries[i]; if (!index_name_is_other(istate, ent->name, ent->len)) continue; - show_dir_entry(tag_other, ent); + show_dir_entry(istate, tag_other, ent); } } @@ -196,7 +197,7 @@ static void show_killed_files(const struct index_state *istate, } } if (killed) - show_dir_entry(tag_killed, dir->entries[i]); + show_dir_entry(istate, tag_killed, dir->entries[i]); } } @@ -228,7 +229,7 @@ static void show_ce(struct repository *repo, struct dir_struct *dir, if (recurse_submodules && S_ISGITLINK(ce->ce_mode) && is_submodule_active(repo, ce->name)) { show_submodule(repo, dir, ce->name); - } else if (match_pathspec(&pathspec, fullname, strlen(fullname), + } else if (match_pathspec(repo->index, &pathspec, fullname, strlen(fullname), max_prefix_len, ps_matched, S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode))) { @@ -264,7 +265,7 @@ static void show_ru_info(const struct index_state *istate) len = strlen(path); if (len < max_prefix_len) continue; /* outside of the prefix */ - if (!match_pathspec(&pathspec, path, len, + if (!match_pathspec(istate, &pathspec, path, len, max_prefix_len, ps_matched, 0)) continue; /* uninterested */ for (i = 0; i < 3; i++) { diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index 409da4e835..fe3b952cb3 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -5,6 +5,7 @@ */ #include "cache.h" #include "config.h" +#include "object-store.h" #include "blob.h" #include "tree.h" #include "commit.h" diff --git a/builtin/merge-base.c b/builtin/merge-base.c index 3b7600150b..1c92099070 100644 --- a/builtin/merge-base.c +++ b/builtin/merge-base.c @@ -6,6 +6,8 @@ #include "diff.h" #include "revision.h" #include "parse-options.h" +#include "repository.h" +#include "commit-reach.h" static int show_merge_base(struct commit **rev, int rev_nr, int show_all) { @@ -42,7 +44,7 @@ static struct commit *get_commit_reference(const char *arg) if (get_oid(arg, &revkey)) die("Not a valid object name %s", arg); - r = lookup_commit_reference(&revkey); + r = lookup_commit_reference(the_repository, &revkey); if (!r) die("Not a valid commit name %s", arg); @@ -123,7 +125,7 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs) if (is_null_oid(oid)) return; - commit = lookup_commit(oid); + commit = lookup_commit(the_repository, oid); if (!commit || (commit->object.flags & TMP_MARK) || parse_commit(commit)) @@ -171,7 +173,7 @@ static int handle_fork_point(int argc, const char **argv) if (get_oid(commitname, &oid)) die("Not a valid object name: '%s'", commitname); - derived = lookup_commit_reference(&oid); + derived = lookup_commit_reference(the_repository, &oid); memset(&revs, 0, sizeof(revs)); revs.initial = 1; for_each_reflog_ent(refname, collect_one_reflog_ent, &revs); diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c index 0dd9021958..9b2f707c29 100644 --- a/builtin/merge-recursive.c +++ b/builtin/merge-recursive.c @@ -9,10 +9,10 @@ static const char builtin_merge_recursive_usage[] = static const char *better_branch_name(const char *branch) { - static char githead_env[8 + GIT_SHA1_HEXSZ + 1]; + static char githead_env[8 + GIT_MAX_HEXSZ + 1]; char *name; - if (strlen(branch) != GIT_SHA1_HEXSZ) + if (strlen(branch) != the_hash_algo->hexsz) return branch; xsnprintf(githead_env, sizeof(githead_env), "GITHEAD_%s", branch); name = getenv(githead_env); diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index bf01e05808..f8023bae1e 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -1,6 +1,8 @@ #include "builtin.h" #include "tree-walk.h" #include "xdiff-interface.h" +#include "object-store.h" +#include "repository.h" #include "blob.h" #include "exec-cmd.h" #include "merge-blobs.h" @@ -169,7 +171,7 @@ static struct merge_list *create_entry(unsigned stage, unsigned mode, const stru res->stage = stage; res->path = path; res->mode = mode; - res->blob = lookup_blob(oid); + res->blob = lookup_blob(the_repository, oid); return res; } diff --git a/builtin/merge.c b/builtin/merge.c index 4a4c09496c..7a8e3e274f 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -36,6 +36,7 @@ #include "packfile.h" #include "tag.h" #include "alias.h" +#include "commit-reach.h" #define DEFAULT_TWOHEAD (1<<0) #define DEFAULT_OCTOPUS (1<<1) @@ -111,6 +112,35 @@ static int option_parse_message(const struct option *opt, return 0; } +static int option_read_message(struct parse_opt_ctx_t *ctx, + const struct option *opt, int unset) +{ + struct strbuf *buf = opt->value; + const char *arg; + + if (unset) + BUG("-F cannot be negated"); + + if (ctx->opt) { + arg = ctx->opt; + ctx->opt = NULL; + } else if (ctx->argc > 1) { + ctx->argc--; + arg = *++ctx->argv; + } else + return opterror(opt, "requires a value", 0); + + if (buf->len) + strbuf_addch(buf, '\n'); + if (ctx->prefix && !is_absolute_path(arg)) + arg = prefix_filename(ctx->prefix, arg); + if (strbuf_read_file(buf, arg, 0) < 0) + return error(_("could not read file '%s'"), arg); + have_message = 1; + + return 0; +} + static struct strategy *get_strategy(const char *name) { int i; @@ -228,6 +258,9 @@ static struct option builtin_merge_options[] = { OPT_CALLBACK('m', "message", &merge_msg, N_("message"), N_("merge commit message (for a non-fast-forward merge)"), option_parse_message), + { OPTION_LOWLEVEL_CALLBACK, 'F', "file", &merge_msg, N_("path"), + N_("read message from file"), PARSE_OPT_NONEG, + (parse_opt_cb *) option_read_message }, OPT__VERBOSITY(&verbosity), OPT_BOOL(0, "abort", &abort_current_merge, N_("abort the current in-progress merge")), @@ -247,9 +280,9 @@ static struct option builtin_merge_options[] = { /* Cleans up metadata that is uninteresting after a succeeded merge. */ static void drop_save(void) { - unlink(git_path_merge_head()); - unlink(git_path_merge_msg()); - unlink(git_path_merge_mode()); + unlink(git_path_merge_head(the_repository)); + unlink(git_path_merge_msg(the_repository)); + unlink(git_path_merge_mode(the_repository)); } static int save_state(struct object_id *stash) @@ -382,7 +415,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead oid_to_hex(&commit->object.oid)); pretty_print_commit(&ctx, commit, &out); } - write_file_buf(git_path_squash_msg(), out.buf, out.len); + write_file_buf(git_path_squash_msg(the_repository), out.buf, out.len); strbuf_release(&out); } @@ -693,7 +726,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, exit(128); if (write_locked_index(&the_index, &lock, COMMIT_LOCK | SKIP_IF_UNCHANGED)) - die (_("unable to write %s"), get_index_file()); + die(_("unable to write %s"), get_index_file()); return clean ? 0 : 1; } else { return try_merge_command(strategy, xopts_nr, xopts, @@ -741,7 +774,7 @@ static void add_strategies(const char *string, unsigned attr) static void read_merge_msg(struct strbuf *msg) { - const char *filename = git_path_merge_msg(); + const char *filename = git_path_merge_msg(the_repository); strbuf_reset(msg); if (strbuf_read_file(msg, filename, 0) < 0) die_errno(_("Could not read from '%s'"), filename); @@ -778,18 +811,18 @@ static void prepare_to_commit(struct commit_list *remoteheads) if (signoff) append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0); write_merge_heads(remoteheads); - write_file_buf(git_path_merge_msg(), msg.buf, msg.len); + write_file_buf(git_path_merge_msg(the_repository), msg.buf, msg.len); if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg", - git_path_merge_msg(), "merge", NULL)) + git_path_merge_msg(the_repository), "merge", NULL)) abort_commit(remoteheads, NULL); if (0 < option_edit) { - if (launch_editor(git_path_merge_msg(), NULL, NULL)) + if (launch_editor(git_path_merge_msg(the_repository), NULL, NULL)) abort_commit(remoteheads, NULL); } if (verify_msg && run_commit_hook(0 < option_edit, get_index_file(), "commit-msg", - git_path_merge_msg(), NULL)) + git_path_merge_msg(the_repository), NULL)) abort_commit(remoteheads, NULL); read_merge_msg(&msg); @@ -859,7 +892,7 @@ static int suggest_conflicts(void) FILE *fp; struct strbuf msgbuf = STRBUF_INIT; - filename = git_path_merge_msg(); + filename = git_path_merge_msg(the_repository); fp = xfopen(filename, "a"); append_conflicts_hint(&msgbuf); @@ -942,12 +975,12 @@ static void write_merge_heads(struct commit_list *remoteheads) } strbuf_addf(&buf, "%s\n", oid_to_hex(oid)); } - write_file_buf(git_path_merge_head(), buf.buf, buf.len); + write_file_buf(git_path_merge_head(the_repository), buf.buf, buf.len); strbuf_reset(&buf); if (fast_forward == FF_NO) strbuf_addstr(&buf, "no-ff"); - write_file_buf(git_path_merge_mode(), buf.buf, buf.len); + write_file_buf(git_path_merge_mode(the_repository), buf.buf, buf.len); strbuf_release(&buf); } @@ -955,7 +988,8 @@ static void write_merge_state(struct commit_list *remoteheads) { write_merge_heads(remoteheads); strbuf_addch(&merge_msg, '\n'); - write_file_buf(git_path_merge_msg(), merge_msg.buf, merge_msg.len); + write_file_buf(git_path_merge_msg(the_repository), merge_msg.buf, + merge_msg.len); } static int default_edit_option(void) @@ -1034,11 +1068,12 @@ static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge const char *filename; int fd, pos, npos; struct strbuf fetch_head_file = STRBUF_INIT; + const unsigned hexsz = the_hash_algo->hexsz; if (!merge_names) merge_names = &fetch_head_file; - filename = git_path_fetch_head(); + filename = git_path_fetch_head(the_repository); fd = open(filename, O_RDONLY); if (fd < 0) die_errno(_("could not open '%s' for reading"), filename); @@ -1059,16 +1094,16 @@ static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge else npos = merge_names->len; - if (npos - pos < GIT_SHA1_HEXSZ + 2 || + if (npos - pos < hexsz + 2 || get_oid_hex(merge_names->buf + pos, &oid)) commit = NULL; /* bad */ - else if (memcmp(merge_names->buf + pos + GIT_SHA1_HEXSZ, "\t\t", 2)) + else if (memcmp(merge_names->buf + pos + hexsz, "\t\t", 2)) continue; /* not-for-merge */ else { - char saved = merge_names->buf[pos + GIT_SHA1_HEXSZ]; - merge_names->buf[pos + GIT_SHA1_HEXSZ] = '\0'; + char saved = merge_names->buf[pos + hexsz]; + merge_names->buf[pos + hexsz] = '\0'; commit = get_merge_parent(merge_names->buf + pos); - merge_names->buf[pos + GIT_SHA1_HEXSZ] = saved; + merge_names->buf[pos + hexsz] = saved; } if (!commit) { if (ptr) @@ -1213,7 +1248,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) usage_msg_opt(_("--abort expects no arguments"), builtin_merge_usage, builtin_merge_options); - if (!file_exists(git_path_merge_head())) + if (!file_exists(git_path_merge_head(the_repository))) die(_("There is no merge to abort (MERGE_HEAD missing).")); /* Invoke 'git reset --merge' */ @@ -1229,7 +1264,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) usage_msg_opt(_("--continue expects no arguments"), builtin_merge_usage, builtin_merge_options); - if (!file_exists(git_path_merge_head())) + if (!file_exists(git_path_merge_head(the_repository))) die(_("There is no merge in progress (MERGE_HEAD missing).")); /* Invoke 'git commit' */ @@ -1240,7 +1275,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) if (read_cache_unmerged()) die_resolve_conflict("merge"); - if (file_exists(git_path_merge_head())) { + if (file_exists(git_path_merge_head(the_repository))) { /* * There is no unmerged entry, don't advise 'git * add/rm <file>', just 'git commit'. @@ -1251,7 +1286,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) else die(_("You have not concluded your merge (MERGE_HEAD exists).")); } - if (file_exists(git_path_cherry_pick_head())) { + if (file_exists(git_path_cherry_pick_head(the_repository))) { if (advice_resolve_conflict) die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" "Please, commit your changes before you merge.")); diff --git a/builtin/mktag.c b/builtin/mktag.c index 82a6e86077..6fb7dc8578 100644 --- a/builtin/mktag.c +++ b/builtin/mktag.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "tag.h" #include "replace-object.h" +#include "object-store.h" /* * A signature file has a very simple fixed format: four lines diff --git a/builtin/mktree.c b/builtin/mktree.c index bb76b469fd..2dc4ad6ba8 100644 --- a/builtin/mktree.c +++ b/builtin/mktree.c @@ -7,6 +7,7 @@ #include "quote.h" #include "tree.h" #include "parse-options.h" +#include "object-store.h" static struct treeent { unsigned mode; diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c new file mode 100644 index 0000000000..2633efd95d --- /dev/null +++ b/builtin/multi-pack-index.c @@ -0,0 +1,47 @@ +#include "builtin.h" +#include "cache.h" +#include "config.h" +#include "parse-options.h" +#include "midx.h" + +static char const * const builtin_multi_pack_index_usage[] = { + N_("git multi-pack-index [--object-dir=<dir>] write"), + NULL +}; + +static struct opts_multi_pack_index { + const char *object_dir; +} opts; + +int cmd_multi_pack_index(int argc, const char **argv, + const char *prefix) +{ + static struct option builtin_multi_pack_index_options[] = { + OPT_FILENAME(0, "object-dir", &opts.object_dir, + N_("object directory containing set of packfile and pack-index pairs")), + OPT_END(), + }; + + git_config(git_default_config, NULL); + + argc = parse_options(argc, argv, prefix, + builtin_multi_pack_index_options, + builtin_multi_pack_index_usage, 0); + + if (!opts.object_dir) + opts.object_dir = get_object_directory(); + + if (argc == 0) + usage_with_options(builtin_multi_pack_index_usage, + builtin_multi_pack_index_options); + + if (argc > 1) { + die(_("too many arguments")); + return 1; + } + + if (!strcmp(argv[0], "write")) + return write_midx_file(opts.object_dir); + + die(_("unrecognized verb: %s"), argv[0]); +} diff --git a/builtin/name-rev.c b/builtin/name-rev.c index 0eb440359d..f1cb45c227 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "repository.h" #include "config.h" #include "commit.h" #include "tag.h" @@ -203,7 +204,7 @@ static int tipcmp(const void *a_, const void *b_) static int name_ref(const char *path, const struct object_id *oid, int flags, void *cb_data) { - struct object *o = parse_object(oid); + struct object *o = parse_object(the_repository, oid); struct name_ref_data *data = cb_data; int can_abbreviate_output = data->tags_only && data->name_only; int deref = 0; @@ -261,7 +262,7 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo struct tag *t = (struct tag *) o; if (!t->tagged) break; /* broken repository */ - o = parse_object(&t->tagged->oid); + o = parse_object(the_repository, &t->tagged->oid); deref = 1; taggerdate = t->date; } @@ -378,7 +379,8 @@ static void name_rev_line(char *p, struct name_ref_data *data) *(p+1) = 0; if (!get_oid(p - (GIT_SHA1_HEXSZ - 1), &oid)) { struct object *o = - lookup_object(oid.hash); + lookup_object(the_repository, + oid.hash); if (o) name = get_rev_name(o, &buf); } @@ -451,9 +453,10 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix) } commit = NULL; - object = parse_object(&oid); + object = parse_object(the_repository, &oid); if (object) { - struct object *peeled = deref_tag(object, *argv, 0); + struct object *peeled = deref_tag(the_repository, + object, *argv, 0); if (peeled && peeled->type == OBJ_COMMIT) commit = (struct commit *)peeled; } diff --git a/builtin/notes.c b/builtin/notes.c index 6981e2d906..c05cd004ab 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -11,6 +11,8 @@ #include "config.h" #include "builtin.h" #include "notes.h" +#include "object-store.h" +#include "repository.h" #include "blob.h" #include "pretty.h" #include "refs.h" @@ -710,7 +712,7 @@ static int merge_commit(struct notes_merge_options *o) if (get_oid("NOTES_MERGE_PARTIAL", &oid)) die(_("failed to read ref NOTES_MERGE_PARTIAL")); - else if (!(partial = lookup_commit_reference(&oid))) + else if (!(partial = lookup_commit_reference(the_repository, &oid))) die(_("could not find commit from NOTES_MERGE_PARTIAL.")); else if (parse_commit(partial)) die(_("could not parse commit from NOTES_MERGE_PARTIAL.")); diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 71056d8294..425bdc8ac5 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -24,6 +24,7 @@ #include "streaming.h" #include "thread-utils.h" #include "pack-bitmap.h" +#include "delta-islands.h" #include "reachable.h" #include "sha1-array.h" #include "argv-array.h" @@ -31,6 +32,7 @@ #include "packfile.h" #include "object-store.h" #include "dir.h" +#include "midx.h" #define IN_PACK(obj) oe_in_pack(&to_pack, obj) #define SIZE(obj) oe_size(&to_pack, obj) @@ -40,6 +42,7 @@ #define DELTA_CHILD(obj) oe_delta_child(&to_pack, obj) #define DELTA_SIBLING(obj) oe_delta_sibling(&to_pack, obj) #define SET_DELTA(obj, val) oe_set_delta(&to_pack, obj, val) +#define SET_DELTA_EXT(obj, oid) oe_set_delta_ext(&to_pack, obj, oid) #define SET_DELTA_SIZE(obj, val) oe_set_delta_size(&to_pack, obj, val) #define SET_DELTA_CHILD(obj, val) oe_set_delta_child(&to_pack, obj, val) #define SET_DELTA_SIBLING(obj, val) oe_set_delta_sibling(&to_pack, obj, val) @@ -59,6 +62,8 @@ static struct packing_data to_pack; static struct pack_idx_entry **written_list; static uint32_t nr_result, nr_written, nr_seen; +static struct bitmap_index *bitmap_git; +static uint32_t write_layer; static int non_empty; static int reuse_delta = 1, reuse_object = 1; @@ -79,6 +84,7 @@ static unsigned long pack_size_limit; static int depth = 50; static int delta_search_threads; static int pack_to_stdout; +static int thin; static int num_preferred_base; static struct progress *progress_state; @@ -93,6 +99,8 @@ static uint16_t write_bitmap_options; static int exclude_promisor_objects; +static int use_delta_islands; + static unsigned long delta_cache_size = 0; static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE; static unsigned long cache_max_small_delta_size = 1000; @@ -140,7 +148,7 @@ static void *get_delta(struct object_entry *entry) buf = read_object_file(&entry->idx.oid, &type, &size); if (!buf) - die("unable to read %s", oid_to_hex(&entry->idx.oid)); + die(_("unable to read %s"), oid_to_hex(&entry->idx.oid)); base_buf = read_object_file(&DELTA(entry)->idx.oid, &type, &base_size); if (!base_buf) @@ -148,8 +156,13 @@ static void *get_delta(struct object_entry *entry) oid_to_hex(&DELTA(entry)->idx.oid)); delta_buf = diff_delta(base_buf, base_size, buf, size, &delta_size, 0); + /* + * We succesfully computed this delta once but dropped it for + * memory reasons. Something is very wrong if this time we + * recompute and create a different delta. + */ if (!delta_buf || delta_size != DELTA_SIZE(entry)) - die("delta size changed"); + BUG("delta size changed"); free(buf); free(base_buf); return delta_buf; @@ -406,7 +419,7 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry, datalen = revidx[1].offset - offset; if (!pack_to_stdout && p->index_version > 1 && check_pack_crc(p, &w_curs, offset, datalen, revidx->nr)) { - error("bad packed object CRC for %s", + error(_("bad packed object CRC for %s"), oid_to_hex(&entry->idx.oid)); unuse_pack(&w_curs); return write_no_reuse_object(f, entry, limit, usable_delta); @@ -417,7 +430,7 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry, if (!pack_to_stdout && p->index_version == 1 && check_pack_inflate(p, &w_curs, offset, datalen, entry_size)) { - error("corrupt packed object for %s", + error(_("corrupt packed object for %s"), oid_to_hex(&entry->idx.oid)); unuse_pack(&w_curs); return write_no_reuse_object(f, entry, limit, usable_delta); @@ -548,7 +561,7 @@ static enum write_one_status write_one(struct hashfile *f, */ recursing = (e->idx.offset == 1); if (recursing) { - warning("recursive delta detected for object %s", + warning(_("recursive delta detected for object %s"), oid_to_hex(&e->idx.oid)); return WRITE_ONE_RECURSIVE; } else if (e->idx.offset || e->preferred_base) { @@ -582,7 +595,7 @@ static enum write_one_status write_one(struct hashfile *f, /* make sure off_t is sufficiently large not to wrap */ if (signed_add_overflows(*offset, size)) - die("pack too large for current definition of off_t"); + die(_("pack too large for current definition of off_t")); *offset += size; return WRITE_ONE_WRITTEN; } @@ -607,7 +620,7 @@ static inline void add_to_write_order(struct object_entry **wo, unsigned int *endp, struct object_entry *e) { - if (e->filled) + if (e->filled || oe_layer(&to_pack, e) != write_layer) return; wo[(*endp)++] = e; e->filled = 1; @@ -667,48 +680,15 @@ static void add_family_to_write_order(struct object_entry **wo, add_descendants_to_write_order(wo, endp, root); } -static struct object_entry **compute_write_order(void) +static void compute_layer_order(struct object_entry **wo, unsigned int *wo_end) { - unsigned int i, wo_end, last_untagged; - - struct object_entry **wo; + unsigned int i, last_untagged; struct object_entry *objects = to_pack.objects; for (i = 0; i < to_pack.nr_objects; i++) { - objects[i].tagged = 0; - objects[i].filled = 0; - SET_DELTA_CHILD(&objects[i], NULL); - SET_DELTA_SIBLING(&objects[i], NULL); - } - - /* - * Fully connect delta_child/delta_sibling network. - * Make sure delta_sibling is sorted in the original - * recency order. - */ - for (i = to_pack.nr_objects; i > 0;) { - struct object_entry *e = &objects[--i]; - if (!DELTA(e)) - continue; - /* Mark me as the first child */ - e->delta_sibling_idx = DELTA(e)->delta_child_idx; - SET_DELTA_CHILD(DELTA(e), e); - } - - /* - * Mark objects that are at the tip of tags. - */ - for_each_tag_ref(mark_tagged, NULL); - - /* - * Give the objects in the original recency order until - * we see a tagged tip. - */ - ALLOC_ARRAY(wo, to_pack.nr_objects); - for (i = wo_end = 0; i < to_pack.nr_objects; i++) { if (objects[i].tagged) break; - add_to_write_order(wo, &wo_end, &objects[i]); + add_to_write_order(wo, wo_end, &objects[i]); } last_untagged = i; @@ -717,7 +697,7 @@ static struct object_entry **compute_write_order(void) */ for (; i < to_pack.nr_objects; i++) { if (objects[i].tagged) - add_to_write_order(wo, &wo_end, &objects[i]); + add_to_write_order(wo, wo_end, &objects[i]); } /* @@ -727,7 +707,7 @@ static struct object_entry **compute_write_order(void) if (oe_type(&objects[i]) != OBJ_COMMIT && oe_type(&objects[i]) != OBJ_TAG) continue; - add_to_write_order(wo, &wo_end, &objects[i]); + add_to_write_order(wo, wo_end, &objects[i]); } /* @@ -736,19 +716,64 @@ static struct object_entry **compute_write_order(void) for (i = last_untagged; i < to_pack.nr_objects; i++) { if (oe_type(&objects[i]) != OBJ_TREE) continue; - add_to_write_order(wo, &wo_end, &objects[i]); + add_to_write_order(wo, wo_end, &objects[i]); } /* * Finally all the rest in really tight order */ for (i = last_untagged; i < to_pack.nr_objects; i++) { - if (!objects[i].filled) - add_family_to_write_order(wo, &wo_end, &objects[i]); + if (!objects[i].filled && oe_layer(&to_pack, &objects[i]) == write_layer) + add_family_to_write_order(wo, wo_end, &objects[i]); + } +} + +static struct object_entry **compute_write_order(void) +{ + uint32_t max_layers = 1; + unsigned int i, wo_end; + + struct object_entry **wo; + struct object_entry *objects = to_pack.objects; + + for (i = 0; i < to_pack.nr_objects; i++) { + objects[i].tagged = 0; + objects[i].filled = 0; + SET_DELTA_CHILD(&objects[i], NULL); + SET_DELTA_SIBLING(&objects[i], NULL); + } + + /* + * Fully connect delta_child/delta_sibling network. + * Make sure delta_sibling is sorted in the original + * recency order. + */ + for (i = to_pack.nr_objects; i > 0;) { + struct object_entry *e = &objects[--i]; + if (!DELTA(e)) + continue; + /* Mark me as the first child */ + e->delta_sibling_idx = DELTA(e)->delta_child_idx; + SET_DELTA_CHILD(DELTA(e), e); } + /* + * Mark objects that are at the tip of tags. + */ + for_each_tag_ref(mark_tagged, NULL); + + if (use_delta_islands) + max_layers = compute_pack_layers(&to_pack); + + ALLOC_ARRAY(wo, to_pack.nr_objects); + wo_end = 0; + + for (; write_layer < max_layers; ++write_layer) + compute_layer_order(wo, &wo_end); + if (wo_end != to_pack.nr_objects) - die("ordered %u objects, expected %"PRIu32, wo_end, to_pack.nr_objects); + die(_("ordered %u objects, expected %"PRIu32), + wo_end, to_pack.nr_objects); return wo; } @@ -760,15 +785,15 @@ static off_t write_reused_pack(struct hashfile *f) int fd; if (!is_pack_valid(reuse_packfile)) - die("packfile is invalid: %s", reuse_packfile->pack_name); + die(_("packfile is invalid: %s"), reuse_packfile->pack_name); fd = git_open(reuse_packfile->pack_name); if (fd < 0) - die_errno("unable to open packfile for reuse: %s", + die_errno(_("unable to open packfile for reuse: %s"), reuse_packfile->pack_name); if (lseek(fd, sizeof(struct pack_header), SEEK_SET) == -1) - die_errno("unable to seek in reused packfile"); + die_errno(_("unable to seek in reused packfile")); if (reuse_packfile_offset < 0) reuse_packfile_offset = reuse_packfile->pack_size - the_hash_algo->rawsz; @@ -779,7 +804,7 @@ static off_t write_reused_pack(struct hashfile *f) int read_pack = xread(fd, buffer, sizeof(buffer)); if (read_pack <= 0) - die_errno("unable to read from reused packfile"); + die_errno(_("unable to read from reused packfile")); if (read_pack > to_write) read_pack = to_write; @@ -882,7 +907,7 @@ static void write_pack_file(void) * to preserve this property. */ if (stat(pack_tmp_name, &st) < 0) { - warning_errno("failed to stat %s", pack_tmp_name); + warning_errno(_("failed to stat %s"), pack_tmp_name); } else if (!last_mtime) { last_mtime = st.st_mtime; } else { @@ -890,7 +915,7 @@ static void write_pack_file(void) utb.actime = st.st_atime; utb.modtime = --last_mtime; if (utime(pack_tmp_name, &utb) < 0) - warning_errno("failed utime() on %s", pack_tmp_name); + warning_errno(_("failed utime() on %s"), pack_tmp_name); } strbuf_addf(&tmpname, "%s-", base_name); @@ -935,8 +960,8 @@ static void write_pack_file(void) free(write_order); stop_progress(&progress_state); if (written != nr_result) - die("wrote %"PRIu32" objects while expecting %"PRIu32, - written, nr_result); + die(_("wrote %"PRIu32" objects while expecting %"PRIu32), + written, nr_result); } static int no_try_delta(const char *path) @@ -945,7 +970,7 @@ static int no_try_delta(const char *path) if (!check) check = attr_check_initl("delta", NULL); - if (git_check_attr(path, check)) + if (git_check_attr(&the_index, path, check)) return 0; if (ATTR_FALSE(check->items[0].value)) return 1; @@ -1034,6 +1059,7 @@ static int want_object_in_pack(const struct object_id *oid, { int want; struct list_head *pos; + struct multi_pack_index *m; if (!exclude && local && has_loose_object_nonlocal(oid)) return 0; @@ -1048,6 +1074,32 @@ static int want_object_in_pack(const struct object_id *oid, if (want != -1) return want; } + + for (m = get_multi_pack_index(the_repository); m; m = m->next) { + struct pack_entry e; + if (fill_midx_entry(oid, &e, m)) { + struct packed_git *p = e.p; + off_t offset; + + if (p == *found_pack) + offset = *found_offset; + else + offset = find_pack_entry_one(oid->hash, p); + + if (offset) { + if (!*found_pack) { + if (!is_pack_valid(p)) + continue; + *found_offset = offset; + *found_pack = p; + } + want = want_found_object(exclude, p); + if (want != -1) + return want; + } + } + } + list_for_each(pos, get_packed_git_mru(the_repository)) { struct packed_git *p = list_entry(pos, struct packed_git, mru); off_t offset; @@ -1480,7 +1532,7 @@ static void check_object(struct object_entry *entry) while (c & 128) { ofs += 1; if (!ofs || MSB(ofs, 7)) { - error("delta base offset overflow in pack for %s", + error(_("delta base offset overflow in pack for %s"), oid_to_hex(&entry->idx.oid)); goto give_up; } @@ -1489,7 +1541,7 @@ static void check_object(struct object_entry *entry) } ofs = entry->in_pack_offset - ofs; if (ofs <= 0 || ofs >= entry->in_pack_offset) { - error("delta base offset out of bound for %s", + error(_("delta base offset out of bound for %s"), oid_to_hex(&entry->idx.oid)); goto give_up; } @@ -1504,11 +1556,16 @@ static void check_object(struct object_entry *entry) break; } - if (base_ref && (base_entry = packlist_find(&to_pack, base_ref, NULL))) { + if (base_ref && ( + (base_entry = packlist_find(&to_pack, base_ref, NULL)) || + (thin && + bitmap_has_sha1_in_uninteresting(bitmap_git, base_ref))) && + in_same_island(&entry->idx.oid, &base_entry->idx.oid)) { /* * If base_ref was set above that means we wish to - * reuse delta data, and we even found that base - * in the list of objects we want to pack. Goodie! + * reuse delta data, and either we found that object in + * the list of objects we want to pack, or it's one we + * know the receiver has. * * Depth value does not matter - find_deltas() will * never consider reused delta as the base object to @@ -1517,10 +1574,16 @@ static void check_object(struct object_entry *entry) */ oe_set_type(entry, entry->in_pack_type); SET_SIZE(entry, in_pack_size); /* delta size */ - SET_DELTA(entry, base_entry); SET_DELTA_SIZE(entry, in_pack_size); - entry->delta_sibling_idx = base_entry->delta_child_idx; - SET_DELTA_CHILD(base_entry, entry); + + if (base_entry) { + SET_DELTA(entry, base_entry); + entry->delta_sibling_idx = base_entry->delta_child_idx; + SET_DELTA_CHILD(base_entry, entry); + } else { + SET_DELTA_EXT(entry, base_ref); + } + unuse_pack(&w_curs); return; } @@ -1820,6 +1883,11 @@ static int type_size_sort(const void *_a, const void *_b) return -1; if (a->preferred_base < b->preferred_base) return 1; + if (use_delta_islands) { + int island_cmp = island_delta_cmp(&a->idx.oid, &b->idx.oid); + if (island_cmp) + return island_cmp; + } if (a_size > b_size) return -1; if (a_size < b_size) @@ -1852,18 +1920,30 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size, #ifndef NO_PTHREADS +/* Protect access to object database */ static pthread_mutex_t read_mutex; #define read_lock() pthread_mutex_lock(&read_mutex) #define read_unlock() pthread_mutex_unlock(&read_mutex) +/* Protect delta_cache_size */ static pthread_mutex_t cache_mutex; #define cache_lock() pthread_mutex_lock(&cache_mutex) #define cache_unlock() pthread_mutex_unlock(&cache_mutex) +/* + * Protect object list partitioning (e.g. struct thread_param) and + * progress_state + */ static pthread_mutex_t progress_mutex; #define progress_lock() pthread_mutex_lock(&progress_mutex) #define progress_unlock() pthread_mutex_unlock(&progress_mutex) +/* + * Access to struct object_entry is unprotected since each thread owns + * a portion of the main object list. Just don't access object entries + * ahead in the list because they can be stolen and would need + * progress_mutex for protection. + */ #else #define read_lock() (void)0 @@ -1968,16 +2048,19 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, if (trg_size < src_size / 32) return 0; + if (!in_same_island(&trg->entry->idx.oid, &src->entry->idx.oid)) + return 0; + /* Load data if not already done */ if (!trg->data) { read_lock(); trg->data = read_object_file(&trg_entry->idx.oid, &type, &sz); read_unlock(); if (!trg->data) - die("object %s cannot be read", + die(_("object %s cannot be read"), oid_to_hex(&trg_entry->idx.oid)); if (sz != trg_size) - die("object %s inconsistent object length (%lu vs %lu)", + die(_("object %s inconsistent object length (%lu vs %lu)"), oid_to_hex(&trg_entry->idx.oid), sz, trg_size); *mem_usage += sz; @@ -1990,7 +2073,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, if (src_entry->preferred_base) { static int warned = 0; if (!warned++) - warning("object %s cannot be read", + warning(_("object %s cannot be read"), oid_to_hex(&src_entry->idx.oid)); /* * Those objects are not included in the @@ -2000,11 +2083,11 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, */ return 0; } - die("object %s cannot be read", + die(_("object %s cannot be read"), oid_to_hex(&src_entry->idx.oid)); } if (sz != src_size) - die("object %s inconsistent object length (%lu vs %lu)", + die(_("object %s inconsistent object length (%lu vs %lu)"), oid_to_hex(&src_entry->idx.oid), sz, src_size); *mem_usage += sz; @@ -2014,7 +2097,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, if (!src->index) { static int warned = 0; if (!warned++) - warning("suboptimal pack - out of memory"); + warning(_("suboptimal pack - out of memory")); return 0; } *mem_usage += sizeof_delta_index(src->index); @@ -2023,10 +2106,6 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, delta_buf = create_delta(src->index, trg->data, trg_size, &delta_size, max_size); if (!delta_buf) return 0; - if (delta_size >= (1U << OE_DELTA_SIZE_BITS)) { - free(delta_buf); - return 0; - } if (DELTA(trg_entry)) { /* Prefer only shallower same-sized deltas. */ @@ -2245,12 +2324,19 @@ static void try_to_free_from_threads(size_t size) static try_to_free_t old_try_to_free_routine; /* + * The main object list is split into smaller lists, each is handed to + * one worker. + * * The main thread waits on the condition that (at least) one of the workers * has stopped working (which is indicated in the .working member of * struct thread_params). + * * When a work thread has completed its work, it sets .working to 0 and * signals the main thread and waits on the condition that .data_ready * becomes 1. + * + * The main thread steals half of the work from the worker that has + * most work left to hand it to the idle worker. */ struct thread_params { @@ -2278,6 +2364,7 @@ static void init_threaded_search(void) pthread_mutex_init(&cache_mutex, NULL); pthread_mutex_init(&progress_mutex, NULL); pthread_cond_init(&progress_cond, NULL); + pthread_mutex_init(&to_pack.lock, NULL); old_try_to_free_routine = set_try_to_free_routine(try_to_free_from_threads); } @@ -2341,8 +2428,8 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, return; } if (progress > pack_to_stdout) - fprintf(stderr, "Delta compression using up to %d threads.\n", - delta_search_threads); + fprintf_ln(stderr, _("Delta compression using up to %d threads"), + delta_search_threads); p = xcalloc(delta_search_threads, sizeof(*p)); /* Partition the work amongst work threads. */ @@ -2382,7 +2469,7 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, ret = pthread_create(&p[i].thread, NULL, threaded_find_deltas, &p[i]); if (ret) - die("unable to create thread: %s", strerror(ret)); + die(_("unable to create thread: %s"), strerror(ret)); active_threads++; } @@ -2474,10 +2561,10 @@ static void add_tag_chain(const struct object_id *oid) if (packlist_find(&to_pack, oid->hash, NULL)) return; - tag = lookup_tag(oid); + tag = lookup_tag(the_repository, oid); while (1) { if (!tag || parse_tag(tag) || !tag->tagged) - die("unable to pack objects reachable from tag %s", + die(_("unable to pack objects reachable from tag %s"), oid_to_hex(oid)); add_object_entry(&tag->object.oid, OBJ_TAG, NULL, 0); @@ -2506,6 +2593,9 @@ static void prepare_pack(int window, int depth) uint32_t i, nr_deltas; unsigned n; + if (use_delta_islands) + resolve_tree_islands(progress, &to_pack); + get_object_details(); /* @@ -2543,7 +2633,7 @@ static void prepare_pack(int window, int depth) if (!entry->preferred_base) { nr_deltas++; if (oe_type(entry) < 0) - die("unable to get type of object %s", + die(_("unable to get type of object %s"), oid_to_hex(&entry->idx.oid)); } else { if (oe_type(entry) < 0) { @@ -2567,7 +2657,7 @@ static void prepare_pack(int window, int depth) ll_find_deltas(delta_list, n, window+1, depth, &nr_done); stop_progress(&progress_state); if (nr_done != nr_deltas) - die("inconsistency with delta count"); + die(_("inconsistency with delta count")); } free(delta_list); } @@ -2607,11 +2697,11 @@ static int git_pack_config(const char *k, const char *v, void *cb) if (!strcmp(k, "pack.threads")) { delta_search_threads = git_config_int(k, v); if (delta_search_threads < 0) - die("invalid number of threads specified (%d)", + die(_("invalid number of threads specified (%d)"), delta_search_threads); #ifdef NO_PTHREADS if (delta_search_threads != 1) { - warning("no threads support, ignoring %s", k); + warning(_("no threads support, ignoring %s"), k); delta_search_threads = 0; } #endif @@ -2620,7 +2710,7 @@ static int git_pack_config(const char *k, const char *v, void *cb) if (!strcmp(k, "pack.indexversion")) { pack_idx_opts.version = git_config_int(k, v); if (pack_idx_opts.version > 2) - die("bad pack.indexversion=%"PRIu32, + die(_("bad pack.indexversion=%"PRIu32), pack_idx_opts.version); return 0; } @@ -2638,7 +2728,7 @@ static void read_object_list_from_stdin(void) if (feof(stdin)) break; if (!ferror(stdin)) - die("fgets returned NULL, not EOF, not error!"); + die("BUG: fgets returned NULL, not EOF, not error!"); if (errno != EINTR) die_errno("fgets"); clearerr(stdin); @@ -2646,13 +2736,13 @@ static void read_object_list_from_stdin(void) } if (line[0] == '-') { if (get_oid_hex(line+1, &oid)) - die("expected edge object ID, got garbage:\n %s", + die(_("expected edge object ID, got garbage:\n %s"), line); add_preferred_base(&oid); continue; } if (parse_oid_hex(line, &oid, &p)) - die("expected object ID, got garbage:\n %s", line); + die(_("expected object ID, got garbage:\n %s"), line); add_preferred_base_object(p + 1); add_object_entry(&oid, OBJ_NONE, p + 1, 0); @@ -2669,6 +2759,9 @@ static void show_commit(struct commit *commit, void *data) if (write_bitmap_index) index_commit_for_bitmap(commit); + + if (use_delta_islands) + propagate_island_marks(commit); } static void show_object(struct object *obj, const char *name, void *data) @@ -2676,6 +2769,19 @@ static void show_object(struct object *obj, const char *name, void *data) add_preferred_base_object(name); add_object_entry(&obj->oid, obj->type, name, 0); obj->flags |= OBJECT_ADDED; + + if (use_delta_islands) { + const char *p; + unsigned depth = 0; + struct object_entry *ent; + + for (p = strchr(name, '/'); p; p = strchr(p + 1, '/')) + depth++; + + ent = packlist_find(&to_pack, obj->oid.hash, NULL); + if (ent && depth > oe_tree_depth(&to_pack, ent)) + oe_set_tree_depth(&to_pack, ent, depth); + } } static void show_object__ma_allow_any(struct object *obj, const char *name, void *data) @@ -2784,14 +2890,14 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs) memset(&in_pack, 0, sizeof(in_pack)); - for (p = get_packed_git(the_repository); p; p = p->next) { + for (p = get_all_packs(the_repository); p; p = p->next) { struct object_id oid; struct object *o; if (!p->pack_local || p->pack_keep || p->pack_keep_in_core) continue; if (open_pack_index(p)) - die("cannot open pack index"); + die(_("cannot open pack index")); ALLOC_GROW(in_pack.array, in_pack.nr + p->num_objects, @@ -2822,7 +2928,7 @@ static int add_loose_object(const struct object_id *oid, const char *path, enum object_type type = oid_object_info(the_repository, oid, NULL); if (type < 0) { - warning("loose object at %s could not be examined", path); + warning(_("loose object at %s could not be examined"), path); return 0; } @@ -2848,7 +2954,7 @@ static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid) struct packed_git *p; p = (last_found != (void *)1) ? last_found : - get_packed_git(the_repository); + get_all_packs(the_repository); while (p) { if ((!p->pack_local || p->pack_keep || @@ -2858,7 +2964,7 @@ static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid) return 1; } if (p == last_found) - p = get_packed_git(the_repository); + p = get_all_packs(the_repository); else p = p->next; if (p == last_found) @@ -2894,12 +3000,12 @@ static void loosen_unused_packed_objects(struct rev_info *revs) uint32_t i; struct object_id oid; - for (p = get_packed_git(the_repository); p; p = p->next) { + for (p = get_all_packs(the_repository); p; p = p->next) { if (!p->pack_local || p->pack_keep || p->pack_keep_in_core) continue; if (open_pack_index(p)) - die("cannot open pack index"); + die(_("cannot open pack index")); for (i = 0; i < p->num_objects; i++) { nth_packed_object_oid(&oid, p, i); @@ -2907,7 +3013,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs) !has_sha1_pack_kept_or_nonlocal(&oid) && !loosened_object_can_be_discarded(&oid, p->mtime)) if (force_object_loose(&oid, p->mtime)) - die("unable to force loose object"); + die(_("unable to force loose object")); } } } @@ -2929,11 +3035,12 @@ static int pack_options_allow_reuse(void) static int get_object_list_from_bitmap(struct rev_info *revs) { - if (prepare_bitmap_walk(revs) < 0) + if (!(bitmap_git = prepare_bitmap_walk(revs))) return -1; if (pack_options_allow_reuse() && !reuse_partial_packfile_from_bitmap( + bitmap_git, &reuse_packfile, &reuse_packfile_objects, &reuse_packfile_offset)) { @@ -2942,7 +3049,7 @@ static int get_object_list_from_bitmap(struct rev_info *revs) display_progress(progress_state, nr_result); } - traverse_bitmap_commit_list(&add_object_entry_from_bitmap); + traverse_bitmap_commit_list(bitmap_git, &add_object_entry_from_bitmap); return 0; } @@ -2969,7 +3076,7 @@ static void get_object_list(int ac, const char **av) setup_revisions(ac, av, &revs, NULL); /* make sure shallows are read */ - is_repository_shallow(); + is_repository_shallow(the_repository); while (fgets(line, sizeof(line), stdin) != NULL) { int len = strlen(line); @@ -2987,21 +3094,24 @@ static void get_object_list(int ac, const char **av) struct object_id oid; if (get_oid_hex(line + 10, &oid)) die("not an SHA-1 '%s'", line + 10); - register_shallow(&oid); + register_shallow(the_repository, &oid); use_bitmap_index = 0; continue; } - die("not a rev '%s'", line); + die(_("not a rev '%s'"), line); } if (handle_revision_arg(line, &revs, flags, REVARG_CANNOT_BE_FILENAME)) - die("bad revision '%s'", line); + die(_("bad revision '%s'"), line); } if (use_bitmap_index && !get_object_list_from_bitmap(&revs)) return; + if (use_delta_islands) + load_delta_islands(); + if (prepare_revision_walk(&revs)) - die("revision walk setup failed"); + die(_("revision walk setup failed")); mark_edges_uninteresting(&revs, show_edge); if (!fn_show_object) @@ -3014,9 +3124,9 @@ static void get_object_list(int ac, const char **av) revs.ignore_missing_links = 1; if (add_unseen_recent_objects_to_traversal(&revs, unpack_unreachable_expiration)) - die("unable to add recent objects"); + die(_("unable to add recent objects")); if (prepare_revision_walk(&revs)) - die("revision walk setup failed"); + die(_("revision walk setup failed")); traverse_commit_list(&revs, record_recent_commit, record_recent_object, NULL); } @@ -3038,7 +3148,7 @@ static void add_extra_kept_packs(const struct string_list *names) if (!names->nr) return; - for (p = get_packed_git(the_repository); p; p = p->next) { + for (p = get_all_packs(the_repository); p; p = p->next) { const char *name = basename(p->pack_name); int i; @@ -3090,7 +3200,6 @@ static int option_parse_unpack_unreachable(const struct option *opt, int cmd_pack_objects(int argc, const char **argv, const char *prefix) { int use_internal_rev_list = 0; - int thin = 0; int shallow = 0; int all_progress_implied = 0; struct argv_array rp = ARGV_ARRAY_INIT; @@ -3107,7 +3216,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "all-progress-implied", &all_progress_implied, N_("similar to --all-progress when progress meter is shown")), - { OPTION_CALLBACK, 0, "index-version", NULL, N_("version[,offset]"), + { OPTION_CALLBACK, 0, "index-version", NULL, N_("<version>[,<offset>]"), N_("write the pack index file in the specified idx format version"), 0, option_parse_index_version }, OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit, @@ -3179,13 +3288,15 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) option_parse_missing_action }, OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects, N_("do not pack objects in promisor packfiles")), + OPT_BOOL(0, "delta-islands", &use_delta_islands, + N_("respect islands during delta compression")), OPT_END(), }; if (DFS_NUM_STATES > (1 << OE_DFS_STATE_BITS)) BUG("too many dfs states, increase OE_DFS_STATE_BITS"); - check_replace_refs = 0; + read_replace_refs = 0; reset_pack_idx_option(&pack_idx_opts); git_config(git_pack_config, NULL); @@ -3251,35 +3362,35 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) if (pack_compression_level == -1) pack_compression_level = Z_DEFAULT_COMPRESSION; else if (pack_compression_level < 0 || pack_compression_level > Z_BEST_COMPRESSION) - die("bad pack compression level %d", pack_compression_level); + die(_("bad pack compression level %d"), pack_compression_level); if (!delta_search_threads) /* --threads=0 means autodetect */ delta_search_threads = online_cpus(); #ifdef NO_PTHREADS if (delta_search_threads != 1) - warning("no threads support, ignoring --threads"); + warning(_("no threads support, ignoring --threads")); #endif if (!pack_to_stdout && !pack_size_limit) pack_size_limit = pack_size_limit_cfg; if (pack_to_stdout && pack_size_limit) - die("--max-pack-size cannot be used to build a pack for transfer."); + die(_("--max-pack-size cannot be used to build a pack for transfer")); if (pack_size_limit && pack_size_limit < 1024*1024) { - warning("minimum pack size limit is 1 MiB"); + warning(_("minimum pack size limit is 1 MiB")); pack_size_limit = 1024*1024; } if (!pack_to_stdout && thin) - die("--thin cannot be used to build an indexable pack."); + die(_("--thin cannot be used to build an indexable pack")); if (keep_unreachable && unpack_unreachable) - die("--keep-unreachable and --unpack-unreachable are incompatible."); + die(_("--keep-unreachable and --unpack-unreachable are incompatible")); if (!rev_list_all || !rev_list_reflog || !rev_list_index) unpack_unreachable_expiration = 0; if (filter_options.choice) { if (!pack_to_stdout) - die("cannot use --filter without --stdout."); + die(_("cannot use --filter without --stdout")); use_bitmap_index = 0; } @@ -3299,19 +3410,22 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) use_bitmap_index = use_bitmap_index_default; /* "hard" reasons not to use bitmaps; these just won't work at all */ - if (!use_internal_rev_list || (!pack_to_stdout && write_bitmap_index) || is_repository_shallow()) + if (!use_internal_rev_list || (!pack_to_stdout && write_bitmap_index) || is_repository_shallow(the_repository)) use_bitmap_index = 0; if (pack_to_stdout || !rev_list_all) write_bitmap_index = 0; + if (use_delta_islands) + argv_array_push(&rp, "--topo-order"); + if (progress && all_progress_implied) progress = 2; add_extra_kept_packs(&keep_pack_list); if (ignore_packed_keep_on_disk) { struct packed_git *p; - for (p = get_packed_git(the_repository); p; p = p->next) + for (p = get_all_packs(the_repository); p; p = p->next) if (p->pack_local && p->pack_keep) break; if (!p) /* no keep-able packs found */ @@ -3324,7 +3438,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) * it also covers non-local objects */ struct packed_git *p; - for (p = get_packed_git(the_repository); p; p = p->next) { + for (p = get_all_packs(the_repository); p; p = p->next) { if (!p->pack_local) { have_non_local_packs = 1; break; @@ -3353,8 +3467,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) prepare_pack(window, depth); write_pack_file(); if (progress) - fprintf(stderr, "Total %"PRIu32" (delta %"PRIu32")," - " reused %"PRIu32" (delta %"PRIu32")\n", - written, written_delta, reused, reused_delta); + fprintf_ln(stderr, + _("Total %"PRIu32" (delta %"PRIu32")," + " reused %"PRIu32" (delta %"PRIu32")"), + written, written_delta, reused, reused_delta); return 0; } diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c index 0494dceff7..cf9a9aabd4 100644 --- a/builtin/pack-redundant.c +++ b/builtin/pack-redundant.c @@ -577,7 +577,7 @@ static struct pack_list * add_pack(struct packed_git *p) static struct pack_list * add_pack_file(const char *filename) { - struct packed_git *p = get_packed_git(the_repository); + struct packed_git *p = get_all_packs(the_repository); if (strlen(filename) < 40) die("Bad pack filename: %s", filename); @@ -592,7 +592,7 @@ static struct pack_list * add_pack_file(const char *filename) static void load_all(void) { - struct packed_git *p = get_packed_git(the_repository); + struct packed_git *p = get_all_packs(the_repository); while (p) { add_pack(p); diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c index 4ff525e50f..a9e7b552b9 100644 --- a/builtin/prune-packed.c +++ b/builtin/prune-packed.c @@ -3,6 +3,7 @@ #include "progress.h" #include "parse-options.h" #include "packfile.h" +#include "object-store.h" static const char * const prune_packed_usage[] = { N_("git prune-packed [-n | --dry-run] [-q | --quiet]"), diff --git a/builtin/prune.c b/builtin/prune.c index 518ffbea13..4916a4daa2 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -6,6 +6,7 @@ #include "reachable.h" #include "parse-options.h" #include "progress.h" +#include "object-store.h" static const char * const prune_usage[] = { N_("git prune [-n] [-v] [--progress] [--expire <time>] [--] [<head>...]"), @@ -39,7 +40,7 @@ static int prune_object(const struct object_id *oid, const char *fullpath, * Do we know about this object? * It must have been reachable */ - if (lookup_object(oid->hash)) + if (lookup_object(the_repository, oid->hash)) return 0; if (lstat(fullpath, &st)) { @@ -117,7 +118,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix) expire = TIME_MAX; save_commit_buffer = 0; - check_replace_refs = 0; + read_replace_refs = 0; ref_paranoia = 1; init_revisions(&revs, prefix); @@ -159,7 +160,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix) remove_temporary_files(s); free(s); - if (is_repository_shallow()) + if (is_repository_shallow(the_repository)) prune_shallow(show_only); return 0; diff --git a/builtin/pull.c b/builtin/pull.c index fe002a72f8..2514bfb9cd 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -22,6 +22,7 @@ #include "tempfile.h" #include "lockfile.h" #include "wt-status.h" +#include "commit-reach.h" enum rebase_type { REBASE_INVALID = -1, @@ -48,11 +49,11 @@ static enum rebase_type parse_config_rebase(const char *key, const char *value, return REBASE_FALSE; else if (v > 0) return REBASE_TRUE; - else if (!strcmp(value, "preserve")) + else if (!strcmp(value, "preserve") || !strcmp(value, "p")) return REBASE_PRESERVE; - else if (!strcmp(value, "merges")) + else if (!strcmp(value, "merges") || !strcmp(value, "m")) return REBASE_MERGES; - else if (!strcmp(value, "interactive")) + else if (!strcmp(value, "interactive") || !strcmp(value, "i")) return REBASE_INTERACTIVE; if (fatal) @@ -135,7 +136,7 @@ static struct option pull_options[] = { /* Options passed to git-merge or git-rebase */ OPT_GROUP(N_("Options related to merging")), { OPTION_CALLBACK, 'r', "rebase", &opt_rebase, - "false|true|merges|preserve|interactive", + "(false|true|merges|preserve|interactive)", N_("incorporate changes by rebasing rather than merging"), PARSE_OPT_OPTARG, parse_opt_rebase }, OPT_PASSTHRU('n', NULL, &opt_diffstat, NULL, @@ -356,7 +357,7 @@ static int git_pull_config(const char *var, const char *value, void *cb) */ static void get_merge_heads(struct oid_array *merge_heads) { - const char *filename = git_path_fetch_head(); + const char *filename = git_path_fetch_head(the_repository); FILE *fp; struct strbuf sb = STRBUF_INIT; struct object_id oid; @@ -765,10 +766,13 @@ static int get_octopus_merge_base(struct object_id *merge_base, { struct commit_list *revs = NULL, *result; - commit_list_insert(lookup_commit_reference(curr_head), &revs); - commit_list_insert(lookup_commit_reference(merge_head), &revs); + commit_list_insert(lookup_commit_reference(the_repository, curr_head), + &revs); + commit_list_insert(lookup_commit_reference(the_repository, merge_head), + &revs); if (!is_null_oid(fork_point)) - commit_list_insert(lookup_commit_reference(fork_point), &revs); + commit_list_insert(lookup_commit_reference(the_repository, fork_point), + &revs); result = get_octopus_merge_bases(revs); free_commit_list(revs); @@ -864,7 +868,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix) if (read_cache_unmerged()) die_resolve_conflict("pull"); - if (file_exists(git_path_merge_head())) + if (file_exists(git_path_merge_head(the_repository))) die_conclude_merge(); if (get_oid("HEAD", &orig_head)) @@ -944,9 +948,11 @@ int cmd_pull(int argc, const char **argv, const char *prefix) struct commit_list *list = NULL; struct commit *merge_head, *head; - head = lookup_commit_reference(&orig_head); + head = lookup_commit_reference(the_repository, + &orig_head); commit_list_insert(head, &list); - merge_head = lookup_commit_reference(&merge_heads.oid[0]); + merge_head = lookup_commit_reference(the_repository, + &merge_heads.oid[0]); if (is_descendant_of(merge_head, list)) { /* we can fast-forward this without invoking rebase */ opt_ff = "--ff-only"; diff --git a/builtin/push.c b/builtin/push.c index 9cd8e8cd56..d09a42062c 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -558,10 +558,10 @@ int cmd_push(int argc, const char **argv, const char *prefix) OPT_BIT( 0, "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN), OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE), { OPTION_CALLBACK, - 0, CAS_OPT_NAME, &cas, N_("refname>:<expect"), + 0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"), N_("require old value of ref to be at this value"), - PARSE_OPT_OPTARG, parseopt_push_cas_option }, - { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, "check|on-demand|no", + PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option }, + { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, "(check|on-demand|no)", N_("control recursive pushing of submodules"), PARSE_OPT_OPTARG, option_parse_recurse_submodules }, OPT_BOOL_F( 0 , "thin", &thin, N_("use thin pack"), PARSE_OPT_NOCOMPLETE), @@ -576,7 +576,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) OPT_BIT(0, "follow-tags", &flags, N_("push missing but relevant tags"), TRANSPORT_PUSH_FOLLOW_TAGS), { OPTION_CALLBACK, - 0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"), + 0, "signed", &push_cert, "(yes|no|if-asked)", N_("GPG sign the push"), PARSE_OPT_OPTARG, option_parse_push_signed }, OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC), OPT_STRING_LIST('o', "push-option", &push_options_cmdline, N_("server-specific"), N_("option to transmit")), diff --git a/builtin/range-diff.c b/builtin/range-diff.c new file mode 100644 index 0000000000..96af537493 --- /dev/null +++ b/builtin/range-diff.c @@ -0,0 +1,101 @@ +#include "cache.h" +#include "builtin.h" +#include "parse-options.h" +#include "range-diff.h" +#include "config.h" + +static const char * const builtin_range_diff_usage[] = { +N_("git range-diff [<options>] <old-base>..<old-tip> <new-base>..<new-tip>"), +N_("git range-diff [<options>] <old-tip>...<new-tip>"), +N_("git range-diff [<options>] <base> <old-tip> <new-tip>"), +NULL +}; + +int cmd_range_diff(int argc, const char **argv, const char *prefix) +{ + int creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT; + struct diff_options diffopt = { NULL }; + int simple_color = -1; + struct option options[] = { + OPT_INTEGER(0, "creation-factor", &creation_factor, + N_("Percentage by which creation is weighted")), + OPT_BOOL(0, "no-dual-color", &simple_color, + N_("use simple diff colors")), + OPT_END() + }; + int i, j, res = 0; + struct strbuf range1 = STRBUF_INIT, range2 = STRBUF_INIT; + + git_config(git_diff_ui_config, NULL); + + diff_setup(&diffopt); + + argc = parse_options(argc, argv, NULL, options, + builtin_range_diff_usage, PARSE_OPT_KEEP_UNKNOWN | + PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0); + + for (i = j = 1; i < argc && strcmp("--", argv[i]); ) { + int c = diff_opt_parse(&diffopt, argv + i, argc - i, prefix); + + if (!c) + argv[j++] = argv[i++]; + else + i += c; + } + while (i < argc) + argv[j++] = argv[i++]; + argc = j; + diff_setup_done(&diffopt); + + /* Make sure that there are no unparsed options */ + argc = parse_options(argc, argv, NULL, + options + ARRAY_SIZE(options) - 1, /* OPT_END */ + builtin_range_diff_usage, 0); + + /* force color when --dual-color was used */ + if (!simple_color) + diffopt.use_color = 1; + + if (argc == 2) { + if (!strstr(argv[0], "..")) + die(_("no .. in range: '%s'"), argv[0]); + strbuf_addstr(&range1, argv[0]); + + if (!strstr(argv[1], "..")) + die(_("no .. in range: '%s'"), argv[1]); + strbuf_addstr(&range2, argv[1]); + } else if (argc == 3) { + strbuf_addf(&range1, "%s..%s", argv[0], argv[1]); + strbuf_addf(&range2, "%s..%s", argv[0], argv[2]); + } else if (argc == 1) { + const char *b = strstr(argv[0], "..."), *a = argv[0]; + int a_len; + + if (!b) { + error(_("single arg format must be symmetric range")); + usage_with_options(builtin_range_diff_usage, options); + } + + a_len = (int)(b - a); + if (!a_len) { + a = "HEAD"; + a_len = strlen(a); + } + b += 3; + if (!*b) + b = "HEAD"; + strbuf_addf(&range1, "%s..%.*s", b, a_len, a); + strbuf_addf(&range2, "%.*s..%s", a_len, a, b); + } else { + error(_("need two commit ranges")); + usage_with_options(builtin_range_diff_usage, options); + } + + res = show_range_diff(range1.buf, range2.buf, creation_factor, + simple_color < 1, &diffopt); + + strbuf_release(&range1); + strbuf_release(&range2); + + return res; +} diff --git a/builtin/read-tree.c b/builtin/read-tree.c index ebc43eb805..fbbc98e516 100644 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@ -133,7 +133,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) N_("same as -m, but discard unmerged entries")), { OPTION_STRING, 0, "prefix", &opts.prefix, N_("<subdirectory>/"), N_("read the tree into the index under <subdirectory>/"), - PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP }, + PARSE_OPT_NONEG }, OPT_BOOL('u', NULL, &opts.update, N_("update working tree with merge result")), { OPTION_CALLBACK, 0, "exclude-per-directory", &opts, diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 68d36e0a56..35a3fcfbd9 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -25,7 +25,9 @@ #include "tmp-objdir.h" #include "oidset.h" #include "packfile.h" +#include "object-store.h" #include "protocol.h" +#include "commit-reach.h" static const char * const receive_pack_usage[] = { N_("git receive-pack <git-dir>"), @@ -629,8 +631,6 @@ static void prepare_push_cert_sha1(struct child_process *proc) return; if (!already_done) { - struct strbuf gpg_output = STRBUF_INIT; - struct strbuf gpg_status = STRBUF_INIT; int bogs /* beginning_of_gpg_sig */; already_done = 1; @@ -639,22 +639,11 @@ static void prepare_push_cert_sha1(struct child_process *proc) oidclr(&push_cert_oid); memset(&sigcheck, '\0', sizeof(sigcheck)); - sigcheck.result = 'N'; bogs = parse_signature(push_cert.buf, push_cert.len); - if (verify_signed_buffer(push_cert.buf, bogs, - push_cert.buf + bogs, push_cert.len - bogs, - &gpg_output, &gpg_status) < 0) { - ; /* error running gpg */ - } else { - sigcheck.payload = push_cert.buf; - sigcheck.gpg_output = gpg_output.buf; - sigcheck.gpg_status = gpg_status.buf; - parse_gpg_output(&sigcheck); - } + check_signature(push_cert.buf, bogs, push_cert.buf + bogs, + push_cert.len - bogs, &sigcheck); - strbuf_release(&gpg_output); - strbuf_release(&gpg_status); nonce_status = check_nonce(push_cert.buf, bogs); } if (!is_null_oid(&push_cert_oid)) { @@ -905,7 +894,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si) * not lose these new roots.. */ for (i = 0; i < extra.nr; i++) - register_shallow(&extra.oid[i]); + register_shallow(the_repository, &extra.oid[i]); si->shallow_ref[cmd->index] = 0; oid_array_clear(&extra); @@ -1107,8 +1096,8 @@ static const char *update(struct command *cmd, struct shallow_info *si) struct object *old_object, *new_object; struct commit *old_commit, *new_commit; - old_object = parse_object(old_oid); - new_object = parse_object(new_oid); + old_object = parse_object(the_repository, old_oid); + new_object = parse_object(the_repository, new_oid); if (!old_object || !new_object || old_object->type != OBJ_COMMIT || @@ -1131,7 +1120,7 @@ static const char *update(struct command *cmd, struct shallow_info *si) if (is_null_oid(new_oid)) { struct strbuf err = STRBUF_INIT; - if (!parse_object(old_oid)) { + if (!parse_object(the_repository, old_oid)) { old_oid = NULL; if (ref_exists(name)) { rp_warning("Allowing deletion of corrupt ref."); diff --git a/builtin/reflog.c b/builtin/reflog.c index a48984d37e..3acef5a0ab 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -1,6 +1,8 @@ #include "builtin.h" #include "config.h" #include "lockfile.h" +#include "object-store.h" +#include "repository.h" #include "commit.h" #include "refs.h" #include "dir.h" @@ -64,7 +66,7 @@ static int tree_is_complete(const struct object_id *oid) int complete; struct tree *tree; - tree = lookup_tree(oid); + tree = lookup_tree(the_repository, oid); if (!tree) return 0; if (tree->object.flags & SEEN) @@ -128,7 +130,7 @@ static int commit_is_complete(struct commit *commit) struct commit_list *parent; c = (struct commit *)object_array_pop(&study); - if (!c->object.parsed && !parse_object(&c->object.oid)) + if (!c->object.parsed && !parse_object(the_repository, &c->object.oid)) c->object.flags |= INCOMPLETE; if (c->object.flags & INCOMPLETE) { @@ -194,7 +196,7 @@ static int keep_entry(struct commit **it, struct object_id *oid) if (is_null_oid(oid)) return 1; - commit = lookup_commit_reference_gently(oid, 1); + commit = lookup_commit_reference_gently(the_repository, oid, 1); if (!commit) return 0; @@ -263,7 +265,8 @@ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit if (is_null_oid(oid)) return 0; - commit = lookup_commit_reference_gently(oid, 1); + commit = lookup_commit_reference_gently(the_repository, oid, + 1); /* Not a commit -- keep it */ if (!commit) @@ -320,7 +323,7 @@ static int push_tip_to_list(const char *refname, const struct object_id *oid, struct commit *tip_commit; if (flags & REF_ISSYMREF) return 0; - tip_commit = lookup_commit_reference_gently(oid, 1); + tip_commit = lookup_commit_reference_gently(the_repository, oid, 1); if (!tip_commit) return 0; commit_list_insert(tip_commit, list); @@ -337,7 +340,8 @@ static void reflog_expiry_prepare(const char *refname, cb->tip_commit = NULL; cb->unreachable_expire_kind = UE_HEAD; } else { - cb->tip_commit = lookup_commit_reference_gently(oid, 1); + cb->tip_commit = lookup_commit_reference_gently(the_repository, + oid, 1); if (!cb->tip_commit) cb->unreachable_expire_kind = UE_ALWAYS; else diff --git a/builtin/remote.c b/builtin/remote.c index 1a82d850a2..61479bc428 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -8,7 +8,9 @@ #include "run-command.h" #include "refs.h" #include "refspec.h" +#include "object-store.h" #include "argv-array.h" +#include "commit-reach.h" static const char * const builtin_remote_usage[] = { N_("git remote [-v | --verbose]"), @@ -167,7 +169,7 @@ static int add(int argc, const char **argv) OPT_STRING_LIST('t', "track", &track, N_("branch"), N_("branch(es) to track")), OPT_STRING('m', "master", &master, N_("branch"), N_("master branch")), - { OPTION_CALLBACK, 0, "mirror", &mirror, N_("push|fetch"), + { OPTION_CALLBACK, 0, "mirror", &mirror, "(push|fetch)", N_("set up remote as a mirror to push to or fetch from"), PARSE_OPT_OPTARG | PARSE_OPT_COMP_ARG, parse_mirror_opt }, OPT_END() @@ -565,7 +567,7 @@ static int read_remote_branches(const char *refname, strbuf_addf(&buf, "refs/remotes/%s/", rename->old_name); if (starts_with(refname, buf.buf)) { - item = string_list_append(rename->remote_branches, xstrdup(refname)); + item = string_list_append(rename->remote_branches, refname); symref = resolve_ref_unsafe(refname, RESOLVE_REF_READING, NULL, &flag); if (symref && (flag & REF_ISSYMREF)) @@ -611,7 +613,7 @@ static int mv(int argc, const char **argv) struct remote *oldremote, *newremote; struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT, old_remote_context = STRBUF_INIT; - struct string_list remote_branches = STRING_LIST_INIT_NODUP; + struct string_list remote_branches = STRING_LIST_INIT_DUP; struct rename_info rename; int i, refspec_updated = 0; @@ -733,6 +735,7 @@ static int mv(int argc, const char **argv) if (create_symref(buf.buf, buf2.buf, buf3.buf)) die(_("creating '%s' failed"), buf.buf); } + string_list_clear(&remote_branches, 1); return 0; } diff --git a/builtin/repack.c b/builtin/repack.c index 6c636e159e..c6a7943d5c 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -8,10 +8,14 @@ #include "strbuf.h" #include "string-list.h" #include "argv-array.h" +#include "midx.h" +#include "packfile.h" +#include "object-store.h" static int delta_base_offset = 1; static int pack_kept_objects = -1; static int write_bitmaps; +static int use_delta_islands; static char *packdir, *packtmp; static const char *const git_repack_usage[] = { @@ -40,6 +44,10 @@ static int repack_config(const char *var, const char *value, void *cb) write_bitmaps = git_config_bool(var, value); return 0; } + if (!strcmp(var, "repack.usedeltaislands")) { + use_delta_islands = git_config_bool(var, value); + return 0; + } return git_default_config(var, value, cb); } @@ -83,7 +91,7 @@ static void remove_pack_on_signal(int signo) /* * Adds all packs hex strings to the fname list, which do not - * have a corresponding .keep or .promisor file. These packs are not to + * have a corresponding .keep file. These packs are not to * be kept if we are going to pack everything into one file. */ static void get_non_kept_pack_filenames(struct string_list *fname_list, @@ -111,8 +119,7 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list, fname = xmemdupz(e->d_name, len); - if (!file_exists(mkpath("%s/%s.keep", packdir, fname)) && - !file_exists(mkpath("%s/%s.promisor", packdir, fname))) + if (!file_exists(mkpath("%s/%s.keep", packdir, fname))) string_list_append_nodup(fname_list, fname); else free(fname); @@ -122,7 +129,7 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list, static void remove_redundant_pack(const char *dir_name, const char *base_name) { - const char *exts[] = {".pack", ".idx", ".keep", ".bitmap"}; + const char *exts[] = {".pack", ".idx", ".keep", ".bitmap", ".promisor"}; int i; struct strbuf buf = STRBUF_INIT; size_t plen; @@ -138,6 +145,117 @@ static void remove_redundant_pack(const char *dir_name, const char *base_name) strbuf_release(&buf); } +struct pack_objects_args { + const char *window; + const char *window_memory; + const char *depth; + const char *threads; + const char *max_pack_size; + int no_reuse_delta; + int no_reuse_object; + int quiet; + int local; +}; + +static void prepare_pack_objects(struct child_process *cmd, + const struct pack_objects_args *args) +{ + argv_array_push(&cmd->args, "pack-objects"); + if (args->window) + argv_array_pushf(&cmd->args, "--window=%s", args->window); + if (args->window_memory) + argv_array_pushf(&cmd->args, "--window-memory=%s", args->window_memory); + if (args->depth) + argv_array_pushf(&cmd->args, "--depth=%s", args->depth); + if (args->threads) + argv_array_pushf(&cmd->args, "--threads=%s", args->threads); + if (args->max_pack_size) + argv_array_pushf(&cmd->args, "--max-pack-size=%s", args->max_pack_size); + if (args->no_reuse_delta) + argv_array_pushf(&cmd->args, "--no-reuse-delta"); + if (args->no_reuse_object) + argv_array_pushf(&cmd->args, "--no-reuse-object"); + if (args->local) + argv_array_push(&cmd->args, "--local"); + if (args->quiet) + argv_array_push(&cmd->args, "--quiet"); + if (delta_base_offset) + argv_array_push(&cmd->args, "--delta-base-offset"); + argv_array_push(&cmd->args, packtmp); + cmd->git_cmd = 1; + cmd->out = -1; +} + +/* + * Write oid to the given struct child_process's stdin, starting it first if + * necessary. + */ +static int write_oid(const struct object_id *oid, struct packed_git *pack, + uint32_t pos, void *data) +{ + struct child_process *cmd = data; + + if (cmd->in == -1) { + if (start_command(cmd)) + die("Could not start pack-objects to repack promisor objects"); + } + + xwrite(cmd->in, oid_to_hex(oid), GIT_SHA1_HEXSZ); + xwrite(cmd->in, "\n", 1); + return 0; +} + +static void repack_promisor_objects(const struct pack_objects_args *args, + struct string_list *names) +{ + struct child_process cmd = CHILD_PROCESS_INIT; + FILE *out; + struct strbuf line = STRBUF_INIT; + + prepare_pack_objects(&cmd, args); + cmd.in = -1; + + /* + * NEEDSWORK: Giving pack-objects only the OIDs without any ordering + * hints may result in suboptimal deltas in the resulting pack. See if + * the OIDs can be sent with fake paths such that pack-objects can use a + * {type -> existing pack order} ordering when computing deltas instead + * of a {type -> size} ordering, which may produce better deltas. + */ + for_each_packed_object(write_oid, &cmd, + FOR_EACH_OBJECT_PROMISOR_ONLY); + + if (cmd.in == -1) + /* No packed objects; cmd was never started */ + return; + + close(cmd.in); + + out = xfdopen(cmd.out, "r"); + while (strbuf_getline_lf(&line, out) != EOF) { + char *promisor_name; + int fd; + if (line.len != 40) + die("repack: Expecting 40 character sha1 lines only from pack-objects."); + string_list_append(names, line.buf); + + /* + * pack-objects creates the .pack and .idx files, but not the + * .promisor file. Create the .promisor file, which is empty. + */ + promisor_name = mkpathdup("%s-%s.promisor", packtmp, + line.buf); + fd = open(promisor_name, O_CREAT|O_EXCL|O_WRONLY, 0600); + if (fd < 0) + die_errno("unable to create '%s'", promisor_name); + close(fd); + free(promisor_name); + } + fclose(out); + if (finish_command(&cmd)) + die("Could not finish pack-objects to repack promisor objects"); +} + #define ALL_INTO_ONE 1 #define LOOSEN_UNREACHABLE 2 @@ -150,6 +268,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix) {".pack"}, {".idx"}, {".bitmap", 1}, + {".promisor", 1}, }; struct child_process cmd = CHILD_PROCESS_INIT; struct string_list_item *item; @@ -165,15 +284,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix) int delete_redundant = 0; const char *unpack_unreachable = NULL; int keep_unreachable = 0; - const char *window = NULL, *window_memory = NULL; - const char *depth = NULL; - const char *threads = NULL; - const char *max_pack_size = NULL; struct string_list keep_pack_list = STRING_LIST_INIT_NODUP; - int no_reuse_delta = 0, no_reuse_object = 0; int no_update_server_info = 0; - int quiet = 0; - int local = 0; + int midx_cleared = 0; + struct pack_objects_args po_args = {NULL}; struct option builtin_repack_options[] = { OPT_BIT('a', NULL, &pack_everything, @@ -183,30 +297,32 @@ int cmd_repack(int argc, const char **argv, const char *prefix) LOOSEN_UNREACHABLE | ALL_INTO_ONE), OPT_BOOL('d', NULL, &delete_redundant, N_("remove redundant packs, and run git-prune-packed")), - OPT_BOOL('f', NULL, &no_reuse_delta, + OPT_BOOL('f', NULL, &po_args.no_reuse_delta, N_("pass --no-reuse-delta to git-pack-objects")), - OPT_BOOL('F', NULL, &no_reuse_object, + OPT_BOOL('F', NULL, &po_args.no_reuse_object, N_("pass --no-reuse-object to git-pack-objects")), OPT_BOOL('n', NULL, &no_update_server_info, N_("do not run git-update-server-info")), - OPT__QUIET(&quiet, N_("be quiet")), - OPT_BOOL('l', "local", &local, + OPT__QUIET(&po_args.quiet, N_("be quiet")), + OPT_BOOL('l', "local", &po_args.local, N_("pass --local to git-pack-objects")), OPT_BOOL('b', "write-bitmap-index", &write_bitmaps, N_("write bitmap index")), + OPT_BOOL('i', "delta-islands", &use_delta_islands, + N_("pass --delta-islands to git-pack-objects")), OPT_STRING(0, "unpack-unreachable", &unpack_unreachable, N_("approxidate"), N_("with -A, do not loosen objects older than this")), OPT_BOOL('k', "keep-unreachable", &keep_unreachable, N_("with -a, repack unreachable objects")), - OPT_STRING(0, "window", &window, N_("n"), + OPT_STRING(0, "window", &po_args.window, N_("n"), N_("size of the window used for delta compression")), - OPT_STRING(0, "window-memory", &window_memory, N_("bytes"), + OPT_STRING(0, "window-memory", &po_args.window_memory, N_("bytes"), N_("same as the above, but limit memory size instead of entries count")), - OPT_STRING(0, "depth", &depth, N_("n"), + OPT_STRING(0, "depth", &po_args.depth, N_("n"), N_("limits the maximum delta depth")), - OPT_STRING(0, "threads", &threads, N_("n"), + OPT_STRING(0, "threads", &po_args.threads, N_("n"), N_("limits the maximum number of threads")), - OPT_STRING(0, "max-pack-size", &max_pack_size, N_("bytes"), + OPT_STRING(0, "max-pack-size", &po_args.max_pack_size, N_("bytes"), N_("maximum size of each packfile")), OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects, N_("repack objects in packs marked with .keep")), @@ -238,7 +354,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix) sigchain_push_common(remove_pack_on_signal); - argv_array_push(&cmd.args, "pack-objects"); + prepare_pack_objects(&cmd, &po_args); + argv_array_push(&cmd.args, "--keep-true-parents"); if (!pack_kept_objects) argv_array_push(&cmd.args, "--honor-pack-keep"); @@ -251,26 +368,16 @@ int cmd_repack(int argc, const char **argv, const char *prefix) argv_array_push(&cmd.args, "--indexed-objects"); if (repository_format_partial_clone) argv_array_push(&cmd.args, "--exclude-promisor-objects"); - if (window) - argv_array_pushf(&cmd.args, "--window=%s", window); - if (window_memory) - argv_array_pushf(&cmd.args, "--window-memory=%s", window_memory); - if (depth) - argv_array_pushf(&cmd.args, "--depth=%s", depth); - if (threads) - argv_array_pushf(&cmd.args, "--threads=%s", threads); - if (max_pack_size) - argv_array_pushf(&cmd.args, "--max-pack-size=%s", max_pack_size); - if (no_reuse_delta) - argv_array_pushf(&cmd.args, "--no-reuse-delta"); - if (no_reuse_object) - argv_array_pushf(&cmd.args, "--no-reuse-object"); if (write_bitmaps) argv_array_push(&cmd.args, "--write-bitmap-index"); + if (use_delta_islands) + argv_array_push(&cmd.args, "--delta-islands"); if (pack_everything & ALL_INTO_ONE) { get_non_kept_pack_filenames(&existing_packs, &keep_pack_list); + repack_promisor_objects(&po_args, &names); + if (existing_packs.nr && delete_redundant) { if (unpack_unreachable) { argv_array_pushf(&cmd.args, @@ -292,17 +399,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix) argv_array_push(&cmd.args, "--incremental"); } - if (local) - argv_array_push(&cmd.args, "--local"); - if (quiet) - argv_array_push(&cmd.args, "--quiet"); - if (delta_base_offset) - argv_array_push(&cmd.args, "--delta-base-offset"); - - argv_array_push(&cmd.args, packtmp); - - cmd.git_cmd = 1; - cmd.out = -1; cmd.no_stdin = 1; ret = start_command(&cmd); @@ -320,7 +416,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix) if (ret) return ret; - if (!names.nr && !quiet) + if (!names.nr && !po_args.quiet) printf("Nothing new to pack.\n"); /* @@ -333,6 +429,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix) for_each_string_list_item(item, &names) { for (ext = 0; ext < ARRAY_SIZE(exts); ext++) { char *fname, *fname_old; + + if (!midx_cleared) { + /* if we move a packfile, it will invalidated the midx */ + clear_midx_file(get_object_directory()); + midx_cleared = 1; + } + fname = mkpathdup("%s/pack-%s%s", packdir, item->string, exts[ext].name); if (!file_exists(fname)) { @@ -429,6 +532,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix) /* End of pack replacement. */ + reprepare_packed_git(the_repository); + if (delete_redundant) { int opts = 0; string_list_sort(&names); @@ -441,7 +546,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix) if (!string_list_has_string(&names, sha1)) remove_redundant_pack(packdir, item->string); } - if (!quiet && isatty(2)) + if (!po_args.quiet && isatty(2)) opts |= PRUNE_PACKED_VERBOSE; prune_packed_objects(opts); } diff --git a/builtin/replace.c b/builtin/replace.c index 6da2411e14..4f05791f3e 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -54,7 +54,7 @@ static int show_reference(const char *refname, const struct object_id *oid, enum object_type obj_type, repl_type; if (get_oid(refname, &object)) - return error("Failed to resolve '%s' as a valid ref.", refname); + return error(_("failed to resolve '%s' as a valid ref"), refname); obj_type = oid_object_info(the_repository, &object, NULL); @@ -83,8 +83,8 @@ static int list_replace_refs(const char *pattern, const char *format) else if (!strcmp(format, "long")) data.format = REPLACE_FORMAT_LONG; else - return error("invalid replace format '%s'\n" - "valid formats are 'short', 'medium' and 'long'\n", + return error(_("invalid replace format '%s'\n" + "valid formats are 'short', 'medium' and 'long'"), format); for_each_replace_ref(the_repository, show_reference, (void *)&data); @@ -108,7 +108,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn) for (p = argv; *p; p++) { if (get_oid(*p, &oid)) { - error("Failed to resolve '%s' as a valid ref.", *p); + error("failed to resolve '%s' as a valid ref", *p); had_error = 1; continue; } @@ -118,7 +118,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn) full_hex = ref.buf + base_len; if (read_ref(ref.buf, &oid)) { - error("replace ref '%s' not found.", full_hex); + error(_("replace ref '%s' not found"), full_hex); had_error = 1; continue; } @@ -134,7 +134,7 @@ static int delete_replace_ref(const char *name, const char *ref, { if (delete_ref(NULL, ref, oid, 0)) return 1; - printf("Deleted replace ref '%s'\n", name); + printf_ln(_("Deleted replace ref '%s'"), name); return 0; } @@ -146,12 +146,12 @@ static int check_ref_valid(struct object_id *object, strbuf_reset(ref); strbuf_addf(ref, "%s%s", git_replace_ref_base, oid_to_hex(object)); if (check_refname_format(ref->buf, 0)) - return error("'%s' is not a valid ref name.", ref->buf); + return error(_("'%s' is not a valid ref name"), ref->buf); if (read_ref(ref->buf, prev)) oidclr(prev); else if (!force) - return error("replace ref '%s' already exists", ref->buf); + return error(_("replace ref '%s' already exists"), ref->buf); return 0; } @@ -171,10 +171,10 @@ static int replace_object_oid(const char *object_ref, obj_type = oid_object_info(the_repository, object, NULL); repl_type = oid_object_info(the_repository, repl, NULL); if (!force && obj_type != repl_type) - return error("Objects must be of the same type.\n" - "'%s' points to a replaced object of type '%s'\n" - "while '%s' points to a replacement object of " - "type '%s'.", + return error(_("Objects must be of the same type.\n" + "'%s' points to a replaced object of type '%s'\n" + "while '%s' points to a replacement object of " + "type '%s'."), object_ref, type_name(obj_type), replace_ref, type_name(repl_type)); @@ -200,10 +200,10 @@ static int replace_object(const char *object_ref, const char *replace_ref, int f struct object_id object, repl; if (get_oid(object_ref, &object)) - return error("Failed to resolve '%s' as a valid ref.", + return error(_("failed to resolve '%s' as a valid ref"), object_ref); if (get_oid(replace_ref, &repl)) - return error("Failed to resolve '%s' as a valid ref.", + return error(_("failed to resolve '%s' as a valid ref"), replace_ref); return replace_object_oid(object_ref, &object, replace_ref, &repl, force); @@ -222,7 +222,7 @@ static int export_object(const struct object_id *oid, enum object_type type, fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd < 0) - return error_errno("unable to open %s for writing", filename); + return error_errno(_("unable to open %s for writing"), filename); argv_array_push(&cmd.args, "--no-replace-objects"); argv_array_push(&cmd.args, "cat-file"); @@ -235,7 +235,7 @@ static int export_object(const struct object_id *oid, enum object_type type, cmd.out = fd; if (run_command(&cmd)) - return error("cat-file reported failure"); + return error(_("cat-file reported failure")); return 0; } @@ -251,7 +251,7 @@ static int import_object(struct object_id *oid, enum object_type type, fd = open(filename, O_RDONLY); if (fd < 0) - return error_errno("unable to open %s for reading", filename); + return error_errno(_("unable to open %s for reading"), filename); if (!raw && type == OBJ_TREE) { const char *argv[] = { "mktree", NULL }; @@ -265,11 +265,11 @@ static int import_object(struct object_id *oid, enum object_type type, if (start_command(&cmd)) { close(fd); - return error("unable to spawn mktree"); + return error(_("unable to spawn mktree")); } if (strbuf_read(&result, cmd.out, 41) < 0) { - error_errno("unable to read from mktree"); + error_errno(_("unable to read from mktree")); close(fd); close(cmd.out); return -1; @@ -278,11 +278,11 @@ static int import_object(struct object_id *oid, enum object_type type, if (finish_command(&cmd)) { strbuf_release(&result); - return error("mktree reported failure"); + return error(_("mktree reported failure")); } if (get_oid_hex(result.buf, oid) < 0) { strbuf_release(&result); - return error("mktree did not return an object name"); + return error(_("mktree did not return an object name")); } strbuf_release(&result); @@ -291,12 +291,12 @@ static int import_object(struct object_id *oid, enum object_type type, int flags = HASH_FORMAT_CHECK | HASH_WRITE_OBJECT; if (fstat(fd, &st) < 0) { - error_errno("unable to fstat %s", filename); + error_errno(_("unable to fstat %s"), filename); close(fd); return -1; } if (index_fd(oid, fd, &st, type, NULL, flags) < 0) - return error("unable to write object to database"); + return error(_("unable to write object to database")); /* index_fd close()s fd for us */ } @@ -315,11 +315,11 @@ static int edit_and_replace(const char *object_ref, int force, int raw) struct strbuf ref = STRBUF_INIT; if (get_oid(object_ref, &old_oid) < 0) - return error("Not a valid object name: '%s'", object_ref); + return error(_("not a valid object name: '%s'"), object_ref); type = oid_object_info(the_repository, &old_oid, NULL); if (type < 0) - return error("unable to get object type for %s", + return error(_("unable to get object type for %s"), oid_to_hex(&old_oid)); if (check_ref_valid(&old_oid, &prev, &ref, force)) { @@ -335,7 +335,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw) } if (launch_editor(tmpfile, NULL, NULL) < 0) { free(tmpfile); - return error("editing object file failed"); + return error(_("editing object file failed")); } if (import_object(&new_oid, type, raw, tmpfile)) { free(tmpfile); @@ -344,7 +344,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw) free(tmpfile); if (!oidcmp(&old_oid, &new_oid)) - return error("new object is the same as the old one: '%s'", oid_to_hex(&old_oid)); + return error(_("new object is the same as the old one: '%s'"), oid_to_hex(&old_oid)); return replace_object_oid(object_ref, &old_oid, "replacement", &new_oid, force); } @@ -368,10 +368,10 @@ static int replace_parents(struct strbuf *buf, int argc, const char **argv) struct object_id oid; if (get_oid(argv[i], &oid) < 0) { strbuf_release(&new_parents); - return error(_("Not a valid object name: '%s'"), + return error(_("not a valid object name: '%s'"), argv[i]); } - if (!lookup_commit_reference(&oid)) { + if (!lookup_commit_reference(the_repository, &oid)) { strbuf_release(&new_parents); return error(_("could not parse %s"), argv[i]); } @@ -402,17 +402,17 @@ static int check_one_mergetag(struct commit *commit, int i; hash_object_file(extra->value, extra->len, type_name(OBJ_TAG), &tag_oid); - tag = lookup_tag(&tag_oid); + tag = lookup_tag(the_repository, &tag_oid); if (!tag) return error(_("bad mergetag in commit '%s'"), ref); - if (parse_tag_buffer(tag, extra->value, extra->len)) + if (parse_tag_buffer(the_repository, tag, extra->value, extra->len)) return error(_("malformed mergetag in commit '%s'"), ref); /* iterate over new parents */ for (i = 1; i < mergetag_data->argc; i++) { struct object_id oid; if (get_oid(mergetag_data->argv[i], &oid) < 0) - return error(_("Not a valid object name: '%s'"), + return error(_("not a valid object name: '%s'"), mergetag_data->argv[i]); if (!oidcmp(&tag->tagged->oid, &oid)) return 0; /* found */ @@ -442,8 +442,8 @@ static int create_graft(int argc, const char **argv, int force, int gentle) unsigned long size; if (get_oid(old_ref, &old_oid) < 0) - return error(_("Not a valid object name: '%s'"), old_ref); - commit = lookup_commit_reference(&old_oid); + return error(_("not a valid object name: '%s'"), old_ref); + commit = lookup_commit_reference(the_repository, &old_oid); if (!commit) return error(_("could not parse %s"), old_ref); @@ -457,7 +457,7 @@ static int create_graft(int argc, const char **argv, int force, int gentle) } if (remove_signature(&buf)) { - warning(_("the original commit '%s' has a gpg signature."), old_ref); + warning(_("the original commit '%s' has a gpg signature"), old_ref); warning(_("the signature will be removed in the replacement commit!")); } @@ -476,10 +476,10 @@ static int create_graft(int argc, const char **argv, int force, int gentle) if (!oidcmp(&old_oid, &new_oid)) { if (gentle) { - warning("graft for '%s' unnecessary", oid_to_hex(&old_oid)); + warning(_("graft for '%s' unnecessary"), oid_to_hex(&old_oid)); return 0; } - return error("new commit is the same as the old one: '%s'", oid_to_hex(&old_oid)); + return error(_("new commit is the same as the old one: '%s'"), oid_to_hex(&old_oid)); } return replace_object_oid(old_ref, &old_oid, "replacement", &new_oid, force); @@ -487,7 +487,7 @@ static int create_graft(int argc, const char **argv, int force, int gentle) static int convert_graft_file(int force) { - const char *graft_file = get_graft_file(); + const char *graft_file = get_graft_file(the_repository); FILE *fp = fopen_or_warn(graft_file, "r"); struct strbuf buf = STRBUF_INIT, err = STRBUF_INIT; struct argv_array args = ARGV_ARRAY_INIT; @@ -544,7 +544,7 @@ int cmd_replace(int argc, const char **argv, const char *prefix) OPT_END() }; - check_replace_refs = 0; + read_replace_refs = 0; git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0); @@ -553,7 +553,7 @@ int cmd_replace(int argc, const char **argv, const char *prefix) cmdmode = argc ? MODE_REPLACE : MODE_LIST; if (format && cmdmode != MODE_LIST) - usage_msg_opt("--format cannot be used when not listing", + usage_msg_opt(_("--format cannot be used when not listing"), git_replace_usage, options); if (force && @@ -561,47 +561,47 @@ int cmd_replace(int argc, const char **argv, const char *prefix) cmdmode != MODE_EDIT && cmdmode != MODE_GRAFT && cmdmode != MODE_CONVERT_GRAFT_FILE) - usage_msg_opt("-f only makes sense when writing a replacement", + usage_msg_opt(_("-f only makes sense when writing a replacement"), git_replace_usage, options); if (raw && cmdmode != MODE_EDIT) - usage_msg_opt("--raw only makes sense with --edit", + usage_msg_opt(_("--raw only makes sense with --edit"), git_replace_usage, options); switch (cmdmode) { case MODE_DELETE: if (argc < 1) - usage_msg_opt("-d needs at least one argument", + usage_msg_opt(_("-d needs at least one argument"), git_replace_usage, options); return for_each_replace_name(argv, delete_replace_ref); case MODE_REPLACE: if (argc != 2) - usage_msg_opt("bad number of arguments", + usage_msg_opt(_("bad number of arguments"), git_replace_usage, options); return replace_object(argv[0], argv[1], force); case MODE_EDIT: if (argc != 1) - usage_msg_opt("-e needs exactly one argument", + usage_msg_opt(_("-e needs exactly one argument"), git_replace_usage, options); return edit_and_replace(argv[0], force, raw); case MODE_GRAFT: if (argc < 1) - usage_msg_opt("-g needs at least one argument", + usage_msg_opt(_("-g needs at least one argument"), git_replace_usage, options); return create_graft(argc, argv, force, 0); case MODE_CONVERT_GRAFT_FILE: if (argc != 0) - usage_msg_opt("--convert-graft-file takes no argument", + usage_msg_opt(_("--convert-graft-file takes no argument"), git_replace_usage, options); return !!convert_graft_file(force); case MODE_LIST: if (argc > 1) - usage_msg_opt("only one pattern can be given with -l", + usage_msg_opt(_("only one pattern can be given with -l"), git_replace_usage, options); return list_replace_refs(argv[0], format); diff --git a/builtin/reset.c b/builtin/reset.c index a862c70fab..11cd0dcb8c 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -39,7 +39,7 @@ static const char *reset_type_names[] = { static inline int is_merge(void) { - return !access(git_path_merge_head(), F_OK); + return !access(git_path_merge_head(the_repository), F_OK); } static int reset_index(const struct object_id *oid, int reset_type, int quiet) @@ -134,7 +134,7 @@ static void update_index_from_diff(struct diff_queue_struct *q, continue; } - ce = make_cache_entry(one->mode, one->oid.hash, one->path, + ce = make_cache_entry(&the_index, one->mode, &one->oid, one->path, 0, 0); if (!ce) die(_("make_cache_entry failed for path '%s'"), @@ -319,7 +319,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) struct commit *commit; if (get_oid_committish(rev, &oid)) die(_("Failed to resolve '%s' as a valid revision."), rev); - commit = lookup_commit_reference(&oid); + commit = lookup_commit_reference(the_repository, &oid); if (!commit) die(_("Could not parse object '%s'."), rev); oidcpy(&oid, &commit->object.oid); @@ -396,7 +396,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) update_ref_status = reset_refs(rev, &oid); if (reset_type == HARD && !update_ref_status && !quiet) - print_new_head_line(lookup_commit_reference(&oid)); + print_new_head_line(lookup_commit_reference(the_repository, &oid)); } if (!pathspec.nr) remove_branch_state(); diff --git a/builtin/rev-list.c b/builtin/rev-list.c index fadd3ec14c..ed0ea7dc5b 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -6,6 +6,7 @@ #include "list-objects.h" #include "list-objects-filter.h" #include "list-objects-filter-options.h" +#include "object-store.h" #include "pack.h" #include "pack-bitmap.h" #include "builtin.h" @@ -16,6 +17,7 @@ #include "reflog-walk.h" #include "oidset.h" #include "packfile.h" +#include "object-store.h" static const char rev_list_usage[] = "git rev-list [OPTION] <commit-id>... [ -- paths... ]\n" @@ -238,7 +240,7 @@ static int finish_object(struct object *obj, const char *name, void *cb_data) return 1; } if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT) - parse_object(&obj->oid); + parse_object(the_repository, &obj->oid); return 0; } @@ -491,7 +493,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) if ((!revs.commits && reflog_walk_empty(revs.reflog_info) && (!(revs.tag_objects || revs.tree_objects || revs.blob_objects) && !revs.pending.nr) && - !revs.rev_input_given) || + !revs.rev_input_given && !revs.read_from_stdin) || revs.diff) usage(rev_list_usage); @@ -514,17 +516,21 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) if (revs.count && !revs.left_right && !revs.cherry_mark) { uint32_t commit_count; int max_count = revs.max_count; - if (!prepare_bitmap_walk(&revs)) { - count_bitmap_commit_list(&commit_count, NULL, NULL, NULL); + struct bitmap_index *bitmap_git; + if ((bitmap_git = prepare_bitmap_walk(&revs))) { + count_bitmap_commit_list(bitmap_git, &commit_count, NULL, NULL, NULL); if (max_count >= 0 && max_count < commit_count) commit_count = max_count; printf("%d\n", commit_count); + free_bitmap_index(bitmap_git); return 0; } } else if (revs.max_count < 0 && revs.tag_objects && revs.tree_objects && revs.blob_objects) { - if (!prepare_bitmap_walk(&revs)) { - traverse_bitmap_commit_list(&show_object_fast); + struct bitmap_index *bitmap_git; + if ((bitmap_git = prepare_bitmap_walk(&revs))) { + traverse_bitmap_commit_list(bitmap_git, &show_object_fast); + free_bitmap_index(bitmap_git); return 0; } } diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 4f49e96bfd..455f62246d 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -14,6 +14,7 @@ #include "revision.h" #include "split-index.h" #include "submodule.h" +#include "commit-reach.h" #define DO_REVS 1 #define DO_NOREV 2 @@ -280,8 +281,8 @@ static int try_difference(const char *arg) if (symmetric) { struct commit_list *exclude; struct commit *a, *b; - a = lookup_commit_reference(&start_oid); - b = lookup_commit_reference(&end_oid); + a = lookup_commit_reference(the_repository, &start_oid); + b = lookup_commit_reference(the_repository, &end_oid); if (!a || !b) { *dotdot = '.'; return 0; @@ -333,7 +334,7 @@ static int try_parent_shorthands(const char *arg) *dotdot = 0; if (get_oid_committish(arg, &oid) || - !(commit = lookup_commit_reference(&oid))) { + !(commit = lookup_commit_reference(the_repository, &oid))) { *dotdot = '^'; return 0; } @@ -883,7 +884,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "--is-shallow-repository")) { - printf("%s\n", is_repository_shallow() ? "true" + printf("%s\n", + is_repository_shallow(the_repository) ? "true" : "false"); continue; } diff --git a/builtin/revert.c b/builtin/revert.c index 76f0a35b07..9a66720cfc 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -7,6 +7,7 @@ #include "rerere.h" #include "dir.h" #include "sequencer.h" +#include "branch.h" /* * This implements the builtins revert and cherry-pick. @@ -191,8 +192,12 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts) opts->gpg_sign = xstrdup_or_null(opts->gpg_sign); opts->strategy = xstrdup_or_null(opts->strategy); - if (cmd == 'q') - return sequencer_remove_state(opts); + if (cmd == 'q') { + int ret = sequencer_remove_state(opts); + if (!ret) + remove_branch_state(); + return ret; + } if (cmd == 'c') return sequencer_continue(opts); if (cmd == 'a') diff --git a/builtin/rm.c b/builtin/rm.c index 65b448ef8e..2cbe89e0ae 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -278,14 +278,14 @@ int cmd_rm(int argc, const char **argv, const char *prefix) for (i = 0; i < active_nr; i++) { const struct cache_entry *ce = active_cache[i]; - if (!ce_path_match(ce, &pathspec, seen)) + if (!ce_path_match(&the_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)) - die (_("Please stage your changes to .gitmodules or stash them to proceed")); + die(_("please stage your changes to .gitmodules or stash them to proceed")); } if (pathspec.nr) { diff --git a/builtin/send-pack.c b/builtin/send-pack.c index 42fd8d1a35..8e3c7490f7 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -166,7 +166,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "mirror", &send_mirror, N_("mirror all refs")), OPT_BOOL('f', "force", &force_update, N_("force updates")), { OPTION_CALLBACK, - 0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"), + 0, "signed", &push_cert, "(yes|no|if-asked)", N_("GPG sign the push"), PARSE_OPT_OPTARG, option_parse_push_signed }, OPT_STRING_LIST(0, "push-option", &push_options, N_("server-specific"), @@ -178,7 +178,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "stdin", &from_stdin, N_("read refs from stdin")), OPT_BOOL(0, "helper-status", &helper_status, N_("print status from remote helper")), { OPTION_CALLBACK, - 0, CAS_OPT_NAME, &cas, N_("refname>:<expect"), + 0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"), N_("require old value of ref to be at this value"), PARSE_OPT_OPTARG, parseopt_push_cas_option }, OPT_END() diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 608d6ba77b..3898a2c9c4 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -268,8 +268,9 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) N_("Suppress commit descriptions, only provides commit count")), OPT_BOOL('e', "email", &log.email, N_("Show the email address of each author")), - { OPTION_CALLBACK, 'w', NULL, &log, N_("w[,i1[,i2]]"), - N_("Linewrap output"), PARSE_OPT_OPTARG, &parse_wrap_args }, + { OPTION_CALLBACK, 'w', NULL, &log, N_("<w>[,<i1>[,<i2>]]"), + N_("Linewrap output"), PARSE_OPT_OPTARG, + &parse_wrap_args }, OPT_END(), }; diff --git a/builtin/show-branch.c b/builtin/show-branch.c index f2e985c00a..363cf8509a 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -378,7 +378,8 @@ static void sort_ref_range(int bottom, int top) static int append_ref(const char *refname, const struct object_id *oid, int allow_dups) { - struct commit *commit = lookup_commit_reference_gently(oid, 1); + struct commit *commit = lookup_commit_reference_gently(the_repository, + oid, 1); int i; if (!commit) @@ -673,7 +674,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) { OPTION_CALLBACK, 'g', "reflog", &reflog_base, N_("<n>[,<base>]"), N_("show <n> most recent ref-log entries starting at " "base"), - PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, + PARSE_OPT_OPTARG, parse_reflog_param }, OPT_END() }; @@ -830,7 +831,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) MAX_REVS), MAX_REVS); if (get_oid(ref_name[num_rev], &revkey)) die(_("'%s' is not a valid ref."), ref_name[num_rev]); - commit = lookup_commit_reference(&revkey); + commit = lookup_commit_reference(the_repository, &revkey); if (!commit) die(_("cannot find commit %s (%s)"), ref_name[num_rev], oid_to_hex(&revkey)); diff --git a/builtin/show-ref.c b/builtin/show-ref.c index f2eb1a7724..2f13f1316f 100644 --- a/builtin/show-ref.c +++ b/builtin/show-ref.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "cache.h" #include "refs.h" +#include "object-store.h" #include "object.h" #include "tag.h" #include "string-list.h" diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 20ae9191ca..40844870cf 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -331,7 +331,7 @@ static int module_list_compute(int argc, const char **argv, for (i = 0; i < active_nr; i++) { const struct cache_entry *ce = active_cache[i]; - if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), + if (!match_pathspec(&the_index, pathspec, ce->name, ce_namelen(ce), 0, ps_matched, 1) || !S_ISGITLINK(ce->ce_mode)) continue; @@ -542,7 +542,7 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item, argv_array_pushv(&cpr.args, info->argv); if (run_command(&cpr)) - die(_("run_command returned non-zero status while" + die(_("run_command returned non-zero status while " "recursing in the nested submodules of %s\n."), displaypath); } @@ -1024,7 +1024,6 @@ static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data { struct sync_cb *info = cb_data; sync_submodule(list_item->name, info->prefix, info->flags); - } static int module_sync(int argc, const char **argv, const char *prefix) @@ -1444,6 +1443,72 @@ static int module_clone(int argc, const char **argv, const char *prefix) return 0; } +static void determine_submodule_update_strategy(struct repository *r, + int just_cloned, + const char *path, + const char *update, + struct submodule_update_strategy *out) +{ + const struct submodule *sub = submodule_from_path(r, &null_oid, path); + char *key; + const char *val; + + key = xstrfmt("submodule.%s.update", sub->name); + + if (update) { + trace_printf("parsing update"); + if (parse_submodule_update_strategy(update, out) < 0) + die(_("Invalid update mode '%s' for submodule path '%s'"), + update, path); + } else if (!repo_config_get_string_const(r, key, &val)) { + if (parse_submodule_update_strategy(val, out) < 0) + die(_("Invalid update mode '%s' configured for submodule path '%s'"), + val, path); + } else if (sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) { + trace_printf("loaded thing"); + out->type = sub->update_strategy.type; + out->command = sub->update_strategy.command; + } else + out->type = SM_UPDATE_CHECKOUT; + + if (just_cloned && + (out->type == SM_UPDATE_MERGE || + out->type == SM_UPDATE_REBASE || + out->type == SM_UPDATE_NONE)) + out->type = SM_UPDATE_CHECKOUT; + + free(key); +} + +static int module_update_module_mode(int argc, const char **argv, const char *prefix) +{ + const char *path, *update = NULL; + int just_cloned; + struct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT }; + + if (argc < 3 || argc > 4) + die("submodule--helper update-module-clone expects <just-cloned> <path> [<update>]"); + + just_cloned = git_config_int("just_cloned", argv[1]); + path = argv[2]; + + if (argc == 4) + update = argv[3]; + + determine_submodule_update_strategy(the_repository, + just_cloned, path, update, + &update_strategy); + fputs(submodule_strategy_to_string(&update_strategy), stdout); + + return 0; +} + +struct update_clone_data { + const struct submodule *sub; + struct object_id oid; + unsigned just_cloned; +}; + struct submodule_update_clone { /* index into 'list', the list of submodules to look into for cloning */ int current; @@ -1463,8 +1528,9 @@ struct submodule_update_clone { const char *recursive_prefix; const char *prefix; - /* Machine-readable status lines to be consumed by git-submodule.sh */ - struct string_list projectlines; + /* to be consumed by git-submodule.sh */ + struct update_clone_data *update_clone; + int update_clone_nr; int update_clone_alloc; /* If we want to stop as fast as possible and return an error */ unsigned quickstop : 1; @@ -1472,11 +1538,13 @@ struct submodule_update_clone { /* failed clones to be retried again */ const struct cache_entry **failed_clones; int failed_clones_nr, failed_clones_alloc; + + int max_jobs; }; #define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \ SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \ NULL, NULL, NULL, \ - STRING_LIST_INIT_DUP, 0, NULL, 0, 0} + NULL, 0, 0, 0, NULL, 0, 0, 0} static void next_submodule_warn_missing(struct submodule_update_clone *suc, @@ -1570,11 +1638,12 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, strbuf_addf(&sb, "%s/.git", ce->name); needs_cloning = !file_exists(sb.buf); - strbuf_reset(&sb); - strbuf_addf(&sb, "%06o %s %d %d\t%s\n", ce->ce_mode, - oid_to_hex(&ce->oid), ce_stage(ce), - needs_cloning, ce->name); - string_list_append(&suc->projectlines, sb.buf); + ALLOC_GROW(suc->update_clone, suc->update_clone_nr + 1, + suc->update_clone_alloc); + oidcpy(&suc->update_clone[suc->update_clone_nr].oid, &ce->oid); + suc->update_clone[suc->update_clone_nr].just_cloned = needs_cloning; + suc->update_clone[suc->update_clone_nr].sub = sub; + suc->update_clone_nr++; if (!needs_cloning) goto cleanup; @@ -1706,8 +1775,8 @@ static int update_clone_task_finished(int result, return 0; } -static int gitmodules_update_clone_config(const char *var, const char *value, - void *cb) +static int git_update_clone_config(const char *var, const char *value, + void *cb) { int *max_jobs = cb; if (!strcmp(var, "submodule.fetchjobs")) @@ -1715,11 +1784,44 @@ static int gitmodules_update_clone_config(const char *var, const char *value, return 0; } +static void update_submodule(struct update_clone_data *ucd) +{ + fprintf(stdout, "dummy %s %d\t%s\n", + oid_to_hex(&ucd->oid), + ucd->just_cloned, + ucd->sub->path); +} + +static int update_submodules(struct submodule_update_clone *suc) +{ + int i; + + run_processes_parallel(suc->max_jobs, + update_clone_get_next_task, + update_clone_start_failure, + update_clone_task_finished, + suc); + + /* + * We saved the output and put it out all at once now. + * That means: + * - the listener does not have to interleave their (checkout) + * work with our fetching. The writes involved in a + * checkout involve more straightforward sequential I/O. + * - the listener can avoid doing any work if fetching failed. + */ + if (suc->quickstop) + return 1; + + for (i = 0; i < suc->update_clone_nr; i++) + update_submodule(&suc->update_clone[i]); + + return 0; +} + static int update_clone(int argc, const char **argv, const char *prefix) { const char *update = NULL; - int max_jobs = 1; - struct string_list_item *item; struct pathspec pathspec; struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT; @@ -1741,7 +1843,7 @@ static int update_clone(int argc, const char **argv, const char *prefix) OPT_STRING(0, "depth", &suc.depth, "<depth>", N_("Create a shallow clone truncated to the " "specified number of revisions")), - OPT_INTEGER('j', "jobs", &max_jobs, + OPT_INTEGER('j', "jobs", &suc.max_jobs, N_("parallel jobs")), OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow, N_("whether the initial clone should follow the shallow recommendation")), @@ -1757,8 +1859,8 @@ static int update_clone(int argc, const char **argv, const char *prefix) }; suc.prefix = prefix; - config_from_gitmodules(gitmodules_update_clone_config, &max_jobs); - git_config(gitmodules_update_clone_config, &max_jobs); + update_clone_config_from_gitmodules(&suc.max_jobs); + git_config(git_update_clone_config, &suc.max_jobs); argc = parse_options(argc, argv, prefix, module_update_clone_options, git_submodule_helper_usage, 0); @@ -1773,27 +1875,7 @@ static int update_clone(int argc, const char **argv, const char *prefix) if (pathspec.nr) suc.warn_if_uninitialized = 1; - run_processes_parallel(max_jobs, - update_clone_get_next_task, - update_clone_start_failure, - update_clone_task_finished, - &suc); - - /* - * We saved the output and put it out all at once now. - * That means: - * - the listener does not have to interleave their (checkout) - * work with our fetching. The writes involved in a - * checkout involve more straightforward sequential I/O. - * - the listener can avoid doing any work if fetching failed. - */ - if (suc.quickstop) - return 1; - - for_each_string_list_item(item, &suc.projectlines) - fprintf(stdout, "%s", item->string); - - return 0; + return update_submodules(&suc); } static int resolve_relative_path(int argc, const char **argv, const char *prefix) @@ -1939,6 +2021,45 @@ static int push_check(int argc, const char **argv, const char *prefix) return 0; } +static int ensure_core_worktree(int argc, const char **argv, const char *prefix) +{ + const struct submodule *sub; + const char *path; + char *cw; + struct repository subrepo; + + if (argc != 2) + BUG("submodule--helper connect-gitdir-workingtree <name> <path>"); + + path = argv[1]; + + sub = submodule_from_path(the_repository, &null_oid, path); + if (!sub) + BUG("We could get the submodule handle before?"); + + if (repo_submodule_init(&subrepo, the_repository, path)) + die(_("could not get a repository handle for submodule '%s'"), path); + + if (!repo_config_get_string(&subrepo, "core.worktree", &cw)) { + char *cfg_file, *abs_path; + const char *rel_path; + struct strbuf sb = STRBUF_INIT; + + cfg_file = repo_git_path(&subrepo, "config"); + + abs_path = absolute_pathdup(path); + rel_path = relative_path(abs_path, subrepo.gitdir, &sb); + + git_config_set_in_file(cfg_file, "core.worktree", rel_path); + + free(cfg_file); + free(abs_path); + strbuf_release(&sb); + } + + return 0; +} + static int absorb_git_dirs(int argc, const char **argv, const char *prefix) { int i; @@ -2016,7 +2137,9 @@ static struct cmd_struct commands[] = { {"list", module_list, 0}, {"name", module_name, 0}, {"clone", module_clone, 0}, + {"update-module-mode", module_update_module_mode, 0}, {"update-clone", update_clone, 0}, + {"ensure-core-worktree", ensure_core_worktree, 0}, {"relative-path", resolve_relative_path, 0}, {"resolve-relative-url", resolve_relative_url, 0}, {"resolve-relative-url-test", resolve_relative_url_test, 0}, diff --git a/builtin/tag.c b/builtin/tag.c index 5d0dd11240..9a19ffb49f 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -10,6 +10,7 @@ #include "config.h" #include "builtin.h" #include "refs.h" +#include "object-store.h" #include "tag.h" #include "run-command.h" #include "parse-options.h" @@ -312,7 +313,7 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb) } free(buf); - if ((c = lookup_commit_reference(oid)) != NULL) + if ((c = lookup_commit_reference(the_repository, oid)) != NULL) strbuf_addf(sb, ", %s", show_date(c->date, 0, DATE_MODE(SHORT))); break; case OBJ_TREE: diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c index 300eb59657..58652229f2 100644 --- a/builtin/unpack-file.c +++ b/builtin/unpack-file.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "config.h" +#include "object-store.h" static char *create_temp_file(struct object_id *oid) { diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index 6e81ca8ca2..30d9413b4b 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "cache.h" #include "config.h" +#include "object-store.h" #include "object.h" #include "delta.h" #include "pack.h" @@ -253,7 +254,7 @@ static void write_object(unsigned nr, enum object_type type, added_object(nr, type, buf, size); free(buf); - blob = lookup_blob(&obj_list[nr].oid); + blob = lookup_blob(the_repository, &obj_list[nr].oid); if (blob) blob->object.flags |= FLAG_WRITTEN; else @@ -264,7 +265,8 @@ static void write_object(unsigned nr, enum object_type type, int eaten; hash_object_file(buf, size, type_name(type), &obj_list[nr].oid); added_object(nr, type, buf, size); - obj = parse_object_buffer(&obj_list[nr].oid, type, size, buf, + obj = parse_object_buffer(the_repository, &obj_list[nr].oid, + type, size, buf, &eaten); if (!obj) die("invalid %s", type_name(type)); @@ -330,7 +332,7 @@ static int resolve_against_held(unsigned nr, const struct object_id *base, { struct object *obj; struct obj_buffer *obj_buffer; - obj = lookup_object(base->hash); + obj = lookup_object(the_repository, base->hash); if (!obj) return 0; obj_buffer = lookup_object_buffer(obj); @@ -512,7 +514,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix) int i; struct object_id oid; - check_replace_refs = 0; + read_replace_refs = 0; git_config(git_default_config, NULL); diff --git a/builtin/update-index.c b/builtin/update-index.c index a8709a26ec..fe84003b4f 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -268,15 +268,14 @@ static int process_lstat_error(const char *path, int err) static int add_one_path(const struct cache_entry *old, const char *path, int len, struct stat *st) { - int option, size; + int option; struct cache_entry *ce; /* Was the old index entry already up-to-date? */ if (old && !ce_stage(old) && !ce_match_stat(old, st, 0)) return 0; - size = cache_entry_size(len); - ce = xcalloc(1, size); + ce = make_empty_cache_entry(&the_index, len); memcpy(ce->name, path, len); ce->ce_flags = create_ce_flags(0); ce->ce_namelen = len; @@ -285,13 +284,13 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len if (index_path(&ce->oid, path, st, info_only ? 0 : HASH_WRITE_OBJECT)) { - free(ce); + 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_cache_entry(ce, option)) { - free(ce); + discard_cache_entry(ce); return error("%s: cannot add to the index - missing --add option?", path); } return 0; @@ -402,15 +401,14 @@ static int process_path(const char *path, struct stat *st, int stat_errno) static int add_cacheinfo(unsigned int mode, const struct object_id *oid, const char *path, int stage) { - int size, len, option; + int len, option; struct cache_entry *ce; if (!verify_path(path, mode)) return error("Invalid path '%s'", path); len = strlen(path); - size = cache_entry_size(len); - ce = xcalloc(1, size); + ce = make_empty_cache_entry(&the_index, len); oidcpy(&ce->oid, oid); memcpy(ce->name, path, len); @@ -492,6 +490,7 @@ static void update_one(const char *path) static void read_index_info(int nul_term_line) { + const int hexsz = the_hash_algo->hexsz; struct strbuf buf = STRBUF_INIT; struct strbuf uq = STRBUF_INIT; strbuf_getline_fn getline_fn; @@ -529,7 +528,7 @@ static void read_index_info(int nul_term_line) mode = ul; tab = strchr(ptr, '\t'); - if (!tab || tab - ptr < GIT_SHA1_HEXSZ + 1) + if (!tab || tab - ptr < hexsz + 1) goto bad_line; if (tab[-2] == ' ' && '0' <= tab[-1] && tab[-1] <= '3') { @@ -542,8 +541,8 @@ static void read_index_info(int nul_term_line) ptr = tab + 1; /* point at the head of path */ } - if (get_oid_hex(tab - GIT_SHA1_HEXSZ, &oid) || - tab[-(GIT_SHA1_HEXSZ + 1)] != ' ') + if (get_oid_hex(tab - hexsz, &oid) || + tab[-(hexsz + 1)] != ' ') goto bad_line; path_name = ptr; @@ -571,7 +570,7 @@ static void read_index_info(int nul_term_line) * ptr[-1] points at tab, * ptr[-41] is at the beginning of sha1 */ - ptr[-(GIT_SHA1_HEXSZ + 2)] = ptr[-1] = 0; + ptr[-(hexsz + 2)] = ptr[-1] = 0; if (add_cacheinfo(mode, &oid, path_name, stage)) die("git update-index: unable to update %s", path_name); @@ -599,7 +598,6 @@ static struct cache_entry *read_one_ent(const char *which, { unsigned mode; struct object_id oid; - int size; struct cache_entry *ce; if (get_tree_entry(ent, path, &oid, &mode)) { @@ -612,8 +610,7 @@ static struct cache_entry *read_one_ent(const char *which, error("%s: not a blob in %s branch.", path, which); return NULL; } - size = cache_entry_size(namelen); - ce = xcalloc(1, size); + ce = make_empty_cache_entry(&the_index, namelen); oidcpy(&ce->oid, &oid); memcpy(ce->name, path, namelen); @@ -690,8 +687,8 @@ static int unresolve_one(const char *path) error("%s: cannot add their version to the index.", path); ret = -1; free_return: - free(ce_2); - free(ce_3); + discard_cache_entry(ce_2); + discard_cache_entry(ce_3); return ret; } @@ -751,14 +748,14 @@ static int do_reupdate(int ac, const char **av, int save_nr; char *path; - if (ce_stage(ce) || !ce_path_match(ce, &pathspec, NULL)) + if (ce_stage(ce) || !ce_path_match(&the_index, ce, &pathspec, NULL)) continue; if (has_head) old = read_one_ent(NULL, &head_oid, ce->name, ce_namelen(ce), 0); if (old && ce->ce_mode == old->ce_mode && !oidcmp(&ce->oid, &old->oid)) { - free(old); + discard_cache_entry(old); continue; /* unchanged */ } /* Be careful. The working tree may not have the @@ -769,7 +766,7 @@ static int do_reupdate(int ac, const char **av, path = xstrdup(ce->name); update_one(path); free(path); - free(old); + discard_cache_entry(old); if (save_nr != active_nr) goto redo; } @@ -826,6 +823,7 @@ static int parse_new_style_cacheinfo(const char *arg, { unsigned long ul; char *endp; + const char *p; if (!arg) return -1; @@ -836,9 +834,9 @@ static int parse_new_style_cacheinfo(const char *arg, return -1; /* not a new-style cacheinfo */ *mode = ul; endp++; - if (get_oid_hex(endp, oid) || endp[GIT_SHA1_HEXSZ] != ',') + if (parse_oid_hex(endp, oid, &p) || *p != ',') return -1; - *path = endp + GIT_SHA1_HEXSZ + 1; + *path = p + 1; return 0; } @@ -971,9 +969,9 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */ PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, (parse_opt_cb *) cacheinfo_callback}, - {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, N_("(+/-)x"), + {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, "(+|-)x", N_("override the executable bit of the listed files"), - PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, + PARSE_OPT_NONEG, chmod_callback}, {OPTION_SET_INT, 0, "assume-unchanged", &mark_valid_only, NULL, N_("mark files as \"not changing\""), diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c index 84532ae9a9..25d9116356 100644 --- a/builtin/upload-archive.c +++ b/builtin/upload-archive.c @@ -43,7 +43,8 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix) } /* parse all options sent by the client */ - return write_archive(sent_argv.argc, sent_argv.argv, prefix, NULL, 1); + return write_archive(sent_argv.argc, sent_argv.argv, prefix, + the_repository, NULL, 1); } __attribute__((format (printf, 1, 2))) diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c index decde5a3b1..42dc4da5a1 100644 --- a/builtin/upload-pack.c +++ b/builtin/upload-pack.c @@ -31,7 +31,7 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix) }; packet_trace_identity("upload-pack"); - check_replace_refs = 0; + read_replace_refs = 0; argc = parse_options(argc, argv, NULL, options, upload_pack_usage, 0); diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c index dcdaada111..7772c07ed7 100644 --- a/builtin/verify-commit.c +++ b/builtin/verify-commit.c @@ -8,6 +8,8 @@ #include "cache.h" #include "config.h" #include "builtin.h" +#include "object-store.h" +#include "repository.h" #include "commit.h" #include "run-command.h" #include <signal.h> @@ -26,7 +28,8 @@ static int run_gpg_verify(const struct object_id *oid, const char *buf, unsigned memset(&signature_check, 0, sizeof(signature_check)); - ret = check_commit_signature(lookup_commit(oid), &signature_check); + ret = check_commit_signature(lookup_commit(the_repository, oid), + &signature_check); print_signature_buffer(&signature_check, flags); signature_check_clear(&signature_check); diff --git a/builtin/worktree.c b/builtin/worktree.c index 5c7d2bb180..41e7714396 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -27,6 +27,7 @@ static const char * const worktree_usage[] = { struct add_opts { int force; int detach; + int quiet; int checkout; int keep_locked; }; @@ -303,9 +304,13 @@ static int add_worktree(const char *path, const char *refname, if (!is_branch) argv_array_pushl(&cp.args, "update-ref", "HEAD", oid_to_hex(&commit->object.oid), NULL); - else + else { argv_array_pushl(&cp.args, "symbolic-ref", "HEAD", symref.buf, NULL); + if (opts->quiet) + argv_array_push(&cp.args, "--quiet"); + } + cp.env = child_env.argv; ret = run_command(&cp); if (ret) @@ -315,6 +320,8 @@ static int add_worktree(const char *path, const char *refname, cp.argv = NULL; argv_array_clear(&cp.args); argv_array_pushl(&cp.args, "reset", "--hard", NULL); + if (opts->quiet) + argv_array_push(&cp.args, "--quiet"); cp.env = child_env.argv; ret = run_command(&cp); if (ret) @@ -412,7 +419,7 @@ static const char *dwim_branch(const char *path, const char **new_branch) if (guess_remote) { struct object_id oid; const char *remote = - unique_tracking_name(*new_branch, &oid); + unique_tracking_name(*new_branch, &oid, NULL); return remote; } return NULL; @@ -437,6 +444,7 @@ static int add(int ac, const char **av, const char *prefix) OPT_BOOL(0, "detach", &opts.detach, N_("detach HEAD at named commit")), OPT_BOOL(0, "checkout", &opts.checkout, N_("populate the new working tree")), OPT_BOOL(0, "lock", &opts.keep_locked, N_("keep the new working tree locked")), + OPT__QUIET(&opts.quiet, N_("suppress progress reporting")), OPT_PASSTHRU(0, "track", &opt_track, NULL, N_("set up tracking mode (see git-branch(1))"), PARSE_OPT_NOARG | PARSE_OPT_OPTARG), @@ -484,15 +492,15 @@ static int add(int ac, const char **av, const char *prefix) commit = lookup_commit_reference_by_name(branch); if (!commit) { - remote = unique_tracking_name(branch, &oid); + remote = unique_tracking_name(branch, &oid, NULL); if (remote) { new_branch = branch; branch = remote; } } } - - print_preparing_worktree_line(opts.detach, branch, new_branch, !!new_branch_force); + if (!opts.quiet) + print_preparing_worktree_line(opts.detach, branch, new_branch, !!new_branch_force); if (new_branch) { struct child_process cp = CHILD_PROCESS_INIT; @@ -500,6 +508,8 @@ static int add(int ac, const char **av, const char *prefix) argv_array_push(&cp.args, "branch"); if (new_branch_force) argv_array_push(&cp.args, "--force"); + if (opts.quiet) + argv_array_push(&cp.args, "--quiet"); argv_array_push(&cp.args, new_branch); argv_array_push(&cp.args, branch); if (opt_track) diff --git a/builtin/write-tree.c b/builtin/write-tree.c index c9d3c544e7..cdcbf8264e 100644 --- a/builtin/write-tree.c +++ b/builtin/write-tree.c @@ -24,9 +24,8 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix) struct option write_tree_options[] = { OPT_BIT(0, "missing-ok", &flags, N_("allow missing objects"), WRITE_TREE_MISSING_OK), - { OPTION_STRING, 0, "prefix", &prefix, N_("<prefix>/"), - N_("write tree object for a subdirectory <prefix>") , - PARSE_OPT_LITERAL_ARGHELP }, + OPT_STRING(0, "prefix", &prefix, N_("<prefix>/"), + N_("write tree object for a subdirectory <prefix>")), { OPTION_BIT, 0, "ignore-cache-tree", &flags, NULL, N_("only useful for debugging"), PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, NULL, |