diff options
Diffstat (limited to 'builtin')
68 files changed, 930 insertions, 322 deletions
diff --git a/builtin/add.c b/builtin/add.c index bf01d89e28..c9e2619a9a 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -9,7 +9,7 @@ #include "lockfile.h" #include "dir.h" #include "pathspec.h" -#include "exec_cmd.h" +#include "exec-cmd.h" #include "cache-tree.h" #include "run-command.h" #include "parse-options.h" @@ -294,7 +294,7 @@ static struct option builtin_add_options[] = { OPT_BOOL('i', "interactive", &add_interactive, N_("interactive picking")), OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")), OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")), - OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files")), + OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files"), 0), OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")), OPT_BOOL(0, "renormalize", &add_renormalize, N_("renormalize EOL of tracked files (implies -u)")), OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")), @@ -534,10 +534,9 @@ int cmd_add(int argc, const char **argv, const char *prefix) unplug_bulk_checkin(); finish: - if (active_cache_changed) { - if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) - die(_("Unable to write new index file")); - } + if (write_locked_index(&the_index, &lock_file, + COMMIT_LOCK | SKIP_IF_UNCHANGED)) + die(_("Unable to write new index file")); UNLEAK(pathspec); UNLEAK(dir); diff --git a/builtin/am.c b/builtin/am.c index 1151b5c73a..d834f9e62b 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -6,7 +6,7 @@ #include "cache.h" #include "config.h" #include "builtin.h" -#include "exec_cmd.h" +#include "exec-cmd.h" #include "parse-options.h" #include "dir.h" #include "run-command.h" @@ -1550,7 +1550,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa discard_cache(); read_cache_from(index_path); - if (write_index_as_tree(orig_tree.hash, &the_index, index_path, 0, NULL)) + if (write_index_as_tree(&orig_tree, &the_index, index_path, 0, NULL)) return error(_("Repository lacks necessary blobs to fall back on 3-way merge.")); say(state, stdout, _("Using index info to reconstruct a base tree...")); @@ -1575,7 +1575,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa return error(_("Did you hand edit your patch?\n" "It does not apply to blobs recorded in its index.")); - if (write_index_as_tree(their_tree.hash, &the_index, index_path, 0, NULL)) + if (write_index_as_tree(&their_tree, &the_index, index_path, 0, NULL)) return error("could not write tree"); say(state, stdout, _("Falling back to patching base and 3-way merge...")); @@ -1626,7 +1626,7 @@ static void do_commit(const struct am_state *state) if (run_hook_le(NULL, "pre-applypatch", NULL)) exit(1); - if (write_cache_as_tree(tree.hash, 0, NULL)) + if (write_cache_as_tree(&tree, 0, NULL)) die(_("git write-tree failed to write a tree")); if (!get_oid_commit("HEAD", &parent)) { @@ -1862,7 +1862,7 @@ next: */ if (!state->rebasing) { am_destroy(state); - close_all_packs(); + close_all_packs(the_repository->objects); run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); } } @@ -2004,7 +2004,7 @@ static int clean_index(const struct object_id *head, const struct object_id *rem if (fast_forward_to(head_tree, head_tree, 1)) return -1; - if (write_cache_as_tree(index.hash, 0, NULL)) + if (write_cache_as_tree(&index, 0, NULL)) return -1; index_tree = parse_tree_indirect(&index); diff --git a/builtin/blame.c b/builtin/blame.c index 9dcb367b90..db38c0b307 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -499,7 +499,7 @@ static int read_ancestry(const char *graft_file) static int update_auto_abbrev(int auto_abbrev, struct blame_origin *suspect) { - const char *uniq = find_unique_abbrev(suspect->commit->object.oid.hash, + const char *uniq = find_unique_abbrev(&suspect->commit->object.oid, auto_abbrev); int len = strlen(uniq); if (auto_abbrev < len) @@ -655,7 +655,7 @@ static int is_a_rev(const char *name) if (get_oid(name, &oid)) return 0; - return OBJ_NONE < sha1_object_info(oid.hash, NULL); + return OBJ_NONE < oid_object_info(&oid, NULL); } int cmd_blame(int argc, const char **argv, const char *prefix) @@ -729,6 +729,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) for (;;) { switch (parse_options_step(&ctx, options, blame_opt_usage)) { case PARSE_OPT_HELP: + case PARSE_OPT_ERROR: exit(129); case PARSE_OPT_DONE: if (ctx.argv[0]) diff --git a/builtin/branch.c b/builtin/branch.c index 8dcc2ed058..efc9ac1922 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -273,7 +273,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, bname.buf, (flags & REF_ISBROKEN) ? "broken" : (flags & REF_ISSYMREF) ? target - : find_unique_abbrev(oid.hash, DEFAULT_ABBREV)); + : find_unique_abbrev(&oid, DEFAULT_ABBREV)); } delete_branch_config(bname.buf); @@ -391,7 +391,6 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin struct ref_array array; int maxwidth = 0; const char *remote_prefix = ""; - struct strbuf out = STRBUF_INIT; char *to_free = NULL; /* @@ -419,7 +418,10 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin ref_array_sort(sorting, &array); for (i = 0; i < array.nr; i++) { - format_ref_array_item(array.items[i], format, &out); + struct strbuf out = STRBUF_INIT; + struct strbuf err = STRBUF_INIT; + if (format_ref_array_item(array.items[i], format, &out, &err)) + die("%s", err.buf); if (column_active(colopts)) { assert(!filter->verbose && "--column and --verbose are incompatible"); /* format to a string_list to let print_columns() do its job */ @@ -428,6 +430,7 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin fwrite(out.buf, 1, out.len, stdout); putchar('\n'); } + strbuf_release(&err); strbuf_release(&out); } @@ -615,7 +618,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPT_BOOL('l', "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")), + OPT__FORCE(&force, N_("force creation, move/rename, deletion"), PARSE_OPT_NOCOMPLETE), OPT_MERGED(&filter, N_("print only branches that are merged")), OPT_NO_MERGED(&filter, N_("print only branches that are not merged")), OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")), diff --git a/builtin/cat-file.c b/builtin/cat-file.c index d90170f070..2c46d257cd 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -32,7 +32,7 @@ static int filter_object(const char *path, unsigned mode, { enum object_type type; - *buf = read_sha1_file(oid->hash, &type, size); + *buf = read_object_file(oid, &type, size); if (!*buf) return error(_("cannot read object %s '%s'"), oid_to_hex(oid), path); @@ -77,7 +77,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, switch (opt) { case 't': oi.type_name = &sb; - if (sha1_object_info_extended(oid.hash, &oi, flags) < 0) + if (oid_object_info_extended(&oid, &oi, flags) < 0) die("git cat-file: could not get object info"); if (sb.len) { printf("%s\n", sb.buf); @@ -88,7 +88,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, case 's': oi.sizep = &size; - if (sha1_object_info_extended(oid.hash, &oi, flags) < 0) + if (oid_object_info_extended(&oid, &oi, flags) < 0) die("git cat-file: could not get object info"); printf("%lu\n", size); return 0; @@ -116,7 +116,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, /* else fallthrough */ case 'p': - type = sha1_object_info(oid.hash, NULL); + type = oid_object_info(&oid, NULL); if (type < 0) die("Not a valid object name %s", obj_name); @@ -130,7 +130,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, if (type == OBJ_BLOB) return stream_blob_to_fd(1, &oid, NULL, 0); - buf = read_sha1_file(oid.hash, &type, &size); + buf = read_object_file(&oid, &type, &size); if (!buf) die("Cannot read object %s", obj_name); @@ -140,8 +140,9 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, case 0: if (type_from_string(exp_type) == OBJ_BLOB) { struct object_id blob_oid; - if (sha1_object_info(oid.hash, NULL) == OBJ_TAG) { - char *buffer = read_sha1_file(oid.hash, &type, &size); + if (oid_object_info(&oid, NULL) == OBJ_TAG) { + char *buffer = read_object_file(&oid, &type, + &size); const char *target; if (!skip_prefix(buffer, "object ", &target) || get_oid_hex(target, &blob_oid)) @@ -150,7 +151,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, } else oidcpy(&blob_oid, &oid); - if (sha1_object_info(blob_oid.hash, NULL) == OBJ_BLOB) + if (oid_object_info(&blob_oid, NULL) == OBJ_BLOB) return stream_blob_to_fd(1, &blob_oid, NULL, 0); /* * we attempted to dereference a tag to a blob @@ -159,7 +160,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, * fall-back to the usual case. */ } - buf = read_object_with_reference(oid.hash, exp_type, &size, NULL); + buf = read_object_with_reference(&oid, exp_type, &size, NULL); break; default: @@ -304,8 +305,9 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d enum object_type type; if (!textconv_object(data->rest, 0100644, oid, 1, &contents, &size)) - contents = read_sha1_file(oid->hash, &type, - &size); + contents = read_object_file(oid, + &type, + &size); if (!contents) die("could not convert '%s' %s", oid_to_hex(oid), data->rest); @@ -321,7 +323,7 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d unsigned long size; void *contents; - contents = read_sha1_file(oid->hash, &type, &size); + contents = read_object_file(oid, &type, &size); if (!contents) die("object %s disappeared", oid_to_hex(oid)); if (type != data->type) @@ -340,8 +342,8 @@ static void batch_object_write(const char *obj_name, struct batch_options *opt, struct strbuf buf = STRBUF_INIT; if (!data->skip_object_info && - sha1_object_info_extended(data->oid.hash, &data->info, - OBJECT_INFO_LOOKUP_REPLACE) < 0) { + oid_object_info_extended(&data->oid, &data->info, + OBJECT_INFO_LOOKUP_REPLACE) < 0) { printf("%s missing\n", obj_name ? obj_name : oid_to_hex(&data->oid)); fflush(stdout); diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index b0e78b819d..a730f6a1aa 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -157,7 +157,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) struct option builtin_checkout_index_options[] = { OPT_BOOL('a', "all", &all, N_("check out all files in the index")), - OPT__FORCE(&force, N_("force overwrite of existing files")), + OPT__FORCE(&force, N_("force overwrite of existing files"), 0), OPT__QUIET(&quiet, N_("no warning for existing files and files not in index")), OPT_BOOL('n', "no-create", ¬_new, diff --git a/builtin/checkout.c b/builtin/checkout.c index 8f4dfb1046..b49b582071 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -66,7 +66,7 @@ static int post_checkout_hook(struct commit *old_commit, struct commit *new_comm } -static int update_some(const unsigned char *sha1, struct strbuf *base, +static int update_some(const struct object_id *oid, struct strbuf *base, const char *pathname, unsigned mode, int stage, void *context) { int len; @@ -78,7 +78,7 @@ static int update_some(const unsigned char *sha1, struct strbuf *base, len = base->len + strlen(pathname); ce = xcalloc(1, cache_entry_size(len)); - hashcpy(ce->oid.hash, sha1); + oidcpy(&ce->oid, oid); memcpy(ce->name, base->buf, base->len); memcpy(ce->name + base->len, pathname, len - base->len); ce->ce_flags = create_ce_flags(0) | CE_UPDATE; @@ -405,10 +405,10 @@ static void describe_detached_head(const char *msg, struct commit *commit) pp_commit_easy(CMIT_FMT_ONELINE, commit, &sb); if (print_sha1_ellipsis()) { fprintf(stderr, "%s %s... %s\n", msg, - find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV), sb.buf); + find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV), sb.buf); } else { fprintf(stderr, "%s %s %s\n", msg, - find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV), sb.buf); + find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV), sb.buf); } strbuf_release(&sb); } @@ -720,7 +720,7 @@ static int add_pending_uninteresting_ref(const char *refname, static void describe_one_orphan(struct strbuf *sb, struct commit *commit) { strbuf_addstr(sb, " "); - strbuf_add_unique_abbrev(sb, commit->object.oid.hash, DEFAULT_ABBREV); + strbuf_add_unique_abbrev(sb, &commit->object.oid, DEFAULT_ABBREV); strbuf_addch(sb, ' '); if (!parse_commit(commit)) pp_commit_easy(CMIT_FMT_ONELINE, commit, sb); @@ -778,7 +778,7 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs) " git branch <new-branch-name> %s\n\n", /* Give ngettext() the count */ lost), - find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV)); + find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV)); } /* @@ -1117,9 +1117,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) 2), OPT_SET_INT('3', "theirs", &opts.writeout_stage, N_("checkout their version for unmerged files"), 3), - OPT__FORCE(&opts.force, N_("force checkout (throw away local modifications)")), + OPT__FORCE(&opts.force, N_("force checkout (throw away local modifications)"), + PARSE_OPT_NOCOMPLETE), OPT_BOOL('m', "merge", &opts.merge, N_("perform a 3-way merge with the new branch")), - OPT_BOOL(0, "overwrite-ignore", &opts.overwrite_ignore, N_("update ignored files (default)")), + OPT_BOOL_F(0, "overwrite-ignore", &opts.overwrite_ignore, + N_("update ignored files (default)"), + PARSE_OPT_NOCOMPLETE), OPT_STRING(0, "conflict", &conflict_style, N_("style"), N_("conflict style (merge or diff3)")), OPT_BOOL('p', "patch", &opts.patch_mode, N_("select hunks interactively")), diff --git a/builtin/clean.c b/builtin/clean.c index 189e20628c..fad533a0a7 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -909,7 +909,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) struct option options[] = { OPT__QUIET(&quiet, N_("do not print names of files removed")), OPT__DRY_RUN(&dry_run, N_("dry run")), - OPT__FORCE(&force, N_("force")), + OPT__FORCE(&force, N_("force"), PARSE_OPT_NOCOMPLETE), OPT_BOOL('i', "interactive", &interactive, N_("interactive cleaning")), OPT_BOOL('d', NULL, &remove_directories, N_("remove whole directories")), diff --git a/builtin/clone.c b/builtin/clone.c index 101c27a593..84f1473d19 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -27,6 +27,7 @@ #include "connected.h" #include "packfile.h" #include "list-objects-filter-options.h" +#include "object-store.h" /* * Overall FIXMEs: @@ -1134,7 +1135,7 @@ 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); + refs = transport_get_remote_refs(transport, NULL); if (refs) { mapped_refs = wanted_peer_refs(refs, refspec); @@ -1217,7 +1218,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) transport_disconnect(transport); if (option_dissociate) { - close_all_packs(); + close_all_packs(the_repository->objects); dissociate_from_references(); } diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c new file mode 100644 index 0000000000..37420ae0fd --- /dev/null +++ b/builtin/commit-graph.c @@ -0,0 +1,171 @@ +#include "builtin.h" +#include "config.h" +#include "dir.h" +#include "lockfile.h" +#include "parse-options.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]"), + NULL +}; + +static const char * const builtin_commit_graph_read_usage[] = { + N_("git commit-graph read [--object-dir <objdir>]"), + NULL +}; + +static const char * const builtin_commit_graph_write_usage[] = { + N_("git commit-graph write [--object-dir <objdir>] [--append] [--stdin-packs|--stdin-commits]"), + NULL +}; + +static struct opts_commit_graph { + const char *obj_dir; + int stdin_packs; + int stdin_commits; + int append; +} opts; + +static int graph_read(int argc, const char **argv) +{ + struct commit_graph *graph = NULL; + char *graph_name; + + static struct option builtin_commit_graph_read_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_read_options, + builtin_commit_graph_read_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); + + if (!graph) + die("graph file %s does not exist", graph_name); + FREE_AND_NULL(graph_name); + + printf("header: %08x %d %d %d %d\n", + ntohl(*(uint32_t*)graph->data), + *(unsigned char*)(graph->data + 4), + *(unsigned char*)(graph->data + 5), + *(unsigned char*)(graph->data + 6), + *(unsigned char*)(graph->data + 7)); + printf("num_commits: %u\n", graph->num_commits); + printf("chunks:"); + + if (graph->chunk_oid_fanout) + printf(" oid_fanout"); + if (graph->chunk_oid_lookup) + printf(" oid_lookup"); + if (graph->chunk_commit_data) + printf(" commit_metadata"); + if (graph->chunk_large_edges) + printf(" large_edges"); + printf("\n"); + + 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; + + 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, "stdin-packs", &opts.stdin_packs, + N_("scan pack-indexes listed by stdin for commits")), + OPT_BOOL(0, "stdin-commits", &opts.stdin_commits, + N_("start walk at commits listed by stdin")), + OPT_BOOL(0, "append", &opts.append, + N_("include all commits already in the commit-graph file")), + OPT_END(), + }; + + argc = parse_options(argc, argv, NULL, + 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.obj_dir) + opts.obj_dir = get_object_directory(); + + 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; + } + } + + write_commit_graph(opts.obj_dir, + pack_indexes, + packs_nr, + commit_hex, + commits_nr, + opts.append); + + return 0; +} + +int cmd_commit_graph(int argc, const char **argv, const char *prefix) +{ + static struct option builtin_commit_graph_options[] = { + OPT_STRING(0, "object-dir", &opts.obj_dir, + N_("dir"), + N_("The object directory to store the graph")), + OPT_END(), + }; + + if (argc == 2 && !strcmp(argv[1], "-h")) + usage_with_options(builtin_commit_graph_usage, + builtin_commit_graph_options); + + git_config(git_default_config, NULL); + argc = parse_options(argc, argv, prefix, + builtin_commit_graph_options, + builtin_commit_graph_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + + if (argc > 0) { + if (!strcmp(argv[0], "read")) + return graph_read(argc, argv); + if (!strcmp(argv[0], "write")) + return graph_write(argc, argv); + } + + usage_with_options(builtin_commit_graph_usage, + builtin_commit_graph_options); +} diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index e5bdf57b1e..ecf42191da 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -58,7 +58,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) usage(commit_tree_usage); if (get_oid_commit(argv[i], &oid)) die("Not a valid object name %s", argv[i]); - assert_sha1_type(oid.hash, OBJ_COMMIT); + assert_oid_type(&oid, OBJ_COMMIT); new_parent(lookup_commit(&oid), &parents); continue; } diff --git a/builtin/commit.c b/builtin/commit.c index 092077c3ee..5571d4a3e2 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -218,8 +218,7 @@ static int list_paths(struct string_list *list, const char *with_tree, if (with_tree) { char *max_prefix = common_prefix(pattern); - overlay_tree_on_index(&the_index, with_tree, - max_prefix ? max_prefix : prefix); + overlay_tree_on_index(&the_index, with_tree, max_prefix); free(max_prefix); } @@ -389,13 +388,9 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix if (active_cache_changed || !cache_tree_fully_valid(active_cache_tree)) update_main_cache_tree(WRITE_TREE_SILENT); - if (active_cache_changed) { - if (write_locked_index(&the_index, &index_lock, - COMMIT_LOCK)) - die(_("unable to write new_index file")); - } else { - rollback_lock_file(&index_lock); - } + if (write_locked_index(&the_index, &index_lock, + COMMIT_LOCK | SKIP_IF_UNCHANGED)) + die(_("unable to write new_index file")); commit_style = COMMIT_AS_IS; ret = get_index_file(); goto out; diff --git a/builtin/config.c b/builtin/config.c index ab5f95476e..01169dd628 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -48,6 +48,13 @@ static int show_origin; #define ACTION_GET_COLORBOOL (1<<14) #define ACTION_GET_URLMATCH (1<<15) +/* + * The actions "ACTION_LIST | ACTION_GET_*" which may produce more than + * one line of output and which should therefore be paged. + */ +#define PAGING_ACTIONS (ACTION_LIST | ACTION_GET_ALL | \ + ACTION_GET_REGEXP | ACTION_GET_URLMATCH) + #define TYPE_BOOL (1<<0) #define TYPE_INT (1<<1) #define TYPE_BOOL_OR_INT (1<<2) @@ -594,6 +601,9 @@ int cmd_config(int argc, const char **argv, const char *prefix) usage_with_options(builtin_config_usage, builtin_config_options); } + if (actions & PAGING_ACTIONS) + setup_auto_pager("config", 1); + if (actions == ACTION_LIST) { check_argc(argc, 0, 0); if (config_with_options(show_all_config, NULL, diff --git a/builtin/count-objects.c b/builtin/count-objects.c index 33343818c8..b054713e1a 100644 --- a/builtin/count-objects.c +++ b/builtin/count-objects.c @@ -7,10 +7,12 @@ #include "cache.h" #include "config.h" #include "dir.h" +#include "repository.h" #include "builtin.h" #include "parse-options.h" #include "quote.h" #include "packfile.h" +#include "object-store.h" static unsigned long garbage; static off_t size_garbage; @@ -120,9 +122,8 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix) struct strbuf loose_buf = STRBUF_INIT; struct strbuf pack_buf = STRBUF_INIT; struct strbuf garbage_buf = STRBUF_INIT; - if (!packed_git) - prepare_packed_git(); - for (p = packed_git; p; p = p->next) { + + for (p = get_packed_git(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 e4869df7b4..b5afc45846 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -6,7 +6,7 @@ #include "blob.h" #include "refs.h" #include "builtin.h" -#include "exec_cmd.h" +#include "exec-cmd.h" #include "parse-options.h" #include "revision.h" #include "diff.h" @@ -285,7 +285,7 @@ static void append_name(struct commit_name *n, struct strbuf *dst) static void append_suffix(int depth, const struct object_id *oid, struct strbuf *dst) { - strbuf_addf(dst, "-%d-g%s", depth, find_unique_abbrev(oid->hash, abbrev)); + strbuf_addf(dst, "-%d-g%s", depth, find_unique_abbrev(oid, abbrev)); } static void describe_commit(struct object_id *oid, struct strbuf *dst) @@ -383,7 +383,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst) if (!match_cnt) { struct object_id *cmit_oid = &cmit->object.oid; if (always) { - strbuf_add_unique_abbrev(dst, cmit_oid->hash, abbrev); + strbuf_add_unique_abbrev(dst, cmit_oid, abbrev); if (suffix) strbuf_addstr(dst, suffix); return; @@ -502,7 +502,7 @@ static void describe(const char *arg, int last_one) if (cmit) describe_commit(&oid, &sb); - else if (sha1_object_info(oid.hash, NULL) == OBJ_BLOB) + else if (oid_object_info(&oid, NULL) == OBJ_BLOB) describe_blob(oid, &sb); else die(_("%s is neither a commit nor blob"), arg); diff --git a/builtin/difftool.c b/builtin/difftool.c index bcc79d1888..aad0e073ee 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -15,7 +15,7 @@ #include "config.h" #include "builtin.h" #include "run-command.h" -#include "exec_cmd.h" +#include "exec-cmd.h" #include "parse-options.h" #include "argv-array.h" #include "strbuf.h" @@ -306,7 +306,7 @@ static char *get_symlink(const struct object_id *oid, const char *path) } else { enum object_type type; unsigned long size; - data = read_sha1_file(oid->hash, &type, &size); + data = read_object_file(oid, &type, &size); if (!data) die(_("could not read object %s for symlink %s"), oid_to_hex(oid), path); diff --git a/builtin/fast-export.c b/builtin/fast-export.c index 27b2cc138e..a15898d641 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -237,10 +237,10 @@ static void export_blob(const struct object_id *oid) object = (struct object *)lookup_blob(oid); eaten = 0; } else { - buf = read_sha1_file(oid->hash, &type, &size); + buf = read_object_file(oid, &type, &size); if (!buf) die ("Could not read blob %s", oid_to_hex(oid)); - if (check_sha1_signature(oid->hash, buf, size, type_name(type)) < 0) + 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); } @@ -682,7 +682,7 @@ static void handle_tag(const char *name, struct tag *tag) return; } - buf = read_sha1_file(tag->object.oid.hash, &type, &size); + buf = read_object_file(&tag->object.oid, &type, &size); if (!buf) die ("Could not read tag %s", oid_to_hex(&tag->object.oid)); message = memmem(buf, size, "\n\n", 2); @@ -947,7 +947,7 @@ static void import_marks(char *input_file) if (last_idnum < mark) last_idnum = mark; - type = sha1_object_info(oid.hash, NULL); + type = oid_object_info(&oid, NULL); if (type < 0) die("object not found: %s", oid_to_hex(&oid)); diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index a7bc1366ab..1a1bc63566 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -4,6 +4,7 @@ #include "remote.h" #include "connect.h" #include "sha1-array.h" +#include "protocol.h" static const char fetch_pack_usage[] = "git fetch-pack [--all] [--stdin] [--quiet | -q] [--keep | -k] [--thin] " @@ -52,6 +53,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) struct fetch_pack_args args; struct oid_array shallow = OID_ARRAY_INIT; struct string_list deepen_not = STRING_LIST_INIT_DUP; + struct packet_reader reader; fetch_if_missing = 0; @@ -211,10 +213,24 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) if (!conn) return args.diag_url ? 0 : 1; } - get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL, &shallow); + + packet_reader_init(&reader, fd[0], NULL, 0, + PACKET_READ_CHOMP_NEWLINE | + PACKET_READ_GENTLE_ON_EOF); + + switch (discover_version(&reader)) { + case protocol_v2: + die("support for protocol v2 not implemented yet"); + case protocol_v1: + case protocol_v0: + get_remote_heads(&reader, &ref, 0, NULL, &shallow); + break; + case protocol_unknown_version: + BUG("unknown protocol version"); + } ref = fetch_pack(&args, fd, conn, ref, dest, sought, nr_sought, - &shallow, pack_lockfile_ptr); + &shallow, pack_lockfile_ptr, protocol_v0); if (pack_lockfile) { printf("lock %s\n", pack_lockfile); fflush(stdout); diff --git a/builtin/fetch.c b/builtin/fetch.c index d32d94692c..7ee83ac0f8 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -126,7 +126,7 @@ static struct option builtin_fetch_options[] = { N_("append to .git/FETCH_HEAD instead of overwriting")), OPT_STRING(0, "upload-pack", &upload_pack, N_("path"), N_("path to upload pack on remote end")), - OPT__FORCE(&force, N_("force overwrite of local branch")), + OPT__FORCE(&force, N_("force overwrite of local branch"), 0), OPT_BOOL('m', "multiple", &multiple, N_("fetch from multiple remotes")), OPT_SET_INT('t', "tags", &tags, @@ -264,7 +264,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); ref; ref = ref->next) { + for (ref = transport_get_remote_refs(transport, NULL); ref; ref = ref->next) { if (!starts_with(ref->name, "refs/tags/")) continue; @@ -346,11 +346,28 @@ 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 = transport_get_remote_refs(transport); + const struct ref *remote_refs; + + for (i = 0; i < refspec_count; i++) { + if (!refspecs[i].exact_sha1) { + const char *glob = strchr(refspecs[i].src, '*'); + if (glob) + argv_array_pushf(&ref_prefixes, "%.*s", + (int)(glob - refspecs[i].src), + refspecs[i].src); + else + expand_ref_prefix(&ref_prefixes, refspecs[i].src); + } + } + + remote_refs = transport_get_remote_refs(transport, &ref_prefixes); + + argv_array_clear(&ref_prefixes); if (refspec_count) { struct refspec *fetch_refspec; @@ -637,7 +654,7 @@ static int update_local_ref(struct ref *ref, struct branch *current_branch = branch_get(NULL); const char *pretty_ref = prettify_refname(ref->name); - type = sha1_object_info(ref->new_oid.hash, NULL); + type = oid_object_info(&ref->new_oid, NULL); if (type < 0) die(_("object %s not found"), oid_to_hex(&ref->new_oid)); @@ -708,9 +725,9 @@ static int update_local_ref(struct ref *ref, if (in_merge_bases(current, updated)) { struct strbuf quickref = STRBUF_INIT; int r; - strbuf_add_unique_abbrev(&quickref, current->object.oid.hash, DEFAULT_ABBREV); + strbuf_add_unique_abbrev(&quickref, ¤t->object.oid, DEFAULT_ABBREV); strbuf_addstr(&quickref, ".."); - strbuf_add_unique_abbrev(&quickref, ref->new_oid.hash, DEFAULT_ABBREV); + strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV); if ((recurse_submodules != RECURSE_SUBMODULES_OFF) && (recurse_submodules != RECURSE_SUBMODULES_ON)) check_for_new_submodule_commits(&ref->new_oid); @@ -723,9 +740,9 @@ static int update_local_ref(struct ref *ref, } else if (force || ref->force) { struct strbuf quickref = STRBUF_INIT; int r; - strbuf_add_unique_abbrev(&quickref, current->object.oid.hash, DEFAULT_ABBREV); + strbuf_add_unique_abbrev(&quickref, ¤t->object.oid, DEFAULT_ABBREV); strbuf_addstr(&quickref, "..."); - strbuf_add_unique_abbrev(&quickref, ref->new_oid.hash, DEFAULT_ABBREV); + strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV); if ((recurse_submodules != RECURSE_SUBMODULES_OFF) && (recurse_submodules != RECURSE_SUBMODULES_ON)) check_for_new_submodule_commits(&ref->new_oid); @@ -1516,7 +1533,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) string_list_clear(&list, 0); - close_all_packs(); + close_all_packs(the_repository->objects); argv_array_pushl(&argv_gc_auto, "gc", "--auto", NULL); if (verbosity < 0) diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index 8e8a15ea4a..bd680be687 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -485,10 +485,10 @@ static void fmt_merge_msg_sigs(struct strbuf *out) struct strbuf tagbuf = STRBUF_INIT; for (i = 0; i < origins.nr; i++) { - unsigned char *sha1 = origins.items[i].util; + struct object_id *oid = origins.items[i].util; enum object_type type; unsigned long size, len; - char *buf = read_sha1_file(sha1, &type, &size); + char *buf = read_object_file(oid, &type, &size); struct strbuf sig = STRBUF_INIT; if (!buf || type != OBJ_TAG) diff --git a/builtin/fsck.c b/builtin/fsck.c index ef78c6c00c..087360a675 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "repository.h" #include "config.h" #include "commit.h" #include "tree.h" @@ -16,6 +17,7 @@ #include "streaming.h" #include "decorate.h" #include "packfile.h" +#include "object-store.h" #define REACHABLE 0x0001 #define SEEN 0x0002 @@ -65,7 +67,7 @@ static const char *printable_type(struct object *obj) const char *ret; if (obj->type == OBJ_NONE) { - enum object_type type = sha1_object_info(obj->oid.hash, NULL); + enum object_type type = oid_object_info(&obj->oid, NULL); if (type > 0) object_as_type(obj, type, 0); } @@ -513,7 +515,7 @@ static struct object *parse_loose_object(const struct object_id *oid, unsigned long size; int eaten; - if (read_loose_object(path, oid->hash, &type, &size, &contents) < 0) + if (read_loose_object(path, oid, &type, &size, &contents) < 0) return NULL; if (!contents && type != OBJ_BLOB) @@ -719,9 +721,12 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) for_each_loose_object(mark_loose_for_connectivity, NULL, 0); for_each_packed_object(mark_packed_for_connectivity, NULL, 0); } else { + struct alternate_object_database *alt_odb_list; + fsck_object_dir(get_object_directory()); - prepare_alt_odb(); + prepare_alt_odb(the_repository); + alt_odb_list = the_repository->objects->alt_odb_list; for (alt = alt_odb_list; alt; alt = alt->next) fsck_object_dir(alt->path); @@ -730,10 +735,9 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) uint32_t total = 0, count = 0; struct progress *progress = NULL; - prepare_packed_git(); - if (show_progress) { - for (p = packed_git; p; p = p->next) { + for (p = get_packed_git(the_repository); p; + p = p->next) { if (open_pack_index(p)) continue; total += p->num_objects; @@ -741,7 +745,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) progress = start_progress(_("Checking objects"), total); } - for (p = packed_git; p; p = p->next) { + for (p = get_packed_git(the_repository); p; + p = p->next) { /* verify gives error messages itself */ if (verify_pack(p, fsck_obj_buffer, progress, count)) diff --git a/builtin/gc.c b/builtin/gc.c index 77fa720bd0..3e67124eaa 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -11,6 +11,7 @@ */ #include "builtin.h" +#include "repository.h" #include "config.h" #include "tempfile.h" #include "lockfile.h" @@ -20,6 +21,7 @@ #include "argv-array.h" #include "commit.h" #include "packfile.h" +#include "object-store.h" #define FAILED_RUN "failed to run %s" @@ -172,8 +174,7 @@ static int too_many_packs(void) if (gc_auto_pack_limit <= 0) return 0; - prepare_packed_git(); - for (cnt = 0, p = packed_git; p; p = p->next) { + for (cnt = 0, p = get_packed_git(the_repository); p; p = p->next) { if (!p->pack_local) continue; if (p->pack_keep) @@ -360,8 +361,11 @@ int cmd_gc(int argc, const char **argv, const char *prefix) N_("prune unreferenced objects"), PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire }, OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")), - OPT_BOOL(0, "auto", &auto_gc, N_("enable auto-gc mode")), - OPT_BOOL(0, "force", &force, N_("force running gc even if there may be another gc running")), + OPT_BOOL_F(0, "auto", &auto_gc, N_("enable auto-gc mode"), + PARSE_OPT_NOCOMPLETE), + OPT_BOOL_F(0, "force", &force, + N_("force running gc even if there may be another gc running"), + PARSE_OPT_NOCOMPLETE), OPT_END() }; @@ -476,7 +480,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix) return error(FAILED_RUN, rerere.argv[0]); report_garbage = report_pack_garbage; - reprepare_packed_git(); + reprepare_packed_git(the_repository); if (pack_garbage.nr > 0) clean_pack_garbage(); diff --git a/builtin/grep.c b/builtin/grep.c index 9a0973e8f1..6e7bc76785 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -22,6 +22,7 @@ #include "pathspec.h" #include "submodule.h" #include "submodule-config.h" +#include "object-store.h" static char const * const grep_usage[] = { N_("git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"), @@ -306,7 +307,7 @@ static void *lock_and_read_oid_file(const struct object_id *oid, enum object_typ void *data; grep_read_lock(); - data = read_sha1_file(oid->hash, type, size); + data = read_object_file(oid, type, size); grep_read_unlock(); return data; } @@ -439,7 +440,7 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject, * object. */ grep_read_lock(); - add_to_alternates_memory(submodule.objectdir); + add_to_alternates_memory(submodule.objects->objectdir); grep_read_unlock(); if (oid) { @@ -452,7 +453,7 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject, object = parse_object_or_die(oid, oid_to_hex(oid)); grep_read_lock(); - data = read_object_with_reference(object->oid.hash, tree_type, + data = read_object_with_reference(&object->oid, tree_type, &size, NULL); grep_read_unlock(); @@ -601,8 +602,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, } static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, - struct object *obj, const char *name, const char *path, - struct repository *repo) + struct object *obj, const char *name, const char *path) { if (obj->type == OBJ_BLOB) return grep_oid(opt, &obj->oid, name, 0, path); @@ -614,7 +614,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, int hit, len; grep_read_lock(); - data = read_object_with_reference(obj->oid.hash, tree_type, + data = read_object_with_reference(&obj->oid, tree_type, &size, NULL); grep_read_unlock(); @@ -629,7 +629,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, } init_tree_desc(&tree, data, size); hit = grep_tree(opt, pathspec, &tree, &base, base.len, - obj->type == OBJ_COMMIT, repo); + obj->type == OBJ_COMMIT, the_repository); strbuf_release(&base); free(data); return hit; @@ -638,7 +638,6 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, } static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, - struct repository *repo, const struct object_array *list) { unsigned int i; @@ -651,11 +650,11 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, /* load the gitmodules file for this rev */ if (recurse_submodules) { - submodule_free(); + submodule_free(the_repository); gitmodules_config_oid(&real_obj->oid); } - if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path, - repo)) { + if (grep_object(opt, pathspec, real_obj, list->objects[i].name, + list->objects[i].path)) { hit = 1; if (opt->status_only) break; @@ -839,8 +838,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOL('L', "files-without-match", &opt.unmatch_name_only, N_("show only the names of files without match")), - OPT_BOOL('z', "null", &opt.null_following_name, - N_("print NUL after filenames")), + OPT_BOOL_F('z', "null", &opt.null_following_name, + N_("print NUL after filenames"), + PARSE_OPT_NOCOMPLETE), OPT_BOOL('c', "count", &opt.count, N_("show the number of matches instead of matching lines")), OPT__COLOR(&opt.color, N_("highlight matches")), @@ -891,9 +891,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_GROUP(""), { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, N_("pager"), N_("show matching files in the pager"), - PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, - OPT_BOOL(0, "ext-grep", &external_grep_allowed__ignored, - N_("allow calling of grep(1) (ignored by this build)")), + PARSE_OPT_OPTARG | PARSE_OPT_NOCOMPLETE, + NULL, (intptr_t)default_pager }, + OPT_BOOL_F(0, "ext-grep", &external_grep_allowed__ignored, + N_("allow calling of grep(1) (ignored by this build)"), + PARSE_OPT_NOCOMPLETE), OPT_END() }; @@ -1104,7 +1106,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (cached) die(_("both --cached and trees are given.")); - hit = grep_objects(&opt, &pathspec, the_repository, &list); + hit = grep_objects(&opt, &pathspec, &list); } if (num_threads) diff --git a/builtin/hash-object.c b/builtin/hash-object.c index 526da5c185..a9a3a198c3 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -9,7 +9,7 @@ #include "blob.h" #include "quote.h" #include "parse-options.h" -#include "exec_cmd.h" +#include "exec-cmd.h" /* * This is to create corrupt objects for debugging and as such it diff --git a/builtin/help.c b/builtin/help.c index 598867cfea..2d51071429 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -4,7 +4,7 @@ #include "cache.h" #include "config.h" #include "builtin.h" -#include "exec_cmd.h" +#include "exec-cmd.h" #include "parse-options.h" #include "run-command.h" #include "column.h" diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 59878e70b8..a2cd29d8f4 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -9,10 +9,11 @@ #include "tree.h" #include "progress.h" #include "fsck.h" -#include "exec_cmd.h" +#include "exec-cmd.h" #include "streaming.h" #include "thread-utils.h" #include "packfile.h" +#include "object-store.h" static const char index_pack_usage[] = "git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])"; @@ -49,6 +50,7 @@ struct thread_local { int pack_fd; }; +/* Remember to update object flag allocation in object.h */ #define FLAG_LINK (1u<<20) #define FLAG_CHECKED (1u<<21) @@ -58,7 +60,7 @@ struct ofs_delta_entry { }; struct ref_delta_entry { - unsigned char sha1[20]; + struct object_id oid; int obj_no; }; @@ -221,7 +223,7 @@ static unsigned check_object(struct object *obj) if (!(obj->flags & FLAG_CHECKED)) { unsigned long size; - int type = sha1_object_info(obj->oid.hash, &size); + int type = oid_object_info(&obj->oid, &size); if (type <= 0) die(_("did not receive expected object %s"), oid_to_hex(&obj->oid)); @@ -671,18 +673,18 @@ static void find_ofs_delta_children(off_t offset, *last_index = last; } -static int compare_ref_delta_bases(const unsigned char *sha1, - const unsigned char *sha2, +static int compare_ref_delta_bases(const struct object_id *oid1, + const struct object_id *oid2, enum object_type type1, enum object_type type2) { int cmp = type1 - type2; if (cmp) return cmp; - return hashcmp(sha1, sha2); + return oidcmp(oid1, oid2); } -static int find_ref_delta(const unsigned char *sha1, enum object_type type) +static int find_ref_delta(const struct object_id *oid, enum object_type type) { int first = 0, last = nr_ref_deltas; @@ -691,7 +693,7 @@ static int find_ref_delta(const unsigned char *sha1, enum object_type type) struct ref_delta_entry *delta = &ref_deltas[next]; int cmp; - cmp = compare_ref_delta_bases(sha1, delta->sha1, + cmp = compare_ref_delta_bases(oid, &delta->oid, type, objects[delta->obj_no].type); if (!cmp) return next; @@ -704,11 +706,11 @@ static int find_ref_delta(const unsigned char *sha1, enum object_type type) return -first-1; } -static void find_ref_delta_children(const unsigned char *sha1, +static void find_ref_delta_children(const struct object_id *oid, int *first_index, int *last_index, enum object_type type) { - int first = find_ref_delta(sha1, type); + int first = find_ref_delta(oid, type); int last = first; int end = nr_ref_deltas - 1; @@ -717,9 +719,9 @@ static void find_ref_delta_children(const unsigned char *sha1, *last_index = -1; return; } - while (first > 0 && !hashcmp(ref_deltas[first - 1].sha1, sha1)) + while (first > 0 && !oidcmp(&ref_deltas[first - 1].oid, oid)) --first; - while (last < end && !hashcmp(ref_deltas[last + 1].sha1, sha1)) + while (last < end && !oidcmp(&ref_deltas[last + 1].oid, oid)) ++last; *first_index = first; *last_index = last; @@ -771,7 +773,7 @@ static int check_collison(struct object_entry *entry) memset(&data, 0, sizeof(data)); data.entry = entry; - data.st = open_istream(entry->idx.oid.hash, &type, &size, NULL); + data.st = open_istream(&entry->idx.oid, &type, &size, NULL); if (!data.st) return -1; if (size != entry->size || type != entry->type) @@ -810,12 +812,12 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, enum object_type has_type; unsigned long has_size; read_lock(); - has_type = sha1_object_info(oid->hash, &has_size); + has_type = oid_object_info(oid, &has_size); if (has_type < 0) die(_("cannot read existing object info %s"), oid_to_hex(oid)); if (has_type != type || has_size != size) die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid)); - has_data = read_sha1_file(oid->hash, &has_type, &has_size); + has_data = read_object_file(oid, &has_type, &has_size); read_unlock(); if (!data) data = new_data = get_data_from_pack(obj_entry); @@ -827,7 +829,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, free(has_data); } - if (strict) { + if (strict || do_fsck_object) { read_lock(); if (type == OBJ_BLOB) { struct blob *blob = lookup_blob(oid); @@ -853,7 +855,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, if (do_fsck_object && fsck_object(obj, buf, size, &fsck_options)) die(_("Error in object")); - if (fsck_walk(obj, NULL, &fsck_options)) + if (strict && fsck_walk(obj, NULL, &fsck_options)) die(_("Not all child objects of %s are reachable"), oid_to_hex(&obj->oid)); if (obj->type == OBJ_TREE) { @@ -991,7 +993,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base, struct base_data *prev_base) { if (base->ref_last == -1 && base->ofs_last == -1) { - find_ref_delta_children(base->obj->idx.oid.hash, + find_ref_delta_children(&base->obj->idx.oid, &base->ref_first, &base->ref_last, OBJ_REF_DELTA); @@ -1075,7 +1077,7 @@ static int compare_ref_delta_entry(const void *a, const void *b) const struct ref_delta_entry *delta_a = a; const struct ref_delta_entry *delta_b = b; - return hashcmp(delta_a->sha1, delta_b->sha1); + return oidcmp(&delta_a->oid, &delta_b->oid); } static void resolve_base(struct object_entry *obj) @@ -1141,7 +1143,7 @@ static void parse_pack_objects(unsigned char *hash) ofs_delta++; } else if (obj->type == OBJ_REF_DELTA) { ALLOC_GROW(ref_deltas, nr_ref_deltas + 1, ref_deltas_alloc); - hashcpy(ref_deltas[nr_ref_deltas].sha1, ref_delta_oid.hash); + oidcpy(&ref_deltas[nr_ref_deltas].oid, &ref_delta_oid); ref_deltas[nr_ref_deltas].obj_no = i; nr_ref_deltas++; } else if (!data) { @@ -1269,7 +1271,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha nr_objects - nr_objects_initial); stop_progress_msg(&progress, msg.buf); strbuf_release(&msg); - hashclose(f, tail_hash, 0); + finalize_hashfile(f, tail_hash, 0); hashcpy(read_hash, pack_hash); fixup_pack_header_footer(output_fd, pack_hash, curr_pack, nr_objects, @@ -1373,14 +1375,15 @@ static void fix_unresolved_deltas(struct hashfile *f) if (objects[d->obj_no].real_type != OBJ_REF_DELTA) continue; - base_obj->data = read_sha1_file(d->sha1, &type, &base_obj->size); + base_obj->data = read_object_file(&d->oid, &type, + &base_obj->size); if (!base_obj->data) continue; - if (check_sha1_signature(d->sha1, base_obj->data, + if (check_object_signature(&d->oid, base_obj->data, base_obj->size, type_name(type))) - die(_("local object %s is corrupt"), sha1_to_hex(d->sha1)); - base_obj->obj = append_obj_to_pack(f, d->sha1, + die(_("local object %s is corrupt"), oid_to_hex(&d->oid)); + base_obj->obj = append_obj_to_pack(f, d->oid.hash, base_obj->data, base_obj->size, type); find_unresolved_deltas(base_obj); display_progress(progress, nr_resolved_deltas); @@ -1590,7 +1593,7 @@ static void read_idx_option(struct pack_idx_option *opts, const char *pack_name) /* * Get rid of the idx file as we do not need it anymore. * NEEDSWORK: extract this bit from free_pack_by_name() in - * sha1_file.c, perhaps? It shouldn't matter very much as we + * sha1-file.c, perhaps? It shouldn't matter very much as we * know we haven't installed this pack (hence we never have * read anything from it). */ @@ -1688,6 +1691,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) } else if (!strcmp(arg, "--check-self-contained-and-connected")) { strict = 1; check_self_contained_and_connected = 1; + } else if (!strcmp(arg, "--fsck-objects")) { + do_fsck_object = 1; } else if (!strcmp(arg, "--verify")) { verify = 1; } else if (!strcmp(arg, "--verify-stat")) { diff --git a/builtin/init-db.c b/builtin/init-db.c index 68ff4ad75a..2542c5244e 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -7,7 +7,7 @@ #include "config.h" #include "refs.h" #include "builtin.h" -#include "exec_cmd.h" +#include "exec-cmd.h" #include "parse-options.h" #ifndef DEFAULT_GIT_TEMPLATE_DIR diff --git a/builtin/log.c b/builtin/log.c index 94ee177d56..71f68a3e4f 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -518,7 +518,7 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev) { unsigned long size; enum object_type type; - char *buf = read_sha1_file(oid->hash, &type, &size); + char *buf = read_object_file(oid, &type, &size); int offset = 0; if (!buf) @@ -541,7 +541,7 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev) return 0; } -static int show_tree_object(const unsigned char *sha1, +static int show_tree_object(const struct object_id *oid, struct strbuf *base, const char *pathname, unsigned mode, int stage, void *context) { @@ -1873,12 +1873,12 @@ static void print_commit(char sign, struct commit *commit, int verbose, { if (!verbose) { fprintf(file, "%c %s\n", sign, - find_unique_abbrev(commit->object.oid.hash, abbrev)); + find_unique_abbrev(&commit->object.oid, abbrev)); } else { struct strbuf buf = STRBUF_INIT; pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf); fprintf(file, "%c %s %s\n", sign, - find_unique_abbrev(commit->object.oid.hash, abbrev), + find_unique_abbrev(&commit->object.oid, abbrev), buf.buf); strbuf_release(&buf); } diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 2fc836e330..a71f6bd088 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -240,7 +240,7 @@ static void show_ce(struct repository *repo, struct dir_struct *dir, printf("%s%06o %s %d\t", tag, ce->ce_mode, - find_unique_abbrev(ce->oid.hash, abbrev), + find_unique_abbrev(&ce->oid, abbrev), ce_stage(ce)); } write_eolinfo(repo->index, ce, fullname); @@ -271,7 +271,7 @@ static void show_ru_info(const struct index_state *istate) if (!ui->mode[i]) continue; printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i], - find_unique_abbrev(ui->sha1[i], abbrev), + find_unique_abbrev(&ui->oid[i], abbrev), i + 1); write_name(path); } diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c index c4be98ab9e..380c180270 100644 --- a/builtin/ls-remote.c +++ b/builtin/ls-remote.c @@ -2,6 +2,7 @@ #include "cache.h" #include "transport.h" #include "remote.h" +#include "refs.h" static const char * const ls_remote_usage[] = { N_("git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" @@ -43,6 +44,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) int show_symref_target = 0; const char *uploadpack = NULL; const char **pattern = NULL; + struct argv_array ref_prefixes = ARGV_ARRAY_INIT; struct remote *remote; struct transport *transport; @@ -60,8 +62,9 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) OPT_BIT(0, "refs", &flags, N_("do not show peeled tags"), REF_NORMAL), OPT_BOOL(0, "get-url", &get_url, N_("take url.<base>.insteadOf into account")), - OPT_SET_INT(0, "exit-code", &status, - N_("exit with exit code 2 if no matching refs are found"), 2), + OPT_SET_INT_F(0, "exit-code", &status, + N_("exit with exit code 2 if no matching refs are found"), + 2, PARSE_OPT_NOCOMPLETE), OPT_BOOL(0, "symref", &show_symref_target, N_("show underlying ref in addition to the object pointed by it")), OPT_END() @@ -74,8 +77,17 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) if (argc > 1) { int i; pattern = xcalloc(argc, sizeof(const char *)); - for (i = 1; i < argc; i++) + for (i = 1; i < argc; i++) { + const char *glob; pattern[i - 1] = xstrfmt("*/%s", argv[i]); + + glob = strchr(argv[i], '*'); + if (glob) + argv_array_pushf(&ref_prefixes, "%.*s", + (int)(glob - argv[i]), argv[i]); + else + expand_ref_prefix(&ref_prefixes, argv[i]); + } } remote = remote_get(dest); @@ -96,7 +108,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) if (uploadpack != NULL) transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack); - ref = transport_get_remote_refs(transport); + ref = transport_get_remote_refs(transport, &ref_prefixes); if (transport_disconnect(transport)) return 1; diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index ef965408e8..d44b4f9c27 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -60,7 +60,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname) return 0; } -static int show_tree(const unsigned char *sha1, struct strbuf *base, +static int show_tree(const struct object_id *oid, struct strbuf *base, const char *pathname, unsigned mode, int stage, void *context) { int retval = 0; @@ -94,7 +94,7 @@ static int show_tree(const unsigned char *sha1, struct strbuf *base, char size_text[24]; if (!strcmp(type, blob_type)) { unsigned long size; - if (sha1_object_info(sha1, &size) == OBJ_BAD) + if (oid_object_info(oid, &size) == OBJ_BAD) xsnprintf(size_text, sizeof(size_text), "BAD"); else @@ -103,11 +103,11 @@ static int show_tree(const unsigned char *sha1, struct strbuf *base, } else xsnprintf(size_text, sizeof(size_text), "-"); printf("%06o %s %s %7s\t", mode, type, - find_unique_abbrev(sha1, abbrev), + find_unique_abbrev(oid, abbrev), size_text); } else printf("%06o %s %s\t", mode, type, - find_unique_abbrev(sha1, abbrev)); + find_unique_abbrev(oid, abbrev)); } baselen = base->len; strbuf_addstr(base, pathname); diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index d01ddecf66..bf01e05808 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -2,7 +2,7 @@ #include "tree-walk.h" #include "xdiff-interface.h" #include "blob.h" -#include "exec_cmd.h" +#include "exec-cmd.h" #include "merge-blobs.h" static const char merge_tree_usage[] = "git merge-tree <base-tree> <branch1> <branch2>"; @@ -60,7 +60,7 @@ static void *result(struct merge_list *entry, unsigned long *size) const char *path = entry->path; if (!entry->stage) - return read_sha1_file(entry->blob->object.oid.hash, &type, size); + return read_object_file(&entry->blob->object.oid, &type, size); base = NULL; if (entry->stage == 1) { base = entry->blob; @@ -82,7 +82,8 @@ static void *origin(struct merge_list *entry, unsigned long *size) enum object_type type; while (entry) { if (entry->stage == 2) - return read_sha1_file(entry->blob->object.oid.hash, &type, size); + return read_object_file(&entry->blob->object.oid, + &type, size); entry = entry->link; } return NULL; diff --git a/builtin/merge.c b/builtin/merge.c index e8d9d4383e..9db5a2cf16 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -412,7 +412,7 @@ static void finish(struct commit *head_commit, * We ignore errors in 'gc --auto', since the * user should see them. */ - close_all_packs(); + close_all_packs(the_repository->objects); run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); } } @@ -639,7 +639,7 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head, static void write_tree_trivial(struct object_id *oid) { - if (write_cache_as_tree(oid->hash, 0, NULL)) + if (write_cache_as_tree(oid, 0, NULL)) die(_("git write-tree failed to write a tree")); } @@ -652,10 +652,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, hold_locked_index(&lock, LOCK_DIE_ON_ERROR); refresh_cache(REFRESH_QUIET); - if (active_cache_changed && - write_locked_index(&the_index, &lock, COMMIT_LOCK)) + if (write_locked_index(&the_index, &lock, + COMMIT_LOCK | SKIP_IF_UNCHANGED)) return error(_("Unable to write index.")); - rollback_lock_file(&lock); if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) { int clean, x; @@ -692,10 +691,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, remoteheads->item, reversed, &result); if (clean < 0) exit(128); - if (active_cache_changed && - write_locked_index(&the_index, &lock, COMMIT_LOCK)) + if (write_locked_index(&the_index, &lock, + COMMIT_LOCK | SKIP_IF_UNCHANGED)) die (_("unable to write %s"), get_index_file()); - rollback_lock_file(&lock); return clean ? 0 : 1; } else { return try_merge_command(strategy, xopts_nr, xopts, @@ -811,10 +809,9 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads) hold_locked_index(&lock, LOCK_DIE_ON_ERROR); refresh_cache(REFRESH_QUIET); - if (active_cache_changed && - write_locked_index(&the_index, &lock, COMMIT_LOCK)) + if (write_locked_index(&the_index, &lock, + COMMIT_LOCK | SKIP_IF_UNCHANGED)) return error(_("Unable to write index.")); - rollback_lock_file(&lock); write_tree_trivial(&result_tree); printf(_("Wonderful.\n")); @@ -1327,7 +1324,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) check_commit_signature(commit, &signature_check); - find_unique_abbrev_r(hex, commit->object.oid.hash, DEFAULT_ABBREV); + find_unique_abbrev_r(hex, &commit->object.oid, DEFAULT_ABBREV); switch (signature_check.result) { case 'G': break; @@ -1420,9 +1417,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix) if (verbosity >= 0) { printf(_("Updating %s..%s\n"), - find_unique_abbrev(head_commit->object.oid.hash, + find_unique_abbrev(&head_commit->object.oid, DEFAULT_ABBREV), - find_unique_abbrev(remoteheads->item->object.oid.hash, + find_unique_abbrev(&remoteheads->item->object.oid, DEFAULT_ABBREV)); } strbuf_addstr(&msg, "Fast-forward"); diff --git a/builtin/mktag.c b/builtin/mktag.c index beb552847b..82a6e86077 100644 --- a/builtin/mktag.c +++ b/builtin/mktag.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "tag.h" +#include "replace-object.h" /* * A signature file has a very simple fixed format: four lines @@ -18,17 +19,17 @@ /* * We refuse to tag something we can't verify. Just because. */ -static int verify_object(const unsigned char *sha1, const char *expected_type) +static int verify_object(const struct object_id *oid, const char *expected_type) { int ret = -1; enum object_type type; unsigned long size; - void *buffer = read_sha1_file(sha1, &type, &size); - const unsigned char *repl = lookup_replace_object(sha1); + void *buffer = read_object_file(oid, &type, &size); + const struct object_id *repl = lookup_replace_object(the_repository, oid); if (buffer) { if (type == type_from_string(expected_type)) - ret = check_sha1_signature(repl, buffer, size, expected_type); + ret = check_object_signature(repl, buffer, size, expected_type); free(buffer); } return ret; @@ -38,8 +39,8 @@ static int verify_tag(char *buffer, unsigned long size) { int typelen; char type[20]; - unsigned char sha1[20]; - const char *object, *type_line, *tag_line, *tagger_line, *lb, *rb; + struct object_id oid; + const char *object, *type_line, *tag_line, *tagger_line, *lb, *rb, *p; size_t len; if (size < 84) @@ -52,11 +53,11 @@ static int verify_tag(char *buffer, unsigned long size) if (memcmp(object, "object ", 7)) return error("char%d: does not start with \"object \"", 0); - if (get_sha1_hex(object + 7, sha1)) + if (parse_oid_hex(object + 7, &oid, &p)) return error("char%d: could not get SHA1 hash", 7); /* Verify type line */ - type_line = object + 48; + type_line = p + 1; if (memcmp(type_line - 1, "\ntype ", 6)) return error("char%d: could not find \"\\ntype \"", 47); @@ -80,8 +81,8 @@ static int verify_tag(char *buffer, unsigned long size) type[typelen] = 0; /* Verify that the object matches */ - if (verify_object(sha1, type)) - return error("char%d: could not verify object %s", 7, sha1_to_hex(sha1)); + if (verify_object(&oid, type)) + return error("char%d: could not verify object %s", 7, oid_to_hex(&oid)); /* Verify the tag-name: we don't allow control characters or spaces in it */ tag_line += 4; diff --git a/builtin/mktree.c b/builtin/mktree.c index f5f3c0eea1..263c530315 100644 --- a/builtin/mktree.c +++ b/builtin/mktree.c @@ -10,13 +10,13 @@ static struct treeent { unsigned mode; - unsigned char sha1[20]; + struct object_id oid; int len; char name[FLEX_ARRAY]; } **entries; static int alloc, used; -static void append_to_tree(unsigned mode, unsigned char *sha1, char *path) +static void append_to_tree(unsigned mode, struct object_id *oid, char *path) { struct treeent *ent; size_t len = strlen(path); @@ -26,7 +26,7 @@ static void append_to_tree(unsigned mode, unsigned char *sha1, char *path) FLEX_ALLOC_MEM(ent, name, path, len); ent->mode = mode; ent->len = len; - hashcpy(ent->sha1, sha1); + oidcpy(&ent->oid, oid); ALLOC_GROW(entries, used + 1, alloc); entries[used++] = ent; @@ -54,7 +54,7 @@ static void write_tree(struct object_id *oid) for (i = 0; i < used; i++) { struct treeent *ent = entries[i]; strbuf_addf(&buf, "%o %s%c", ent->mode, ent->name, '\0'); - strbuf_add(&buf, ent->sha1, 20); + strbuf_add(&buf, ent->oid.hash, the_hash_algo->rawsz); } write_object_file(buf.buf, buf.len, tree_type, oid); @@ -69,11 +69,12 @@ static const char *mktree_usage[] = { static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_missing) { char *ptr, *ntr; + const char *p; unsigned mode; enum object_type mode_type; /* object type derived from mode */ enum object_type obj_type; /* object type derived from sha */ char *path, *to_free = NULL; - unsigned char sha1[20]; + struct object_id oid; ptr = buf; /* @@ -85,9 +86,8 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss die("input format error: %s", buf); ptr = ntr + 1; /* type */ ntr = strchr(ptr, ' '); - if (!ntr || buf + len <= ntr + 40 || - ntr[41] != '\t' || - get_sha1_hex(ntr + 1, sha1)) + if (!ntr || parse_oid_hex(ntr + 1, &oid, &p) || + *p != '\t') die("input format error: %s", buf); /* It is perfectly normal if we do not have a commit from a submodule */ @@ -116,12 +116,12 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss } /* Check the type of object identified by sha1 */ - obj_type = sha1_object_info(sha1, NULL); + obj_type = oid_object_info(&oid, NULL); if (obj_type < 0) { if (allow_missing) { ; /* no problem - missing objects are presumed to be of the right type */ } else { - die("entry '%s' object %s is unavailable", path, sha1_to_hex(sha1)); + die("entry '%s' object %s is unavailable", path, oid_to_hex(&oid)); } } else { if (obj_type != mode_type) { @@ -131,11 +131,11 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss * because the new tree entry will never be correct. */ die("entry '%s' object %s is a %s but specified type was (%s)", - path, sha1_to_hex(sha1), type_name(obj_type), type_name(mode_type)); + path, oid_to_hex(&oid), type_name(obj_type), type_name(mode_type)); } } - append_to_tree(mode, sha1, path); + append_to_tree(mode, &oid, path); free(to_free); } diff --git a/builtin/mv.c b/builtin/mv.c index 8ce6a2ddd4..7a63667d64 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -122,7 +122,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix) struct option builtin_mv_options[] = { OPT__VERBOSE(&verbose, N_("be verbose")), OPT__DRY_RUN(&show_only, N_("dry run")), - OPT__FORCE(&force, N_("force move/rename even if target exists")), + OPT__FORCE(&force, N_("force move/rename even if target exists"), + PARSE_OPT_NOCOMPLETE), OPT_BOOL('k', NULL, &ignore_errors, N_("skip move/rename errors")), OPT_END(), }; @@ -275,10 +276,12 @@ int cmd_mv(int argc, const char **argv, const char *prefix) die_errno(_("renaming '%s' failed"), src); } if (submodule_gitfile[i]) { - if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR) - connect_work_tree_and_git_dir(dst, submodule_gitfile[i]); if (!update_path_in_gitmodules(src, dst)) gitmodules_modified = 1; + if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR) + connect_work_tree_and_git_dir(dst, + submodule_gitfile[i], + 1); } if (mode == WORKING_DIRECTORY) @@ -292,8 +295,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix) if (gitmodules_modified) stage_updated_gitmodules(&the_index); - if (active_cache_changed && - write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) + if (write_locked_index(&the_index, &lock_file, + COMMIT_LOCK | SKIP_IF_UNCHANGED)) die(_("Unable to write new index file")); return 0; diff --git a/builtin/name-rev.c b/builtin/name-rev.c index 9e088ebd11..387ddf85d2 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -328,7 +328,7 @@ static void show_name(const struct object *obj, else if (allow_undefined) printf("undefined\n"); else if (always) - printf("%s\n", find_unique_abbrev(oid->hash, DEFAULT_ABBREV)); + printf("%s\n", find_unique_abbrev(oid, DEFAULT_ABBREV)); else die("cannot describe '%s'", oid_to_hex(oid)); strbuf_release(&buf); diff --git a/builtin/notes.c b/builtin/notes.c index 39304ba743..e5bf80eef1 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -14,7 +14,7 @@ #include "blob.h" #include "pretty.h" #include "refs.h" -#include "exec_cmd.h" +#include "exec-cmd.h" #include "run-command.h" #include "parse-options.h" #include "string-list.h" @@ -118,11 +118,11 @@ static int list_each_note(const struct object_id *object_oid, return 0; } -static void copy_obj_to_fd(int fd, const unsigned char *sha1) +static void copy_obj_to_fd(int fd, const struct object_id *oid) { unsigned long size; enum object_type type; - char *buf = read_sha1_file(sha1, &type, &size); + char *buf = read_object_file(oid, &type, &size); if (buf) { if (size) write_or_die(fd, buf, size); @@ -162,7 +162,7 @@ static void write_commented_object(int fd, const struct object_id *object) } static void prepare_note_data(const struct object_id *object, struct note_data *d, - const unsigned char *old_note) + const struct object_id *old_note) { if (d->use_editor || !d->given) { int fd; @@ -253,7 +253,7 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset) if (get_oid(arg, &object)) die(_("failed to resolve '%s' as a valid ref."), arg); - if (!(buf = read_sha1_file(object.hash, &type, &len))) { + if (!(buf = read_object_file(&object, &type, &len))) { free(buf); die(_("failed to read object '%s'."), arg); } @@ -413,7 +413,7 @@ static int add(int argc, const char **argv, const char *prefix) parse_reuse_arg}, OPT_BOOL(0, "allow-empty", &allow_empty, N_("allow storing empty note")), - OPT__FORCE(&force, N_("replace existing notes")), + OPT__FORCE(&force, N_("replace existing notes"), PARSE_OPT_NOCOMPLETE), OPT_END() }; @@ -457,7 +457,7 @@ static int add(int argc, const char **argv, const char *prefix) oid_to_hex(&object)); } - prepare_note_data(&object, &d, note ? note->hash : NULL); + prepare_note_data(&object, &d, note); if (d.buf.len || allow_empty) { write_note_data(&d, &new_note); if (add_note(t, &object, &new_note, combine_notes_overwrite)) @@ -484,7 +484,7 @@ static int copy(int argc, const char **argv, const char *prefix) struct notes_tree *t; const char *rewrite_cmd = NULL; struct option options[] = { - OPT__FORCE(&force, N_("replace existing notes")), + OPT__FORCE(&force, N_("replace existing notes"), PARSE_OPT_NOCOMPLETE), OPT_BOOL(0, "stdin", &from_stdin, N_("read objects from stdin")), OPT_STRING(0, "for-rewrite", &rewrite_cmd, N_("command"), N_("load rewriting config for <command> (implies " @@ -602,13 +602,13 @@ static int append_edit(int argc, const char **argv, const char *prefix) t = init_notes_check(argv[0], NOTES_INIT_WRITABLE); note = get_note(t, &object); - prepare_note_data(&object, &d, edit && note ? note->hash : NULL); + prepare_note_data(&object, &d, edit && note ? note : NULL); if (note && !edit) { /* Append buf to previous note contents */ unsigned long size; enum object_type type; - char *prev_buf = read_sha1_file(note->hash, &type, &size); + char *prev_buf = read_object_file(note, &type, &size); strbuf_grow(&d.buf, size + 1); if (d.buf.len && prev_buf && size) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index a197926eaa..24b1c6c5dd 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "repository.h" #include "config.h" #include "attr.h" #include "object.h" @@ -28,6 +29,7 @@ #include "argv-array.h" #include "list.h" #include "packfile.h" +#include "object-store.h" static const char *pack_usage[] = { N_("git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"), @@ -122,11 +124,10 @@ static void *get_delta(struct object_entry *entry) void *buf, *base_buf, *delta_buf; enum object_type type; - buf = read_sha1_file(entry->idx.oid.hash, &type, &size); + buf = read_object_file(&entry->idx.oid, &type, &size); if (!buf) die("unable to read %s", oid_to_hex(&entry->idx.oid)); - base_buf = read_sha1_file(entry->delta->idx.oid.hash, &type, - &base_size); + base_buf = read_object_file(&entry->delta->idx.oid, &type, &base_size); if (!base_buf) die("unable to read %s", oid_to_hex(&entry->delta->idx.oid)); @@ -267,11 +268,10 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent if (!usable_delta) { if (entry->type == OBJ_BLOB && entry->size > big_file_threshold && - (st = open_istream(entry->idx.oid.hash, &type, &size, NULL)) != NULL) + (st = open_istream(&entry->idx.oid, &type, &size, NULL)) != NULL) buf = NULL; else { - buf = read_sha1_file(entry->idx.oid.hash, &type, - &size); + buf = read_object_file(&entry->idx.oid, &type, &size); if (!buf) die(_("unable to read %s"), oid_to_hex(&entry->idx.oid)); @@ -837,11 +837,11 @@ static void write_pack_file(void) * If so, rewrite it like in fast-import */ if (pack_to_stdout) { - hashclose(f, oid.hash, CSUM_CLOSE); + finalize_hashfile(f, oid.hash, CSUM_HASH_IN_STREAM | CSUM_CLOSE); } else if (nr_written == nr_remaining) { - hashclose(f, oid.hash, CSUM_FSYNC); + finalize_hashfile(f, oid.hash, CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE); } else { - int fd = hashclose(f, oid.hash, 0); + int fd = finalize_hashfile(f, oid.hash, 0); fixup_pack_header_footer(fd, oid.hash, pack_tmp_name, nr_written, oid.hash, offset); close(fd); @@ -1025,8 +1025,7 @@ static int want_object_in_pack(const struct object_id *oid, if (want != -1) return want; } - - list_for_each(pos, &packed_git_mru) { + list_for_each(pos, get_packed_git_mru(the_repository)) { struct packed_git *p = list_entry(pos, struct packed_git, mru); off_t offset; @@ -1044,7 +1043,8 @@ static int want_object_in_pack(const struct object_id *oid, } want = want_found_object(exclude, p); if (!exclude && want > 0) - list_move(&p->mru, &packed_git_mru); + list_move(&p->mru, + get_packed_git_mru(the_repository)); if (want != -1) return want; } @@ -1190,7 +1190,7 @@ static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid) /* Did not find one. Either we got a bogus request or * we need to read and perhaps cache. */ - data = read_sha1_file(oid->hash, &type, &size); + data = read_object_file(oid, &type, &size); if (!data) return NULL; if (type != OBJ_TREE) { @@ -1351,7 +1351,7 @@ static void add_preferred_base(struct object_id *oid) if (window <= num_preferred_base++) return; - data = read_object_with_reference(oid->hash, tree_type, &size, tree_oid.hash); + data = read_object_with_reference(oid, tree_type, &size, &tree_oid); if (!data) return; @@ -1516,7 +1516,7 @@ static void check_object(struct object_entry *entry) unuse_pack(&w_curs); } - entry->type = sha1_object_info(entry->idx.oid.hash, &entry->size); + entry->type = oid_object_info(&entry->idx.oid, &entry->size); /* * The error condition is checked in prepare_pack(). This is * to permit a missing preferred base object to be ignored @@ -1578,8 +1578,7 @@ static void drop_reused_delta(struct object_entry *entry) * And if that fails, the error will be recorded in entry->type * and dealt with in prepare_pack(). */ - entry->type = sha1_object_info(entry->idx.oid.hash, - &entry->size); + entry->type = oid_object_info(&entry->idx.oid, &entry->size); } } @@ -1871,8 +1870,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, /* Load data if not already done */ if (!trg->data) { read_lock(); - trg->data = read_sha1_file(trg_entry->idx.oid.hash, &type, - &sz); + trg->data = read_object_file(&trg_entry->idx.oid, &type, &sz); read_unlock(); if (!trg->data) die("object %s cannot be read", @@ -1885,8 +1883,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, } if (!src->data) { read_lock(); - src->data = read_sha1_file(src_entry->idx.oid.hash, &type, - &sz); + src->data = read_object_file(&src_entry->idx.oid, &type, &sz); read_unlock(); if (!src->data) { if (src_entry->preferred_base) { @@ -2549,6 +2546,7 @@ static void read_object_list_from_stdin(void) } } +/* Remember to update object flag allocation in object.h */ #define OBJECT_ADDED (1u<<20) static void show_commit(struct commit *commit, void *data) @@ -2673,7 +2671,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs) memset(&in_pack, 0, sizeof(in_pack)); - for (p = packed_git; p; p = p->next) { + for (p = get_packed_git(the_repository); p; p = p->next) { struct object_id oid; struct object *o; @@ -2708,7 +2706,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs) static int add_loose_object(const struct object_id *oid, const char *path, void *data) { - enum object_type type = sha1_object_info(oid->hash, NULL); + enum object_type type = oid_object_info(oid, NULL); if (type < 0) { warning("loose object at %s could not be examined", path); @@ -2736,7 +2734,8 @@ static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid) static struct packed_git *last_found = (void *)1; struct packed_git *p; - p = (last_found != (void *)1) ? last_found : packed_git; + p = (last_found != (void *)1) ? last_found : + get_packed_git(the_repository); while (p) { if ((!p->pack_local || p->pack_keep) && @@ -2745,7 +2744,7 @@ static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid) return 1; } if (p == last_found) - p = packed_git; + p = get_packed_git(the_repository); else p = p->next; if (p == last_found) @@ -2781,7 +2780,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs) uint32_t i; struct object_id oid; - for (p = packed_git; p; p = p->next) { + for (p = get_packed_git(the_repository); p; p = p->next) { if (!p->pack_local || p->pack_keep) continue; @@ -3149,10 +3148,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) if (progress && all_progress_implied) progress = 2; - prepare_packed_git(); if (ignore_packed_keep) { struct packed_git *p; - for (p = packed_git; p; p = p->next) + for (p = get_packed_git(the_repository); p; p = p->next) if (p->pack_local && p->pack_keep) break; if (!p) /* no keep-able packs found */ @@ -3165,7 +3163,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) * also covers non-local objects */ struct packed_git *p; - for (p = packed_git; p; p = p->next) { + for (p = get_packed_git(the_repository); p; p = p->next) { if (!p->pack_local) { have_non_local_packs = 1; break; diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c index 991e1bb76f..354478a127 100644 --- a/builtin/pack-redundant.c +++ b/builtin/pack-redundant.c @@ -7,7 +7,9 @@ */ #include "builtin.h" +#include "repository.h" #include "packfile.h" +#include "object-store.h" #define BLKSIZE 512 @@ -571,7 +573,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 = packed_git; + struct packed_git *p = get_packed_git(the_repository); if (strlen(filename) < 40) die("Bad pack filename: %s", filename); @@ -586,7 +588,7 @@ static struct pack_list * add_pack_file(const char *filename) static void load_all(void) { - struct packed_git *p = packed_git; + struct packed_git *p = get_packed_git(the_repository); while (p) { add_pack(p); @@ -629,8 +631,6 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix) break; } - prepare_packed_git(); - if (load_all_packs) load_all(); else diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c index b106a392a4..f3353564f9 100644 --- a/builtin/pack-refs.c +++ b/builtin/pack-refs.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "parse-options.h" #include "refs.h" +#include "repository.h" static char const * const pack_refs_usage[] = { N_("git pack-refs [<options>]"), @@ -17,5 +18,5 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix) }; if (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0)) usage_with_options(pack_refs_usage, opts); - return refs_pack_refs(get_main_ref_store(), flags); + return refs_pack_refs(get_main_ref_store(the_repository), flags); } diff --git a/builtin/prune.c b/builtin/prune.c index 4394d01c93..38ced18dad 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -50,7 +50,7 @@ static int prune_object(const struct object_id *oid, const char *fullpath, if (st.st_mtime > expire) return 0; if (show_only || verbose) { - enum object_type type = sha1_object_info(oid->hash, NULL); + enum object_type type = oid_object_info(oid, NULL); printf("%s %s\n", oid_to_hex(oid), (type > 0) ? type_name(type) : "unknown"); } diff --git a/builtin/pull.c b/builtin/pull.c index 1876271af9..71aac5005e 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -9,7 +9,7 @@ #include "config.h" #include "builtin.h" #include "parse-options.h" -#include "exec_cmd.h" +#include "exec-cmd.h" #include "run-command.h" #include "sha1-array.h" #include "remote.h" @@ -193,7 +193,7 @@ static struct option pull_options[] = { OPT_PASSTHRU(0, "upload-pack", &opt_upload_pack, N_("path"), N_("path to upload pack on remote end"), 0), - OPT__FORCE(&opt_force, N_("force overwrite of local branch")), + OPT__FORCE(&opt_force, N_("force overwrite of local branch"), 0), OPT_PASSTHRU('t', "tags", &opt_tags, NULL, N_("fetch all tags and associated objects"), PARSE_OPT_NOARG), diff --git a/builtin/push.c b/builtin/push.c index 1c28427d82..013c20d616 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -548,7 +548,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) { 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( 0 , "thin", &thin, N_("use thin pack")), + OPT_BOOL_F( 0 , "thin", &thin, N_("use thin pack"), PARSE_OPT_NOCOMPLETE), OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", N_("receive pack program")), OPT_STRING( 0 , "exec", &receivepack, "receive-pack", N_("receive pack program")), OPT_BIT('u', "set-upstream", &flags, N_("set upstream for git pull/status"), diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 75e7f18ace..0dd163280d 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -1,4 +1,5 @@ #include "builtin.h" +#include "repository.h" #include "config.h" #include "lockfile.h" #include "pack.h" @@ -6,7 +7,7 @@ #include "pkt-line.h" #include "sideband.h" #include "run-command.h" -#include "exec_cmd.h" +#include "exec-cmd.h" #include "commit.h" #include "object.h" #include "remote.h" @@ -1242,11 +1243,11 @@ static void check_aliased_update(struct command *cmd, struct string_list *list) rp_error("refusing inconsistent update between symref '%s' (%s..%s) and" " its target '%s' (%s..%s)", cmd->ref_name, - find_unique_abbrev(cmd->old_oid.hash, DEFAULT_ABBREV), - find_unique_abbrev(cmd->new_oid.hash, DEFAULT_ABBREV), + find_unique_abbrev(&cmd->old_oid, DEFAULT_ABBREV), + find_unique_abbrev(&cmd->new_oid, DEFAULT_ABBREV), dst_cmd->ref_name, - find_unique_abbrev(dst_cmd->old_oid.hash, DEFAULT_ABBREV), - find_unique_abbrev(dst_cmd->new_oid.hash, DEFAULT_ABBREV)); + find_unique_abbrev(&dst_cmd->old_oid, DEFAULT_ABBREV), + find_unique_abbrev(&dst_cmd->new_oid, DEFAULT_ABBREV)); cmd->error_string = dst_cmd->error_string = "inconsistent aliased update"; @@ -1778,7 +1779,7 @@ static const char *unpack(int err_fd, struct shallow_info *si) status = finish_command(&child); if (status) return "index-pack abnormal exit"; - reprepare_packed_git(); + reprepare_packed_git(the_repository); } return NULL; } @@ -1964,6 +1965,12 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) unpack_limit = receive_unpack_limit; switch (determine_protocol_version_server()) { + case protocol_v2: + /* + * push support for protocol v2 has not been implemented yet, + * so ignore the request to use v2 and fallback to using v0. + */ + break; case protocol_v1: /* * v1 is just the original protocol with a version string, @@ -2027,7 +2034,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) proc.git_cmd = 1; proc.argv = argv_gc_auto; - close_all_packs(); + close_all_packs(the_repository->objects); if (!start_command(&proc)) { if (use_sideband) copy_to_sideband(proc.err, -1, NULL); diff --git a/builtin/reflog.c b/builtin/reflog.c index ac3dcd7a51..a89bd1dd25 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -52,6 +52,7 @@ struct collect_reflog_cb { int nr; }; +/* Remember to update object flag allocation in object.h */ #define INCOMPLETE (1u<<10) #define STUDYING (1u<<11) #define REACHABLE (1u<<12) @@ -74,7 +75,7 @@ static int tree_is_complete(const struct object_id *oid) if (!tree->buffer) { enum object_type type; unsigned long size; - void *data = read_sha1_file(oid->hash, &type, &size); + void *data = read_object_file(oid, &type, &size); if (!data) { tree->object.flags |= INCOMPLETE; return 0; diff --git a/builtin/remote.c b/builtin/remote.c index 6487d92abd..8708e584e9 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -168,7 +168,7 @@ static int add(int argc, const char **argv) OPT_STRING('m', "master", &master, N_("branch"), N_("master branch")), { OPTION_CALLBACK, 0, "mirror", &mirror, N_("push|fetch"), N_("set up remote as a mirror to push to or fetch from"), - PARSE_OPT_OPTARG, parse_mirror_opt }, + PARSE_OPT_OPTARG | PARSE_OPT_COMP_ARG, parse_mirror_opt }, OPT_END() }; @@ -862,7 +862,7 @@ static int get_remote_ref_states(const char *name, if (query) { transport = transport_get(states->remote, states->remote->url_nr > 0 ? states->remote->url[0] : NULL); - remote_refs = transport_get_remote_refs(transport); + remote_refs = transport_get_remote_refs(transport, NULL); transport_disconnect(transport); states->queried = 1; diff --git a/builtin/replace.c b/builtin/replace.c index 9f01f3fc7f..237ea656cf 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -14,6 +14,8 @@ #include "refs.h" #include "parse-options.h" #include "run-command.h" +#include "object-store.h" +#include "repository.h" #include "tag.h" static const char * const git_replace_usage[] = { @@ -53,8 +55,8 @@ static int show_reference(const char *refname, const struct object_id *oid, if (get_oid(refname, &object)) return error("Failed to resolve '%s' as a valid ref.", refname); - obj_type = sha1_object_info(object.hash, NULL); - repl_type = sha1_object_info(oid->hash, NULL); + obj_type = oid_object_info(&object, NULL); + repl_type = oid_object_info(oid, NULL); printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type), oid_to_hex(oid), type_name(repl_type)); @@ -83,7 +85,7 @@ static int list_replace_refs(const char *pattern, const char *format) "valid formats are 'short', 'medium' and 'long'\n", format); - for_each_replace_ref(show_reference, (void *)&data); + for_each_replace_ref(the_repository, show_reference, (void *)&data); return 0; } @@ -162,8 +164,8 @@ static int replace_object_oid(const char *object_ref, struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; - obj_type = sha1_object_info(object->hash, NULL); - repl_type = sha1_object_info(repl->hash, NULL); + obj_type = oid_object_info(object, NULL); + repl_type = oid_object_info(repl, NULL); if (!force && obj_type != repl_type) die("Objects must be of the same type.\n" "'%s' points to a replaced object of type '%s'\n" @@ -290,7 +292,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw) if (get_oid(object_ref, &old_oid) < 0) die("Not a valid object name: '%s'", object_ref); - type = sha1_object_info(old_oid.hash, NULL); + type = oid_object_info(&old_oid, NULL); if (type < 0) die("unable to get object type for %s", oid_to_hex(&old_oid)); @@ -439,7 +441,8 @@ int cmd_replace(int argc, const char **argv, const char *prefix) OPT_CMDMODE('d', "delete", &cmdmode, N_("delete replace refs"), MODE_DELETE), OPT_CMDMODE('e', "edit", &cmdmode, N_("edit existing object"), MODE_EDIT), OPT_CMDMODE('g', "graft", &cmdmode, N_("change a commit's parents"), MODE_GRAFT), - OPT_BOOL('f', "force", &force, N_("replace the ref if it exists")), + OPT_BOOL_F('f', "force", &force, N_("replace the ref if it exists"), + PARSE_OPT_NOCOMPLETE), OPT_BOOL(0, "raw", &raw, N_("do not pretty-print contents for --edit")), OPT_STRING(0, "format", &format, N_("format"), N_("use this format")), OPT_END() diff --git a/builtin/reset.c b/builtin/reset.c index 5da0f75de9..7f1c3f02a3 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -109,7 +109,7 @@ static void print_new_head_line(struct commit *commit) struct strbuf buf = STRBUF_INIT; printf(_("HEAD is now at %s"), - find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV)); + find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV)); pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf); if (buf.len > 0) diff --git a/builtin/rev-list.c b/builtin/rev-list.c index d320b6f1e3..fadd3ec14c 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -108,7 +108,7 @@ static void show_commit(struct commit *commit, void *data) if (!revs->graph) fputs(get_revision_mark(revs, commit), stdout); if (revs->abbrev_commit && revs->abbrev) - fputs(find_unique_abbrev(commit->object.oid.hash, revs->abbrev), + fputs(find_unique_abbrev(&commit->object.oid, revs->abbrev), stdout); else fputs(oid_to_hex(&commit->object.oid), stdout); @@ -536,7 +536,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) mark_edges_uninteresting(&revs, show_edge); if (bisect_list) { - int reaches = reaches, all = all; + int reaches, all; find_bisection(&revs.commits, &reaches, &all, bisect_find_all); diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index a1e680b5e9..36b2087782 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -159,7 +159,7 @@ static void show_rev(int type, const struct object_id *oid, const char *name) } } else if (abbrev) - show_with_type(type, find_unique_abbrev(oid->hash, abbrev)); + show_with_type(type, find_unique_abbrev(oid, abbrev)); else show_with_type(type, oid_to_hex(oid)); } diff --git a/builtin/rm.c b/builtin/rm.c index 4a2fcca27b..5b6fc7ee81 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -178,7 +178,7 @@ static int check_local_mod(struct object_id *head, int index_only) * way as changed from the HEAD. */ if (no_head - || get_tree_entry(head->hash, name, oid.hash, &mode) + || get_tree_entry(head, name, &oid, &mode) || ce->ce_mode != create_ce_mode(mode) || oidcmp(&ce->oid, &oid)) staged_changes = 1; @@ -242,7 +242,7 @@ static struct option builtin_rm_options[] = { OPT__DRY_RUN(&show_only, N_("dry run")), OPT__QUIET(&quiet, N_("do not list removed files")), OPT_BOOL( 0 , "cached", &index_only, N_("only remove from the index")), - OPT__FORCE(&force, N_("override the up-to-date check")), + OPT__FORCE(&force, N_("override the up-to-date check"), PARSE_OPT_NOCOMPLETE), OPT_BOOL('r', NULL, &recursive, N_("allow recursive removal")), OPT_BOOL( 0 , "ignore-unmatch", &ignore_unmatch, N_("exit with a zero status even if nothing matched")), @@ -385,10 +385,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix) stage_updated_gitmodules(&the_index); } - if (active_cache_changed) { - if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) - die(_("Unable to write new index file")); - } + if (write_locked_index(&the_index, &lock_file, + COMMIT_LOCK | SKIP_IF_UNCHANGED)) + die(_("Unable to write new index file")); return 0; } diff --git a/builtin/send-pack.c b/builtin/send-pack.c index fc4f0bb5fb..b5427f75e3 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -14,6 +14,7 @@ #include "sha1-array.h" #include "gpg-interface.h" #include "gettext.h" +#include "protocol.h" static const char * const send_pack_usage[] = { N_("git send-pack [--all | --mirror] [--dry-run] [--force] " @@ -154,6 +155,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) int progress = -1; int from_stdin = 0; struct push_cas_option cas = {0}; + struct packet_reader reader; struct option options[] = { OPT__VERBOSITY(&verbose), @@ -256,8 +258,22 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) args.verbose ? CONNECT_VERBOSE : 0); } - get_remote_heads(fd[0], NULL, 0, &remote_refs, REF_NORMAL, - &extra_have, &shallow); + packet_reader_init(&reader, fd[0], NULL, 0, + PACKET_READ_CHOMP_NEWLINE | + PACKET_READ_GENTLE_ON_EOF); + + switch (discover_version(&reader)) { + case protocol_v2: + die("support for protocol v2 not implemented yet"); + break; + case protocol_v1: + case protocol_v0: + get_remote_heads(&reader, &remote_refs, REF_NORMAL, + &extra_have, &shallow); + break; + case protocol_unknown_version: + BUG("unknown protocol version"); + } transport_verify_remote_names(nr_refspecs, refspecs); diff --git a/builtin/serve.c b/builtin/serve.c new file mode 100644 index 0000000000..d3fd240bb3 --- /dev/null +++ b/builtin/serve.c @@ -0,0 +1,30 @@ +#include "cache.h" +#include "builtin.h" +#include "parse-options.h" +#include "serve.h" + +static char const * const serve_usage[] = { + N_("git serve [<options>]"), + NULL +}; + +int cmd_serve(int argc, const char **argv, const char *prefix) +{ + struct serve_options opts = SERVE_OPTIONS_INIT; + + struct option options[] = { + OPT_BOOL(0, "stateless-rpc", &opts.stateless_rpc, + N_("quit after a single request/response exchange")), + OPT_BOOL(0, "advertise-capabilities", &opts.advertise_capabilities, + N_("exit immediately after advertising capabilities")), + OPT_END() + }; + + /* ignore all unknown cmdline switches for now */ + argc = parse_options(argc, argv, prefix, options, serve_usage, + PARSE_OPT_KEEP_DASHDASH | + PARSE_OPT_KEEP_UNKNOWN); + serve(&opts); + + return 0; +} diff --git a/builtin/shortlog.c b/builtin/shortlog.c index e29875b843..608d6ba77b 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -11,7 +11,8 @@ #include "parse-options.h" static char const * const shortlog_usage[] = { - N_("git shortlog [<options>] [<revision-range>] [[--] [<path>...]]"), + N_("git shortlog [<options>] [<revision-range>] [[--] <path>...]"), + N_("git log --pretty=short | git shortlog [<options>]"), NULL }; @@ -283,6 +284,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) for (;;) { switch (parse_options_step(&ctx, options, shortlog_usage)) { case PARSE_OPT_HELP: + case PARSE_OPT_ERROR: exit(129); case PARSE_OPT_DONE: goto parse_done; @@ -292,6 +294,11 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) parse_done: argc = parse_options_end(&ctx); + if (nongit && argc > 1) { + error(_("too many arguments given outside repository")); + usage_with_options(shortlog_usage, options); + } + if (setup_revisions(argc, argv, &rev, NULL) != 1) { error(_("unrecognized argument: %s"), argv[1]); usage_with_options(shortlog_usage, options); diff --git a/builtin/show-branch.c b/builtin/show-branch.c index e8a4aa40cb..6c2148b71d 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -292,7 +292,7 @@ static void show_one_commit(struct commit *commit, int no_name) } else printf("[%s] ", - find_unique_abbrev(commit->object.oid.hash, + find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV)); } puts(pretty_str); diff --git a/builtin/show-ref.c b/builtin/show-ref.c index 41e5e71cad..f2eb1a7724 100644 --- a/builtin/show-ref.c +++ b/builtin/show-ref.c @@ -29,7 +29,7 @@ static void show_one(const char *refname, const struct object_id *oid) if (quiet) return; - hex = find_unique_abbrev(oid->hash, abbrev); + hex = find_unique_abbrev(oid, abbrev); if (hash_only) printf("%s\n", hex); else @@ -39,7 +39,7 @@ static void show_one(const char *refname, const struct object_id *oid) return; if (!peel_ref(refname, &peeled)) { - hex = find_unique_abbrev(peeled.hash, abbrev); + hex = find_unique_abbrev(&peeled, abbrev); printf("%s %s^{}\n", hex, refname); } } diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index b1daca995f..7586f776fe 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -16,6 +16,7 @@ #include "revision.h" #include "diffcore.h" #include "diff.h" +#include "object-store.h" #define OPT_QUIET (1 << 0) #define OPT_CACHED (1 << 1) @@ -454,7 +455,7 @@ static void init_submodule(const char *path, const char *prefix, displaypath = get_submodule_displaypath(path, prefix); - sub = submodule_from_path(&null_oid, path); + sub = submodule_from_path(the_repository, &null_oid, path); if (!sub) die(_("No url found for submodule path '%s' in .gitmodules"), @@ -621,7 +622,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid, struct rev_info rev; int diff_files_result; - if (!submodule_from_path(&null_oid, path)) + if (!submodule_from_path(the_repository, &null_oid, path)) die(_("no submodule mapping found in .gitmodules for path '%s'"), path); @@ -654,9 +655,13 @@ static void status_submodule(const char *path, const struct object_id *ce_oid, displaypath); } else if (!(flags & OPT_CACHED)) { struct object_id oid; + struct ref_store *refs = get_submodule_ref_store(path); - if (refs_head_ref(get_submodule_ref_store(path), - handle_submodule_head_ref, &oid)) + if (!refs) { + print_status(flags, '-', path, ce_oid, displaypath); + goto cleanup; + } + if (refs_head_ref(refs, handle_submodule_head_ref, &oid)) die(_("could not resolve HEAD ref inside the " "submodule '%s'"), path); @@ -741,7 +746,7 @@ static int module_name(int argc, const char **argv, const char *prefix) if (argc != 2) usage(_("git submodule--helper name <path>")); - sub = submodule_from_path(&null_oid, argv[1]); + sub = submodule_from_path(the_repository, &null_oid, argv[1]); if (!sub) die(_("no submodule mapping found in .gitmodules for path '%s'"), @@ -772,7 +777,7 @@ static void sync_submodule(const char *path, const char *prefix, if (!is_submodule_active(the_repository, path)) return; - sub = submodule_from_path(&null_oid, path); + sub = submodule_from_path(the_repository, &null_oid, path); if (sub && sub->url) { if (starts_with_dot_dot_slash(sub->url) || @@ -925,7 +930,7 @@ static void deinit_submodule(const char *path, const char *prefix, struct strbuf sb_config = STRBUF_INIT; char *sub_git_dir = xstrfmt("%s/.git", path); - sub = submodule_from_path(&null_oid, path); + sub = submodule_from_path(the_repository, &null_oid, path); if (!sub || !sub->name) goto cleanup; @@ -1019,7 +1024,7 @@ static int module_deinit(int argc, const char **argv, const char *prefix) struct option module_deinit_options[] = { OPT__QUIET(&quiet, N_("Suppress submodule status output")), - OPT__FORCE(&force, N_("Remove submodule working trees even if they contain local changes")), + OPT__FORCE(&force, N_("Remove submodule working trees even if they contain local changes"), 0), OPT_BOOL(0, "all", &all, N_("Unregister all submodules")), OPT_END() }; @@ -1042,7 +1047,7 @@ static int module_deinit(int argc, const char **argv, const char *prefix) die(_("Use '--all' if you really want to deinitialize all submodules")); if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0) - BUG("module_list_compute should not choke on empty pathspec"); + return 1; info.prefix = prefix; if (quiet) @@ -1259,8 +1264,7 @@ static int module_clone(int argc, const char **argv, const char *prefix) strbuf_reset(&sb); } - /* Connect module worktree and git dir */ - connect_work_tree_and_git_dir(path, sm_gitdir); + connect_work_tree_and_git_dir(path, sm_gitdir, 0); p = git_pathdup_submodule(path, "config"); if (!p) @@ -1367,7 +1371,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, goto cleanup; } - sub = submodule_from_path(&null_oid, ce->name); + sub = submodule_from_path(the_repository, &null_oid, ce->name); if (suc->recursive_prefix) displaypath = relative_path(suc->recursive_prefix, @@ -1650,7 +1654,7 @@ static const char *remote_submodule_branch(const char *path) const char *branch = NULL; char *key; - sub = submodule_from_path(&null_oid, path); + sub = submodule_from_path(the_repository, &null_oid, path); if (!sub) return NULL; diff --git a/builtin/tag.c b/builtin/tag.c index 8c493a569f..46a5c6a1da 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -99,7 +99,8 @@ static int delete_tag(const char *name, const char *ref, { if (delete_ref(NULL, ref, oid, 0)) return 1; - printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(oid->hash, DEFAULT_ABBREV)); + printf(_("Deleted tag '%s' (was %s)\n"), name, + find_unique_abbrev(oid, DEFAULT_ABBREV)); return 0; } @@ -117,7 +118,7 @@ static int verify_tag(const char *name, const char *ref, return -1; if (format->format) - pretty_print_ref(name, oid->hash, format); + pretty_print_ref(name, oid, format); return 0; } @@ -167,7 +168,7 @@ static void write_tag_body(int fd, const struct object_id *oid) enum object_type type; char *buf, *sp; - buf = read_sha1_file(oid->hash, &type, &size); + buf = read_object_file(oid, &type, &size); if (!buf) return; /* skip header */ @@ -211,7 +212,7 @@ static void create_tag(const struct object_id *object, const char *tag, struct strbuf header = STRBUF_INIT; char *path = NULL; - type = sha1_object_info(object->hash, NULL); + type = oid_object_info(object, NULL); if (type <= OBJ_NONE) die(_("bad object type.")); @@ -293,17 +294,17 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb) strbuf_addstr(sb, rla); } else { strbuf_addstr(sb, "tag: tagging "); - strbuf_add_unique_abbrev(sb, oid->hash, DEFAULT_ABBREV); + strbuf_add_unique_abbrev(sb, oid, DEFAULT_ABBREV); } strbuf_addstr(sb, " ("); - type = sha1_object_info(oid->hash, NULL); + type = oid_object_info(oid, NULL); switch (type) { default: strbuf_addstr(sb, "object of unknown type"); break; case OBJ_COMMIT: - if ((buf = read_sha1_file(oid->hash, &type, &size)) != NULL) { + if ((buf = read_object_file(oid, &type, &size)) != NULL) { subject_len = find_commit_subject(buf, &subject_start); strbuf_insert(sb, sb->len, subject_start, subject_len); } else { @@ -397,7 +398,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) N_("how to strip spaces and #comments from message")), OPT_STRING('u', "local-user", &keyid, N_("key-id"), N_("use another key to sign the tag")), - OPT__FORCE(&force, N_("replace the tag if exists")), + OPT__FORCE(&force, N_("replace the tag if exists"), 0), OPT_BOOL(0, "create-reflog", &create_reflog, N_("create a reflog")), OPT_GROUP(N_("Tag listing options")), @@ -558,7 +559,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix) die("%s", err.buf); ref_transaction_free(transaction); if (force && !is_null_oid(&prev) && oidcmp(&prev, &object)) - printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev.hash, DEFAULT_ABBREV)); + printf(_("Updated tag '%s' (was %s)\n"), tag, + find_unique_abbrev(&prev, DEFAULT_ABBREV)); UNLEAK(buf); UNLEAK(ref); diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c index 32e0155577..300eb59657 100644 --- a/builtin/unpack-file.c +++ b/builtin/unpack-file.c @@ -9,7 +9,7 @@ static char *create_temp_file(struct object_id *oid) unsigned long size; int fd; - buf = read_sha1_file(oid->hash, &type, &size); + buf = read_object_file(oid, &type, &size); if (!buf || type != OBJ_BLOB) die("unable to read blob object %s", oid_to_hex(oid)); diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index 9f96949bc0..b7755c6cc5 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -158,6 +158,7 @@ struct obj_info { struct object *obj; }; +/* Remember to update object flag allocation in object.h */ #define FLAG_OPEN (1u<<20) #define FLAG_WRITTEN (1u<<21) @@ -198,7 +199,7 @@ static int check_object(struct object *obj, int type, void *data, struct fsck_op if (!(obj->flags & FLAG_OPEN)) { unsigned long size; - int type = sha1_object_info(obj->oid.hash, &size); + int type = oid_object_info(&obj->oid, &size); if (type != obj->type || type <= 0) die("object of unexpected type"); obj->flags |= FLAG_WRITTEN; @@ -422,7 +423,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size, if (resolve_against_held(nr, &base_oid, delta_data, delta_size)) return; - base = read_sha1_file(base_oid.hash, &type, &base_size); + base = read_object_file(&base_oid, &type, &base_size); if (!base) { error("failed to read delta-pack base object %s", oid_to_hex(&base_oid)); diff --git a/builtin/update-index.c b/builtin/update-index.c index 58d1c2d282..10d070a76f 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -592,7 +592,7 @@ static struct cache_entry *read_one_ent(const char *which, int size; struct cache_entry *ce; - if (get_tree_entry(ent->hash, path, oid.hash, &mode)) { + if (get_tree_entry(ent, path, &oid, &mode)) { if (which) error("%s: not in %s branch.", path, which); return NULL; @@ -1059,6 +1059,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) break; switch (parseopt_state) { case PARSE_OPT_HELP: + case PARSE_OPT_ERROR: exit(129); case PARSE_OPT_NON_OPTION: case PARSE_OPT_DONE: diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c index 873070e517..4321a34456 100644 --- a/builtin/update-server-info.c +++ b/builtin/update-server-info.c @@ -12,7 +12,7 @@ int cmd_update_server_info(int argc, const char **argv, const char *prefix) { int force = 0; struct option options[] = { - OPT__FORCE(&force, N_("update the info files from scratch")), + OPT__FORCE(&force, N_("update the info files from scratch"), 0), OPT_END() }; diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c new file mode 100644 index 0000000000..decde5a3b1 --- /dev/null +++ b/builtin/upload-pack.c @@ -0,0 +1,74 @@ +#include "cache.h" +#include "builtin.h" +#include "exec-cmd.h" +#include "pkt-line.h" +#include "parse-options.h" +#include "protocol.h" +#include "upload-pack.h" +#include "serve.h" + +static const char * const upload_pack_usage[] = { + N_("git upload-pack [<options>] <dir>"), + NULL +}; + +int cmd_upload_pack(int argc, const char **argv, const char *prefix) +{ + const char *dir; + int strict = 0; + struct upload_pack_options opts = { 0 }; + struct serve_options serve_opts = SERVE_OPTIONS_INIT; + struct option options[] = { + OPT_BOOL(0, "stateless-rpc", &opts.stateless_rpc, + N_("quit after a single request/response exchange")), + OPT_BOOL(0, "advertise-refs", &opts.advertise_refs, + N_("exit immediately after initial ref advertisement")), + OPT_BOOL(0, "strict", &strict, + N_("do not try <directory>/.git/ if <directory> is no Git directory")), + OPT_INTEGER(0, "timeout", &opts.timeout, + N_("interrupt transfer after <n> seconds of inactivity")), + OPT_END() + }; + + packet_trace_identity("upload-pack"); + check_replace_refs = 0; + + argc = parse_options(argc, argv, NULL, options, upload_pack_usage, 0); + + if (argc != 1) + usage_with_options(upload_pack_usage, options); + + if (opts.timeout) + opts.daemon_mode = 1; + + setup_path(); + + dir = argv[0]; + + if (!enter_repo(dir, strict)) + die("'%s' does not appear to be a git repository", dir); + + switch (determine_protocol_version_server()) { + case protocol_v2: + serve_opts.advertise_capabilities = opts.advertise_refs; + serve_opts.stateless_rpc = opts.stateless_rpc; + serve(&serve_opts); + break; + case protocol_v1: + /* + * v1 is just the original protocol with a version string, + * so just fall through after writing the version string. + */ + if (opts.advertise_refs || !opts.stateless_rpc) + packet_write_fmt(1, "version 1\n"); + + /* fallthrough */ + case protocol_v0: + upload_pack(&opts); + break; + case protocol_unknown_version: + BUG("unknown protocol version"); + } + + return 0; +} diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c index 05315ea7c9..dcdaada111 100644 --- a/builtin/verify-commit.c +++ b/builtin/verify-commit.c @@ -44,7 +44,7 @@ static int verify_commit(const char *name, unsigned flags) if (get_oid(name, &oid)) return error("commit '%s' not found.", name); - buf = read_sha1_file(oid.hash, &type, &size); + buf = read_object_file(&oid, &type, &size); if (!buf) return error("%s: unable to read file.", name); if (type != OBJ_COMMIT) diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c index ad7b79fa5c..6fa04b751a 100644 --- a/builtin/verify-tag.c +++ b/builtin/verify-tag.c @@ -72,7 +72,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix) } if (format.format) - pretty_print_ref(name, oid.hash, &format); + pretty_print_ref(name, &oid, &format); } return had_error; } diff --git a/builtin/worktree.c b/builtin/worktree.c index 4e7c98758f..40a438ed6c 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -17,7 +17,9 @@ static const char * const worktree_usage[] = { N_("git worktree add [<options>] <path> [<commit-ish>]"), N_("git worktree list [<options>]"), N_("git worktree lock [<options>] <path>"), + N_("git worktree move <worktree> <new-path>"), N_("git worktree prune [<options>]"), + N_("git worktree remove [<options>] <worktree>"), N_("git worktree unlock <path>"), NULL }; @@ -99,16 +101,9 @@ static int prune_worktree(const char *id, struct strbuf *reason) } path[len] = '\0'; if (!file_exists(path)) { - struct stat st_link; free(path); - /* - * the repo is moved manually and has not been - * accessed since? - */ - if (!stat(git_path("worktrees/%s/link", id), &st_link) && - st_link.st_nlink > 1) - return 0; - if (st.st_mtime <= expire) { + if (stat(git_path("worktrees/%s/index", id), &st) || + st.st_mtime <= expire) { strbuf_addf(reason, _("Removing worktrees/%s: gitdir file points to non-existent location"), id); return 1; } else { @@ -379,7 +374,9 @@ static int add(int ac, const char **av, const char *prefix) const char *branch; const char *opt_track = NULL; struct option options[] = { - OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")), + OPT__FORCE(&opts.force, + N_("checkout <branch> even if already checked out in other worktree"), + PARSE_OPT_NOCOMPLETE), OPT_STRING('b', NULL, &opts.new_branch, N_("branch"), N_("create a new branch")), OPT_STRING('B', NULL, &new_branch_force, N_("branch"), @@ -498,7 +495,7 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len) strbuf_addstr(&sb, "(bare)"); else { strbuf_addf(&sb, "%-*s ", abbrev_len, - find_unique_abbrev(wt->head_oid.hash, DEFAULT_ABBREV)); + find_unique_abbrev(&wt->head_oid, DEFAULT_ABBREV)); if (wt->is_detached) strbuf_addstr(&sb, "(detached HEAD)"); else if (wt->head_ref) { @@ -523,7 +520,7 @@ static void measure_widths(struct worktree **wt, int *abbrev, int *maxlen) if (path_len > *maxlen) *maxlen = path_len; - sha1_len = strlen(find_unique_abbrev(wt[i]->head_oid.hash, *abbrev)); + sha1_len = strlen(find_unique_abbrev(&wt[i]->head_oid, *abbrev)); if (sha1_len > *abbrev) *abbrev = sha1_len; } @@ -619,6 +616,220 @@ static int unlock_worktree(int ac, const char **av, const char *prefix) return ret; } +static void validate_no_submodules(const struct worktree *wt) +{ + struct index_state istate = { NULL }; + int i, found_submodules = 0; + + if (read_index_from(&istate, worktree_git_path(wt, "index"), + get_worktree_git_dir(wt)) > 0) { + for (i = 0; i < istate.cache_nr; i++) { + struct cache_entry *ce = istate.cache[i]; + + if (S_ISGITLINK(ce->ce_mode)) { + found_submodules = 1; + break; + } + } + } + discard_index(&istate); + + if (found_submodules) + die(_("working trees containing submodules cannot be moved or removed")); +} + +static int move_worktree(int ac, const char **av, const char *prefix) +{ + struct option options[] = { + OPT_END() + }; + struct worktree **worktrees, *wt; + struct strbuf dst = STRBUF_INIT; + struct strbuf errmsg = STRBUF_INIT; + const char *reason; + char *path; + + ac = parse_options(ac, av, prefix, options, worktree_usage, 0); + if (ac != 2) + usage_with_options(worktree_usage, options); + + path = prefix_filename(prefix, av[1]); + strbuf_addstr(&dst, path); + free(path); + + worktrees = get_worktrees(0); + wt = find_worktree(worktrees, prefix, av[0]); + if (!wt) + die(_("'%s' is not a working tree"), av[0]); + if (is_main_worktree(wt)) + die(_("'%s' is a main working tree"), av[0]); + if (is_directory(dst.buf)) { + const char *sep = find_last_dir_sep(wt->path); + + if (!sep) + die(_("could not figure out destination name from '%s'"), + wt->path); + strbuf_trim_trailing_dir_sep(&dst); + strbuf_addstr(&dst, sep); + } + if (file_exists(dst.buf)) + die(_("target '%s' already exists"), dst.buf); + + validate_no_submodules(wt); + + reason = is_worktree_locked(wt); + if (reason) { + if (*reason) + die(_("cannot move a locked working tree, lock reason: %s"), + reason); + die(_("cannot move a locked working tree")); + } + if (validate_worktree(wt, &errmsg, 0)) + die(_("validation failed, cannot move working tree: %s"), + errmsg.buf); + strbuf_release(&errmsg); + + if (rename(wt->path, dst.buf) == -1) + die_errno(_("failed to move '%s' to '%s'"), wt->path, dst.buf); + + update_worktree_location(wt, dst.buf); + + strbuf_release(&dst); + free_worktrees(worktrees); + return 0; +} + +/* + * Note, "git status --porcelain" is used to determine if it's safe to + * delete a whole worktree. "git status" does not ignore user + * configuration, so if a normal "git status" shows "clean" for the + * user, then it's ok to remove it. + * + * This assumption may be a bad one. We may want to ignore + * (potentially bad) user settings and only delete a worktree when + * it's absolutely safe to do so from _our_ point of view because we + * know better. + */ +static void check_clean_worktree(struct worktree *wt, + const char *original_path) +{ + struct argv_array child_env = ARGV_ARRAY_INIT; + struct child_process cp; + char buf[1]; + int ret; + + /* + * Until we sort this out, all submodules are "dirty" and + * will abort this function. + */ + validate_no_submodules(wt); + + argv_array_pushf(&child_env, "%s=%s/.git", + GIT_DIR_ENVIRONMENT, wt->path); + argv_array_pushf(&child_env, "%s=%s", + GIT_WORK_TREE_ENVIRONMENT, wt->path); + memset(&cp, 0, sizeof(cp)); + argv_array_pushl(&cp.args, "status", + "--porcelain", "--ignore-submodules=none", + NULL); + cp.env = child_env.argv; + cp.git_cmd = 1; + cp.dir = wt->path; + cp.out = -1; + ret = start_command(&cp); + if (ret) + die_errno(_("failed to run 'git status' on '%s'"), + original_path); + ret = xread(cp.out, buf, sizeof(buf)); + if (ret) + die(_("'%s' is dirty, use --force to delete it"), + original_path); + close(cp.out); + ret = finish_command(&cp); + if (ret) + die_errno(_("failed to run 'git status' on '%s', code %d"), + original_path, ret); +} + +static int delete_git_work_tree(struct worktree *wt) +{ + struct strbuf sb = STRBUF_INIT; + int ret = 0; + + strbuf_addstr(&sb, wt->path); + if (remove_dir_recursively(&sb, 0)) { + error_errno(_("failed to delete '%s'"), sb.buf); + ret = -1; + } + strbuf_release(&sb); + return ret; +} + +static int delete_git_dir(struct worktree *wt) +{ + struct strbuf sb = STRBUF_INIT; + int ret = 0; + + strbuf_addstr(&sb, git_common_path("worktrees/%s", wt->id)); + if (remove_dir_recursively(&sb, 0)) { + error_errno(_("failed to delete '%s'"), sb.buf); + ret = -1; + } + strbuf_release(&sb); + return ret; +} + +static int remove_worktree(int ac, const char **av, const char *prefix) +{ + int force = 0; + struct option options[] = { + OPT_BOOL(0, "force", &force, + N_("force removing even if the worktree is dirty")), + OPT_END() + }; + struct worktree **worktrees, *wt; + struct strbuf errmsg = STRBUF_INIT; + const char *reason; + int ret = 0; + + ac = parse_options(ac, av, prefix, options, worktree_usage, 0); + if (ac != 1) + usage_with_options(worktree_usage, options); + + worktrees = get_worktrees(0); + wt = find_worktree(worktrees, prefix, av[0]); + if (!wt) + die(_("'%s' is not a working tree"), av[0]); + if (is_main_worktree(wt)) + die(_("'%s' is a main working tree"), av[0]); + reason = is_worktree_locked(wt); + if (reason) { + if (*reason) + die(_("cannot remove a locked working tree, lock reason: %s"), + reason); + die(_("cannot remove a locked working tree")); + } + if (validate_worktree(wt, &errmsg, WT_VALIDATE_WORKTREE_MISSING_OK)) + die(_("validation failed, cannot remove working tree: %s"), + errmsg.buf); + strbuf_release(&errmsg); + + if (file_exists(wt->path)) { + if (!force) + check_clean_worktree(wt, av[0]); + + ret |= delete_git_work_tree(wt); + } + /* + * continue on even if ret is non-zero, there's no going back + * from here. + */ + ret |= delete_git_dir(wt); + + free_worktrees(worktrees); + return ret; +} + int cmd_worktree(int ac, const char **av, const char *prefix) { struct option options[] = { @@ -641,5 +852,9 @@ int cmd_worktree(int ac, const char **av, const char *prefix) return lock_worktree(ac - 1, av + 1, prefix); if (!strcmp(av[1], "unlock")) return unlock_worktree(ac - 1, av + 1, prefix); + if (!strcmp(av[1], "move")) + return move_worktree(ac - 1, av + 1, prefix); + if (!strcmp(av[1], "remove")) + return remove_worktree(ac - 1, av + 1, prefix); usage_with_options(worktree_usage, options); } diff --git a/builtin/write-tree.c b/builtin/write-tree.c index bd0a78aa3c..c9d3c544e7 100644 --- a/builtin/write-tree.c +++ b/builtin/write-tree.c @@ -19,7 +19,7 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix) { int flags = 0, ret; const char *prefix = NULL; - unsigned char sha1[20]; + struct object_id oid; const char *me = "git-write-tree"; struct option write_tree_options[] = { OPT_BIT(0, "missing-ok", &flags, N_("allow missing objects"), @@ -38,10 +38,10 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix) argc = parse_options(argc, argv, unused_prefix, write_tree_options, write_tree_usage, 0); - ret = write_cache_as_tree(sha1, flags, prefix); + ret = write_cache_as_tree(&oid, flags, prefix); switch (ret) { case 0: - printf("%s\n", sha1_to_hex(sha1)); + printf("%s\n", oid_to_hex(&oid)); break; case WRITE_TREE_UNREADABLE_INDEX: die("%s: error reading the index", me); |