diff options
Diffstat (limited to 'builtin')
| -rw-r--r-- | builtin/blame.c | 15 | ||||
| -rw-r--r-- | builtin/cat-file.c | 256 | ||||
| -rw-r--r-- | builtin/checkout.c | 10 | ||||
| -rw-r--r-- | builtin/clone.c | 7 | ||||
| -rw-r--r-- | builtin/fetch.c | 51 | ||||
| -rw-r--r-- | builtin/gc.c | 92 | ||||
| -rw-r--r-- | builtin/merge-recursive.c | 4 | ||||
| -rw-r--r-- | builtin/merge.c | 23 | ||||
| -rw-r--r-- | builtin/pack-objects.c | 6 | ||||
| -rw-r--r-- | builtin/pull.c | 3 | ||||
| -rw-r--r-- | builtin/rebase.c | 7 | ||||
| -rw-r--r-- | builtin/reflog.c | 221 | ||||
| -rw-r--r-- | builtin/remote.c | 2 | ||||
| -rw-r--r-- | builtin/rev-list.c | 96 | ||||
| -rw-r--r-- | builtin/revert.c | 2 | ||||
| -rw-r--r-- | builtin/rm.c | 21 | ||||
| -rw-r--r-- | builtin/update-ref.c | 66 | ||||
| -rw-r--r-- | builtin/update-server-info.c | 4 |
18 files changed, 553 insertions, 333 deletions
diff --git a/builtin/blame.c b/builtin/blame.c index 4e156bfd19..5bf11c2a3c 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -351,6 +351,19 @@ static void emit_porcelain_details(struct blame_origin *suspect, int repeat) write_filename_info(suspect); } +/* + * Information which needs to be printed per-line goes here. Any + * information which can be clubbed on a commit/file level, should + * be printed via 'emit_one_suspect_detail()'. + */ +static void emit_porcelain_per_line_details(struct blame_entry *ent) +{ + if (mark_unblamable_lines && ent->unblamable) + puts("unblamable"); + if (mark_ignored_lines && ent->ignored) + puts("ignored"); +} + static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent, int opt) { @@ -367,6 +380,7 @@ static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent, ent->lno + 1, ent->num_lines); emit_porcelain_details(suspect, repeat); + emit_porcelain_per_line_details(ent); cp = blame_nth_line(sb, ent->lno); for (cnt = 0; cnt < ent->num_lines; cnt++) { @@ -377,6 +391,7 @@ static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent, ent->lno + 1 + cnt); if (repeat) emit_porcelain_details(suspect, 1); + emit_porcelain_per_line_details(ent); } putchar('\t'); do { diff --git a/builtin/cat-file.c b/builtin/cat-file.c index c870fde260..0e3f10a946 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -15,11 +15,13 @@ #include "gettext.h" #include "hex.h" #include "ident.h" +#include "list-objects-filter-options.h" #include "parse-options.h" #include "userdiff.h" #include "streaming.h" #include "oid-array.h" #include "packfile.h" +#include "pack-bitmap.h" #include "object-file.h" #include "object-name.h" #include "object-store.h" @@ -35,6 +37,7 @@ enum batch_mode { }; struct batch_options { + struct list_objects_filter_options objects_filter; int enabled; int follow_symlinks; enum batch_mode batch_mode; @@ -455,6 +458,16 @@ static void print_default_format(struct strbuf *scratch, struct expand_data *dat (uintmax_t)data->size, opt->output_delim); } +static void report_object_status(struct batch_options *opt, + const char *obj_name, + const struct object_id *oid, + const char *status) +{ + printf("%s %s%c", obj_name ? obj_name : oid_to_hex(oid), + status, opt->output_delim); + fflush(stdout); +} + /* * If "pack" is non-NULL, then "offset" is the byte offset within the pack from * which the object may be accessed (though note that we may also rely on @@ -470,8 +483,13 @@ static void batch_object_write(const char *obj_name, if (!data->skip_object_info) { int ret; - if (use_mailmap) + if (use_mailmap || + opt->objects_filter.choice == LOFC_BLOB_NONE || + opt->objects_filter.choice == LOFC_BLOB_LIMIT || + opt->objects_filter.choice == LOFC_OBJECT_TYPE) data->info.typep = &data->type; + if (opt->objects_filter.choice == LOFC_BLOB_LIMIT) + data->info.sizep = &data->size; if (pack) ret = packed_object_info(the_repository, pack, offset, @@ -481,12 +499,42 @@ static void batch_object_write(const char *obj_name, &data->oid, &data->info, OBJECT_INFO_LOOKUP_REPLACE); if (ret < 0) { - printf("%s missing%c", - obj_name ? obj_name : oid_to_hex(&data->oid), opt->output_delim); - fflush(stdout); + report_object_status(opt, obj_name, &data->oid, "missing"); return; } + switch (opt->objects_filter.choice) { + case LOFC_DISABLED: + break; + case LOFC_BLOB_NONE: + if (data->type == OBJ_BLOB) { + if (!opt->all_objects) + report_object_status(opt, obj_name, + &data->oid, "excluded"); + return; + } + break; + case LOFC_BLOB_LIMIT: + if (data->type == OBJ_BLOB && + data->size >= opt->objects_filter.blob_limit_value) { + if (!opt->all_objects) + report_object_status(opt, obj_name, + &data->oid, "excluded"); + return; + } + break; + case LOFC_OBJECT_TYPE: + if (data->type != opt->objects_filter.object_type) { + if (!opt->all_objects) + report_object_status(opt, obj_name, + &data->oid, "excluded"); + return; + } + break; + default: + BUG("unsupported objects filter"); + } + if (use_mailmap && (data->type == OBJ_COMMIT || data->type == OBJ_TAG)) { size_t s = data->size; char *buf = NULL; @@ -535,10 +583,10 @@ static void batch_one_object(const char *obj_name, if (result != FOUND) { switch (result) { case MISSING_OBJECT: - printf("%s missing%c", obj_name, opt->output_delim); + report_object_status(opt, obj_name, &data->oid, "missing"); break; case SHORT_NAME_AMBIGUOUS: - printf("%s ambiguous%c", obj_name, opt->output_delim); + report_object_status(opt, obj_name, &data->oid, "ambiguous"); break; case DANGLING_SYMLINK: printf("dangling %"PRIuMAX"%c%s%c", @@ -595,25 +643,18 @@ static int batch_object_cb(const struct object_id *oid, void *vdata) return 0; } -static int collect_loose_object(const struct object_id *oid, - const char *path UNUSED, - void *data) -{ - oid_array_append(data, oid); - return 0; -} - -static int collect_packed_object(const struct object_id *oid, - struct packed_git *pack UNUSED, - uint32_t pos UNUSED, - void *data) +static int collect_object(const struct object_id *oid, + struct packed_git *pack UNUSED, + off_t offset UNUSED, + void *data) { oid_array_append(data, oid); return 0; } static int batch_unordered_object(const struct object_id *oid, - struct packed_git *pack, off_t offset, + struct packed_git *pack, + off_t offset, void *vdata) { struct object_cb_data *data = vdata; @@ -627,23 +668,6 @@ static int batch_unordered_object(const struct object_id *oid, return 0; } -static int batch_unordered_loose(const struct object_id *oid, - const char *path UNUSED, - void *data) -{ - return batch_unordered_object(oid, NULL, 0, data); -} - -static int batch_unordered_packed(const struct object_id *oid, - struct packed_git *pack, - uint32_t pos, - void *data) -{ - return batch_unordered_object(oid, pack, - nth_packed_object_offset(pack, pos), - data); -} - typedef void (*parse_cmd_fn_t)(struct batch_options *, const char *, struct strbuf *, struct expand_data *); @@ -776,6 +800,76 @@ static void batch_objects_command(struct batch_options *opt, #define DEFAULT_FORMAT "%(objectname) %(objecttype) %(objectsize)" +typedef int (*for_each_object_fn)(const struct object_id *oid, struct packed_git *pack, + off_t offset, void *data); + +struct for_each_object_payload { + for_each_object_fn callback; + void *payload; +}; + +static int batch_one_object_loose(const struct object_id *oid, + const char *path UNUSED, + void *_payload) +{ + struct for_each_object_payload *payload = _payload; + return payload->callback(oid, NULL, 0, payload->payload); +} + +static int batch_one_object_packed(const struct object_id *oid, + struct packed_git *pack, + uint32_t pos, + void *_payload) +{ + struct for_each_object_payload *payload = _payload; + return payload->callback(oid, pack, nth_packed_object_offset(pack, pos), + payload->payload); +} + +static int batch_one_object_bitmapped(const struct object_id *oid, + enum object_type type UNUSED, + int flags UNUSED, + uint32_t hash UNUSED, + struct packed_git *pack, + off_t offset, + void *_payload) +{ + struct for_each_object_payload *payload = _payload; + return payload->callback(oid, pack, offset, payload->payload); +} + +static void batch_each_object(struct batch_options *opt, + for_each_object_fn callback, + unsigned flags, + void *_payload) +{ + struct for_each_object_payload payload = { + .callback = callback, + .payload = _payload, + }; + struct bitmap_index *bitmap = prepare_bitmap_git(the_repository); + + for_each_loose_object(batch_one_object_loose, &payload, 0); + + if (bitmap && !for_each_bitmapped_object(bitmap, &opt->objects_filter, + batch_one_object_bitmapped, &payload)) { + struct packed_git *pack; + + for (pack = get_all_packs(the_repository); pack; pack = pack->next) { + if (bitmap_index_contains_pack(bitmap, pack) || + open_pack_index(pack)) + continue; + for_each_object_in_pack(pack, batch_one_object_packed, + &payload, flags); + } + } else { + for_each_packed_object(the_repository, batch_one_object_packed, + &payload, flags); + } + + free_bitmap_index(bitmap); +} + static int batch_objects(struct batch_options *opt) { struct strbuf input = STRBUF_INIT; @@ -812,7 +906,8 @@ static int batch_objects(struct batch_options *opt) struct object_cb_data cb; struct object_info empty = OBJECT_INFO_INIT; - if (!memcmp(&data.info, &empty, sizeof(empty))) + if (!memcmp(&data.info, &empty, sizeof(empty)) && + opt->objects_filter.choice == LOFC_DISABLED) data.skip_object_info = 1; if (repo_has_promisor_remote(the_repository)) @@ -829,18 +924,14 @@ static int batch_objects(struct batch_options *opt) cb.seen = &seen; - for_each_loose_object(batch_unordered_loose, &cb, 0); - for_each_packed_object(the_repository, batch_unordered_packed, - &cb, FOR_EACH_OBJECT_PACK_ORDER); + batch_each_object(opt, batch_unordered_object, + FOR_EACH_OBJECT_PACK_ORDER, &cb); oidset_clear(&seen); } else { struct oid_array sa = OID_ARRAY_INIT; - for_each_loose_object(collect_loose_object, &sa, 0); - for_each_packed_object(the_repository, collect_packed_object, - &sa, 0); - + batch_each_object(opt, collect_object, 0, &sa); oid_array_for_each_unique(&sa, batch_object_cb, &cb); oid_array_clear(&sa); @@ -936,12 +1027,15 @@ int cmd_cat_file(int argc, int opt_cw = 0; int opt_epts = 0; const char *exp_type = NULL, *obj_name = NULL; - struct batch_options batch = {0}; + struct batch_options batch = { + .objects_filter = LIST_OBJECTS_FILTER_INIT, + }; int unknown_type = 0; int input_nul_terminated = 0; int nul_terminated = 0; + int ret; - const char * const usage[] = { + const char * const builtin_catfile_usage[] = { N_("git cat-file <type> <object>"), N_("git cat-file (-e | -p) <object>"), N_("git cat-file (-t | -s) [--allow-unknown-type] <object>"), @@ -1000,6 +1094,7 @@ int cmd_cat_file(int argc, N_("run filters on object's content"), 'w'), OPT_STRING(0, "path", &force_path, N_("blob|tree"), N_("use a <path> for (--textconv | --filters); Not with 'batch'")), + OPT_PARSE_LIST_OBJECTS_FILTER(&batch.objects_filter), OPT_END() }; @@ -1007,13 +1102,27 @@ int cmd_cat_file(int argc, batch.buffer_output = -1; - argc = parse_options(argc, argv, prefix, options, usage, 0); + argc = parse_options(argc, argv, prefix, options, builtin_catfile_usage, 0); opt_cw = (opt == 'c' || opt == 'w'); opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's'); if (use_mailmap) read_mailmap(&mailmap); + switch (batch.objects_filter.choice) { + case LOFC_DISABLED: + break; + case LOFC_BLOB_NONE: + case LOFC_BLOB_LIMIT: + case LOFC_OBJECT_TYPE: + if (!batch.enabled) + usage(_("objects filter only supported in batch mode")); + break; + default: + usagef(_("objects filter not supported: '%s'"), + list_object_filter_config_name(batch.objects_filter.choice)); + } + /* --batch-all-objects? */ if (opt == 'b') batch.all_objects = 1; @@ -1021,7 +1130,7 @@ int cmd_cat_file(int argc, /* Option compatibility */ if (force_path && !opt_cw) usage_msg_optf(_("'%s=<%s>' needs '%s' or '%s'"), - usage, options, + builtin_catfile_usage, options, "--path", _("path|tree-ish"), "--filters", "--textconv"); @@ -1029,20 +1138,20 @@ int cmd_cat_file(int argc, if (batch.enabled) ; else if (batch.follow_symlinks) - usage_msg_optf(_("'%s' requires a batch mode"), usage, options, - "--follow-symlinks"); + usage_msg_optf(_("'%s' requires a batch mode"), builtin_catfile_usage, + options, "--follow-symlinks"); else if (batch.buffer_output >= 0) - usage_msg_optf(_("'%s' requires a batch mode"), usage, options, - "--buffer"); + usage_msg_optf(_("'%s' requires a batch mode"), builtin_catfile_usage, + options, "--buffer"); else if (batch.all_objects) - usage_msg_optf(_("'%s' requires a batch mode"), usage, options, - "--batch-all-objects"); + usage_msg_optf(_("'%s' requires a batch mode"), builtin_catfile_usage, + options, "--batch-all-objects"); else if (input_nul_terminated) - usage_msg_optf(_("'%s' requires a batch mode"), usage, options, - "-z"); + usage_msg_optf(_("'%s' requires a batch mode"), builtin_catfile_usage, + options, "-z"); else if (nul_terminated) - usage_msg_optf(_("'%s' requires a batch mode"), usage, options, - "-Z"); + usage_msg_optf(_("'%s' requires a batch mode"), builtin_catfile_usage, + options, "-Z"); batch.input_delim = batch.output_delim = '\n'; if (input_nul_terminated) @@ -1063,33 +1172,37 @@ int cmd_cat_file(int argc, batch.transform_mode = opt; else if (opt && opt != 'b') usage_msg_optf(_("'-%c' is incompatible with batch mode"), - usage, options, opt); + builtin_catfile_usage, options, opt); else if (argc) - usage_msg_opt(_("batch modes take no arguments"), usage, - options); + usage_msg_opt(_("batch modes take no arguments"), + builtin_catfile_usage, options); - return batch_objects(&batch); + ret = batch_objects(&batch); + goto out; } if (opt) { if (!argc && opt == 'c') usage_msg_optf(_("<rev> required with '%s'"), - usage, options, "--textconv"); + builtin_catfile_usage, options, + "--textconv"); else if (!argc && opt == 'w') usage_msg_optf(_("<rev> required with '%s'"), - usage, options, "--filters"); + builtin_catfile_usage, options, + "--filters"); else if (!argc && opt_epts) usage_msg_optf(_("<object> required with '-%c'"), - usage, options, opt); + builtin_catfile_usage, options, opt); else if (argc == 1) obj_name = argv[0]; else - usage_msg_opt(_("too many arguments"), usage, options); + usage_msg_opt(_("too many arguments"), builtin_catfile_usage, + options); } else if (!argc) { - usage_with_options(usage, options); + usage_with_options(builtin_catfile_usage, options); } else if (argc != 2) { usage_msg_optf(_("only two arguments allowed in <type> <object> mode, not %d"), - usage, options, argc); + builtin_catfile_usage, options, argc); } else if (argc) { exp_type = argv[0]; obj_name = argv[1]; @@ -1097,5 +1210,10 @@ int cmd_cat_file(int argc, if (unknown_type && opt != 't' && opt != 's') die("git cat-file --allow-unknown-type: use with -s or -t"); - return cat_one_file(opt, exp_type, obj_name, unknown_type); + + ret = cat_one_file(opt, exp_type, obj_name, unknown_type); + +out: + list_objects_filter_release(&batch.objects_filter); + return ret; } diff --git a/builtin/checkout.c b/builtin/checkout.c index 8136962e2b..d185982f3a 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -17,7 +17,7 @@ #include "merge-ll.h" #include "lockfile.h" #include "mem-pool.h" -#include "merge-recursive.h" +#include "merge-ort-wrappers.h" #include "object-file.h" #include "object-name.h" #include "object-store.h" @@ -908,10 +908,10 @@ static int merge_working_tree(const struct checkout_opts *opts, o.branch1 = new_branch_info->name; o.branch2 = "local"; o.conflict_style = opts->conflict_style; - ret = merge_trees(&o, - new_tree, - work, - old_tree); + ret = merge_ort_nonrecursive(&o, + new_tree, + work, + old_tree); if (ret < 0) exit(128); ret = reset_tree(new_tree, diff --git a/builtin/clone.c b/builtin/clone.c index f64be7e1e1..6b1d11a3ed 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -452,7 +452,9 @@ static struct ref *wanted_peer_refs(struct clone_opts *opts, if (head) tail_link_ref(head, &tail); if (option_single_branch) - refs = to_free = guess_remote_head(head, refs, 0); + refs = to_free = + guess_remote_head(head, refs, + REMOTE_GUESS_HEAD_QUIET); } else if (option_single_branch) { local_refs = NULL; tail = &local_refs; @@ -1525,7 +1527,8 @@ int cmd_clone(int argc, } remote_head = find_ref_by_name(refs, "HEAD"); - remote_head_points_at = guess_remote_head(remote_head, mapped_refs, 0); + remote_head_points_at = guess_remote_head(remote_head, mapped_refs, + REMOTE_GUESS_HEAD_QUIET); if (option_branch) { our_head_points_at = find_remote_branch(mapped_refs, option_branch); diff --git a/builtin/fetch.c b/builtin/fetch.c index b52a32a5e0..95589b4994 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -586,7 +586,7 @@ static struct ref *get_ref_map(struct remote *remote, struct refspec_item tag_refspec; /* also fetch all tags */ - refspec_item_init(&tag_refspec, TAG_REFSPEC, 0); + refspec_item_init_push(&tag_refspec, TAG_REFSPEC); get_fetch_map(remote_refs, &tag_refspec, &tail, 0); refspec_item_clear(&tag_refspec); } else if (tags == TAGS_DEFAULT && *autotags) { @@ -687,7 +687,7 @@ static int s_update_ref(const char *action, switch (ref_transaction_commit(our_transaction, &err)) { case 0: break; - case TRANSACTION_NAME_CONFLICT: + case REF_TRANSACTION_ERROR_NAME_CONFLICT: ret = STORE_REF_ERROR_DF_CONFLICT; goto out; default: @@ -1638,14 +1638,11 @@ static int set_head(const struct ref *remote_refs, struct remote *remote) get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0); matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"), - fetch_map, 1); + fetch_map, REMOTE_GUESS_HEAD_ALL); for (ref = matches; ref; ref = ref->next) { string_list_append(&heads, strip_refshead(ref->name)); } - if (follow_remote_head == FOLLOW_REMOTE_NEVER) - goto cleanup; - if (!heads.nr) result = 1; else if (heads.nr > 1) @@ -1691,21 +1688,6 @@ cleanup: return result; } -static int uses_remote_tracking(struct transport *transport, struct refspec *rs) -{ - if (!remote_is_configured(transport->remote, 0)) - return 0; - - if (!rs->nr) - rs = &transport->remote->fetch; - - for (int i = 0; i < rs->nr; i++) - if (rs->items[i].dst) - return 1; - - return 0; -} - static int do_fetch(struct transport *transport, struct refspec *rs, const struct fetch_config *config) @@ -1720,6 +1702,7 @@ static int do_fetch(struct transport *transport, TRANSPORT_LS_REFS_OPTIONS_INIT; struct fetch_head fetch_head = { 0 }; struct strbuf err = STRBUF_INIT; + int do_set_head = 0; if (tags == TAGS_DEFAULT) { if (transport->remote->fetch_tags == 2) @@ -1740,9 +1723,12 @@ static int do_fetch(struct transport *transport, } else { struct branch *branch = branch_get(NULL); - if (transport->remote->fetch.nr) + if (transport->remote->fetch.nr) { refspec_ref_prefixes(&transport->remote->fetch, &transport_ls_refs_options.ref_prefixes); + if (transport->remote->follow_remote_head != FOLLOW_REMOTE_NEVER) + do_set_head = 1; + } if (branch_has_merge_config(branch) && !strcmp(branch->remote_name, transport->remote->name)) { int i; @@ -1765,8 +1751,7 @@ static int do_fetch(struct transport *transport, strvec_push(&transport_ls_refs_options.ref_prefixes, "refs/tags/"); - if (transport_ls_refs_options.ref_prefixes.nr && - uses_remote_tracking(transport, rs)) + if (do_set_head) strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD"); @@ -1859,8 +1844,15 @@ static int do_fetch(struct transport *transport, goto cleanup; retcode = ref_transaction_commit(transaction, &err); - if (retcode) + if (retcode) { + /* + * Explicitly handle transaction cleanup to avoid + * aborting an already closed transaction. + */ + ref_transaction_free(transaction); + transaction = NULL; goto cleanup; + } } commit_fetch_head(&fetch_head); @@ -1918,12 +1910,13 @@ static int do_fetch(struct transport *transport, "you need to specify exactly one branch with the --set-upstream option")); } } - if (set_head(remote_refs, transport->remote)) - ; + if (do_set_head) { /* - * Way too many cases where this can go wrong - * so let's just fail silently for now. + * Way too many cases where this can go wrong so let's just + * ignore errors and fail silently for now. */ + set_head(remote_refs, transport->remote); + } cleanup: if (retcode) { diff --git a/builtin/gc.c b/builtin/gc.c index 4247e0e7f7..b5ce1d3276 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -32,6 +32,7 @@ #include "pack.h" #include "pack-objects.h" #include "path.h" +#include "reflog.h" #include "blob.h" #include "tree.h" #include "promisor-remote.h" @@ -52,7 +53,6 @@ static const char * const builtin_gc_usage[] = { static timestamp_t gc_log_expire_time; -static struct strvec reflog = STRVEC_INIT; static struct strvec repack = STRVEC_INIT; static struct strvec prune = STRVEC_INIT; static struct strvec prune_worktrees = STRVEC_INIT; @@ -287,6 +287,58 @@ static int maintenance_task_pack_refs(struct maintenance_run_opts *opts, return run_command(&cmd); } +struct count_reflog_entries_data { + struct expire_reflog_policy_cb policy; + size_t count; + size_t limit; +}; + +static int count_reflog_entries(struct object_id *old_oid, struct object_id *new_oid, + const char *committer, timestamp_t timestamp, + int tz, const char *msg, void *cb_data) +{ + struct count_reflog_entries_data *data = cb_data; + if (should_expire_reflog_ent(old_oid, new_oid, committer, timestamp, tz, msg, &data->policy)) + data->count++; + return data->count >= data->limit; +} + +static int reflog_expire_condition(struct gc_config *cfg UNUSED) +{ + timestamp_t now = time(NULL); + struct count_reflog_entries_data data = { + .policy = { + .opts = REFLOG_EXPIRE_OPTIONS_INIT(now), + }, + }; + int limit = 100; + + git_config_get_int("maintenance.reflog-expire.auto", &limit); + if (!limit) + return 0; + if (limit < 0) + return 1; + data.limit = limit; + + repo_config(the_repository, reflog_expire_config, &data.policy.opts); + + reflog_expire_options_set_refname(&data.policy.opts, "HEAD"); + refs_for_each_reflog_ent(get_main_ref_store(the_repository), "HEAD", + count_reflog_entries, &data); + + reflog_expiry_cleanup(&data.policy); + return data.count >= data.limit; +} + +static int maintenance_task_reflog_expire(struct maintenance_run_opts *opts UNUSED, + struct gc_config *cfg UNUSED) +{ + struct child_process cmd = CHILD_PROCESS_INIT; + cmd.git_cmd = 1; + strvec_pushl(&cmd.args, "reflog", "expire", "--all", NULL); + return run_command(&cmd); +} + static int too_many_loose_objects(struct gc_config *cfg) { /* @@ -666,15 +718,8 @@ static void gc_before_repack(struct maintenance_run_opts *opts, if (cfg->pack_refs && maintenance_task_pack_refs(opts, cfg)) die(FAILED_RUN, "pack-refs"); - - if (cfg->prune_reflogs) { - struct child_process cmd = CHILD_PROCESS_INIT; - - cmd.git_cmd = 1; - strvec_pushv(&cmd.args, reflog.v); - if (run_command(&cmd)) - die(FAILED_RUN, reflog.v[0]); - } + if (cfg->prune_reflogs && maintenance_task_reflog_expire(opts, cfg)) + die(FAILED_RUN, "reflog"); } int cmd_gc(int argc, @@ -722,7 +767,6 @@ struct repository *repo UNUSED) show_usage_with_options_if_asked(argc, argv, builtin_gc_usage, builtin_gc_options); - strvec_pushl(&reflog, "reflog", "expire", "--all", NULL); strvec_pushl(&repack, "repack", "-d", "-l", NULL); strvec_pushl(&prune, "prune", "--expire", NULL); strvec_pushl(&prune_worktrees, "worktree", "prune", "--expire", NULL); @@ -1028,6 +1072,8 @@ static int run_write_commit_graph(struct maintenance_run_opts *opts) if (opts->quiet) strvec_push(&child.args, "--no-progress"); + else + strvec_push(&child.args, "--progress"); return !!run_command(&child); } @@ -1160,6 +1206,7 @@ static int write_loose_object_to_stdin(const struct object_id *oid, fprintf(d->in, "%s\n", oid_to_hex(oid)); + /* If batch_size is INT_MAX, then this will return 0 always. */ return ++(d->count) > d->batch_size; } @@ -1184,6 +1231,8 @@ static int pack_loose(struct maintenance_run_opts *opts) strvec_push(&pack_proc.args, "pack-objects"); if (opts->quiet) strvec_push(&pack_proc.args, "--quiet"); + else + strvec_push(&pack_proc.args, "--no-quiet"); strvec_pushf(&pack_proc.args, "%s/pack/loose", r->objects->odb->path); pack_proc.in = -1; @@ -1203,6 +1252,15 @@ static int pack_loose(struct maintenance_run_opts *opts) data.count = 0; data.batch_size = 50000; + repo_config_get_int(r, "maintenance.loose-objects.batchSize", + &data.batch_size); + + /* If configured as 0, then remove limit. */ + if (!data.batch_size) + data.batch_size = INT_MAX; + else if (data.batch_size > 0) + data.batch_size--; /* Decrease for equality on limit. */ + for_each_loose_file_in_objdir(r->objects->odb->path, write_loose_object_to_stdin, NULL, @@ -1262,6 +1320,8 @@ static int multi_pack_index_write(struct maintenance_run_opts *opts) if (opts->quiet) strvec_push(&child.args, "--no-progress"); + else + strvec_push(&child.args, "--progress"); if (run_command(&child)) return error(_("failed to write multi-pack-index")); @@ -1278,6 +1338,8 @@ static int multi_pack_index_expire(struct maintenance_run_opts *opts) if (opts->quiet) strvec_push(&child.args, "--no-progress"); + else + strvec_push(&child.args, "--progress"); if (run_command(&child)) return error(_("'git multi-pack-index expire' failed")); @@ -1334,6 +1396,8 @@ static int multi_pack_index_repack(struct maintenance_run_opts *opts) if (opts->quiet) strvec_push(&child.args, "--no-progress"); + else + strvec_push(&child.args, "--progress"); strvec_pushf(&child.args, "--batch-size=%"PRIuMAX, (uintmax_t)get_auto_pack_size()); @@ -1391,6 +1455,7 @@ enum maintenance_task_label { TASK_GC, TASK_COMMIT_GRAPH, TASK_PACK_REFS, + TASK_REFLOG_EXPIRE, /* Leave as final value */ TASK__COUNT @@ -1427,6 +1492,11 @@ static struct maintenance_task tasks[] = { maintenance_task_pack_refs, pack_refs_condition, }, + [TASK_REFLOG_EXPIRE] = { + "reflog-expire", + maintenance_task_reflog_expire, + reflog_expire_condition, + }, }; static int compare_tasks_by_selection(const void *a_, const void *b_) diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c index abfc060e28..03b5100cfa 100644 --- a/builtin/merge-recursive.c +++ b/builtin/merge-recursive.c @@ -3,7 +3,7 @@ #include "advice.h" #include "gettext.h" #include "hash.h" -#include "merge-recursive.h" +#include "merge-ort-wrappers.h" #include "object-name.h" static const char builtin_merge_recursive_usage[] = @@ -89,7 +89,7 @@ int cmd_merge_recursive(int argc, if (o.verbosity >= 3) printf(_("Merging %s with %s\n"), o.branch1, o.branch2); - failed = merge_recursive_generic(&o, &h1, &h2, bases_count, bases, &result); + failed = merge_ort_generic(&o, &h1, &h2, bases_count, bases, &result); free(better1); free(better2); diff --git a/builtin/merge.c b/builtin/merge.c index ba9faf126a..9efd585842 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -39,7 +39,6 @@ #include "rerere.h" #include "help.h" #include "merge.h" -#include "merge-recursive.h" #include "merge-ort-wrappers.h" #include "resolve-undo.h" #include "remote.h" @@ -171,7 +170,7 @@ static struct strategy *get_strategy(const char *name) struct strategy *ret; static struct cmdnames main_cmds = {0}, other_cmds = {0}; static int loaded; - char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM"); + char *default_strategy = NULL; if (!name) return NULL; @@ -750,12 +749,8 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR); - if (!strcmp(strategy, "ort")) - clean = merge_ort_recursive(&o, head, remoteheads->item, - reversed, &result); - else - clean = merge_recursive(&o, head, remoteheads->item, - reversed, &result); + clean = merge_ort_recursive(&o, head, remoteheads->item, + reversed, &result); free_commit_list(reversed); strbuf_release(&o.obuf); @@ -1316,12 +1311,6 @@ int cmd_merge(int argc, if (branch) skip_prefix(branch, "refs/heads/", &branch); - if (!pull_twohead) { - char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM"); - if (default_strategy && !strcmp(default_strategy, "ort")) - pull_twohead = xstrdup("ort"); - } - init_diff_ui_defaults(); git_config(git_merge_config, NULL); @@ -1522,12 +1511,6 @@ int cmd_merge(int argc, fast_forward = FF_NO; } - if (!use_strategies && !pull_twohead && - remoteheads && !remoteheads->next) { - char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM"); - if (default_strategy) - append_strategy(get_strategy(default_strategy)); - } if (!use_strategies) { if (!remoteheads) ; /* already up-to-date */ diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 488c80f2cf..8174c60c70 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -1400,7 +1400,8 @@ static void write_pack_file(void) if (write_bitmap_index) { bitmap_writer_init(&bitmap_writer, - the_repository, &to_pack); + the_repository, &to_pack, + NULL); bitmap_writer_set_checksum(&bitmap_writer, hash); bitmap_writer_build_type_index(&bitmap_writer, written_list); @@ -1819,7 +1820,8 @@ static int add_object_entry(const struct object_id *oid, enum object_type type, static int add_object_entry_from_bitmap(const struct object_id *oid, enum object_type type, int flags UNUSED, uint32_t name_hash, - struct packed_git *pack, off_t offset) + struct packed_git *pack, off_t offset, + void *payload UNUSED) { display_progress(progress_state, ++nr_seen); diff --git a/builtin/pull.c b/builtin/pull.c index 9c4a00620a..a1ebc6ad33 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -738,7 +738,8 @@ static const char *get_tracking_branch(const char *remote, const char *refspec) const char *spec_src; const char *merge_branch; - refspec_item_init_or_die(&spec, refspec, REFSPEC_FETCH); + if (!refspec_item_init_fetch(&spec, refspec)) + die(_("invalid refspec '%s'"), refspec); spec_src = spec.src; if (!*spec_src || !strcmp(spec_src, "HEAD")) spec_src = "HEAD"; diff --git a/builtin/rebase.c b/builtin/rebase.c index cd9371536f..36e336009c 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -1576,11 +1576,6 @@ int cmd_rebase(int argc, options.default_backend); } - if (options.type == REBASE_MERGE && - !options.strategy && - getenv("GIT_TEST_MERGE_ALGORITHM")) - options.strategy = xstrdup(getenv("GIT_TEST_MERGE_ALGORITHM")); - switch (options.type) { case REBASE_MERGE: options.state_dir = merge_dir(); @@ -1844,7 +1839,7 @@ int cmd_rebase(int argc, strbuf_addf(&msg, "%s (start): checkout %s", options.reflog_action, options.onto_name); ropts.oid = &options.onto->object.oid; - ropts.orig_head = &options.orig_head->object.oid, + ropts.orig_head = &options.orig_head->object.oid; ropts.flags = RESET_HEAD_DETACH | RESET_ORIG_HEAD | RESET_HEAD_RUN_POST_CHECKOUT_HOOK; ropts.head_msg = msg.buf; diff --git a/builtin/reflog.c b/builtin/reflog.c index 95f264989b..3acaf3e32c 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -29,6 +29,9 @@ #define BUILTIN_REFLOG_EXISTS_USAGE \ N_("git reflog exists <ref>") +#define BUILTIN_REFLOG_DROP_USAGE \ + N_("git reflog drop [--all [--single-worktree] | <refs>...]") + static const char *const reflog_show_usage[] = { BUILTIN_REFLOG_SHOW_USAGE, NULL, @@ -54,18 +57,21 @@ static const char *const reflog_exists_usage[] = { NULL, }; +static const char *const reflog_drop_usage[] = { + BUILTIN_REFLOG_DROP_USAGE, + NULL, +}; + static const char *const reflog_usage[] = { BUILTIN_REFLOG_SHOW_USAGE, BUILTIN_REFLOG_LIST_USAGE, BUILTIN_REFLOG_EXPIRE_USAGE, BUILTIN_REFLOG_DELETE_USAGE, + BUILTIN_REFLOG_DROP_USAGE, BUILTIN_REFLOG_EXISTS_USAGE, NULL }; -static timestamp_t default_reflog_expire; -static timestamp_t default_reflog_expire_unreachable; - struct worktree_reflogs { struct worktree *worktree; struct string_list reflogs; @@ -91,131 +97,19 @@ static int collect_reflog(const char *ref, void *cb_data) return 0; } -static struct reflog_expire_cfg { - struct reflog_expire_cfg *next; - timestamp_t expire_total; - timestamp_t expire_unreachable; - char pattern[FLEX_ARRAY]; -} *reflog_expire_cfg, **reflog_expire_cfg_tail; - -static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len) -{ - struct reflog_expire_cfg *ent; - - if (!reflog_expire_cfg_tail) - reflog_expire_cfg_tail = &reflog_expire_cfg; - - for (ent = reflog_expire_cfg; ent; ent = ent->next) - if (!xstrncmpz(ent->pattern, pattern, len)) - return ent; - - FLEX_ALLOC_MEM(ent, pattern, pattern, len); - *reflog_expire_cfg_tail = ent; - reflog_expire_cfg_tail = &(ent->next); - return ent; -} - -/* expiry timer slot */ -#define EXPIRE_TOTAL 01 -#define EXPIRE_UNREACH 02 - -static int reflog_expire_config(const char *var, const char *value, - const struct config_context *ctx, void *cb) -{ - const char *pattern, *key; - size_t pattern_len; - timestamp_t expire; - int slot; - struct reflog_expire_cfg *ent; - - if (parse_config_key(var, "gc", &pattern, &pattern_len, &key) < 0) - return git_default_config(var, value, ctx, cb); - - if (!strcmp(key, "reflogexpire")) { - slot = EXPIRE_TOTAL; - if (git_config_expiry_date(&expire, var, value)) - return -1; - } else if (!strcmp(key, "reflogexpireunreachable")) { - slot = EXPIRE_UNREACH; - if (git_config_expiry_date(&expire, var, value)) - return -1; - } else - return git_default_config(var, value, ctx, cb); - - if (!pattern) { - switch (slot) { - case EXPIRE_TOTAL: - default_reflog_expire = expire; - break; - case EXPIRE_UNREACH: - default_reflog_expire_unreachable = expire; - break; - } - return 0; - } - - ent = find_cfg_ent(pattern, pattern_len); - if (!ent) - return -1; - switch (slot) { - case EXPIRE_TOTAL: - ent->expire_total = expire; - break; - case EXPIRE_UNREACH: - ent->expire_unreachable = expire; - break; - } - return 0; -} - -static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, const char *ref) -{ - struct reflog_expire_cfg *ent; - - if (cb->explicit_expiry == (EXPIRE_TOTAL|EXPIRE_UNREACH)) - return; /* both given explicitly -- nothing to tweak */ - - for (ent = reflog_expire_cfg; ent; ent = ent->next) { - if (!wildmatch(ent->pattern, ref, 0)) { - if (!(cb->explicit_expiry & EXPIRE_TOTAL)) - cb->expire_total = ent->expire_total; - if (!(cb->explicit_expiry & EXPIRE_UNREACH)) - cb->expire_unreachable = ent->expire_unreachable; - return; - } - } - - /* - * If unconfigured, make stash never expire - */ - if (!strcmp(ref, "refs/stash")) { - if (!(cb->explicit_expiry & EXPIRE_TOTAL)) - cb->expire_total = 0; - if (!(cb->explicit_expiry & EXPIRE_UNREACH)) - cb->expire_unreachable = 0; - return; - } - - /* Nothing matched -- use the default value */ - if (!(cb->explicit_expiry & EXPIRE_TOTAL)) - cb->expire_total = default_reflog_expire; - if (!(cb->explicit_expiry & EXPIRE_UNREACH)) - cb->expire_unreachable = default_reflog_expire_unreachable; -} - static int expire_unreachable_callback(const struct option *opt, const char *arg, int unset) { - struct cmd_reflog_expire_cb *cmd = opt->value; + struct reflog_expire_options *opts = opt->value; BUG_ON_OPT_NEG(unset); - if (parse_expiry_date(arg, &cmd->expire_unreachable)) + if (parse_expiry_date(arg, &opts->expire_unreachable)) die(_("invalid timestamp '%s' given to '--%s'"), arg, opt->long_name); - cmd->explicit_expiry |= EXPIRE_UNREACH; + opts->explicit_expiry |= REFLOG_EXPIRE_UNREACH; return 0; } @@ -223,15 +117,15 @@ static int expire_total_callback(const struct option *opt, const char *arg, int unset) { - struct cmd_reflog_expire_cb *cmd = opt->value; + struct reflog_expire_options *opts = opt->value; BUG_ON_OPT_NEG(unset); - if (parse_expiry_date(arg, &cmd->expire_total)) + if (parse_expiry_date(arg, &opts->expire_total)) die(_("invalid timestamp '%s' given to '--%s'"), arg, opt->long_name); - cmd->explicit_expiry |= EXPIRE_TOTAL; + opts->explicit_expiry |= REFLOG_EXPIRE_TOTAL; return 0; } @@ -276,8 +170,8 @@ static int cmd_reflog_list(int argc, const char **argv, const char *prefix, static int cmd_reflog_expire(int argc, const char **argv, const char *prefix, struct repository *repo UNUSED) { - struct cmd_reflog_expire_cb cmd = { 0 }; timestamp_t now = time(NULL); + struct reflog_expire_options opts = REFLOG_EXPIRE_OPTIONS_INIT(now); int i, status, do_all, single_worktree = 0; unsigned int flags = 0; int verbose = 0; @@ -292,15 +186,15 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix, N_("update the reference to the value of the top reflog entry"), EXPIRE_REFLOGS_UPDATE_REF), OPT_BOOL(0, "verbose", &verbose, N_("print extra information on screen")), - OPT_CALLBACK_F(0, "expire", &cmd, N_("timestamp"), + OPT_CALLBACK_F(0, "expire", &opts, N_("timestamp"), N_("prune entries older than the specified time"), PARSE_OPT_NONEG, expire_total_callback), - OPT_CALLBACK_F(0, "expire-unreachable", &cmd, N_("timestamp"), + OPT_CALLBACK_F(0, "expire-unreachable", &opts, N_("timestamp"), N_("prune entries older than <time> that are not reachable from the current tip of the branch"), PARSE_OPT_NONEG, expire_unreachable_callback), - OPT_BOOL(0, "stale-fix", &cmd.stalefix, + OPT_BOOL(0, "stale-fix", &opts.stalefix, N_("prune any reflog entries that point to broken commits")), OPT_BOOL(0, "all", &do_all, N_("process the reflogs of all references")), OPT_BOOL(0, "single-worktree", &single_worktree, @@ -308,17 +202,11 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix, OPT_END() }; - default_reflog_expire_unreachable = now - 30 * 24 * 3600; - default_reflog_expire = now - 90 * 24 * 3600; - git_config(reflog_expire_config, NULL); + git_config(reflog_expire_config, &opts); save_commit_buffer = 0; do_all = status = 0; - cmd.explicit_expiry = 0; - cmd.expire_total = default_reflog_expire; - cmd.expire_unreachable = default_reflog_expire_unreachable; - argc = parse_options(argc, argv, prefix, options, reflog_expire_usage, 0); if (verbose) @@ -329,7 +217,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix, * even in older repository. We cannot trust what's reachable * from reflog if the repository was pruned with older git. */ - if (cmd.stalefix) { + if (opts.stalefix) { struct rev_info revs; repo_init_revisions(the_repository, &revs, prefix); @@ -363,11 +251,11 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix, for_each_string_list_item(item, &collected.reflogs) { struct expire_reflog_policy_cb cb = { - .cmd = cmd, + .opts = opts, .dry_run = !!(flags & EXPIRE_REFLOGS_DRY_RUN), }; - set_reflog_expiry_param(&cb.cmd, item->string); + reflog_expire_options_set_refname(&cb.opts, item->string); status |= refs_reflog_expire(get_main_ref_store(the_repository), item->string, flags, reflog_expiry_prepare, @@ -380,13 +268,13 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix, for (i = 0; i < argc; i++) { char *ref; - struct expire_reflog_policy_cb cb = { .cmd = cmd }; + struct expire_reflog_policy_cb cb = { .opts = opts }; if (!repo_dwim_log(the_repository, argv[i], strlen(argv[i]), NULL, &ref)) { - status |= error(_("%s points nowhere!"), argv[i]); + status |= error(_("reflog could not be found: '%s'"), argv[i]); continue; } - set_reflog_expiry_param(&cb.cmd, ref); + reflog_expire_options_set_refname(&cb.opts, ref); status |= refs_reflog_expire(get_main_ref_store(the_repository), ref, flags, reflog_expiry_prepare, @@ -449,10 +337,64 @@ static int cmd_reflog_exists(int argc, const char **argv, const char *prefix, refname); } +static int cmd_reflog_drop(int argc, const char **argv, const char *prefix, + struct repository *repo) +{ + int ret = 0, do_all = 0, single_worktree = 0; + const struct option options[] = { + OPT_BOOL(0, "all", &do_all, N_("drop the reflogs of all references")), + OPT_BOOL(0, "single-worktree", &single_worktree, + N_("drop reflogs from the current worktree only")), + OPT_END() + }; + + argc = parse_options(argc, argv, prefix, options, reflog_drop_usage, 0); + + if (argc && do_all) + usage(_("references specified along with --all")); + + if (do_all) { + struct worktree_reflogs collected = { + .reflogs = STRING_LIST_INIT_DUP, + }; + struct string_list_item *item; + struct worktree **worktrees, **p; + + worktrees = get_worktrees(); + for (p = worktrees; *p; p++) { + if (single_worktree && !(*p)->is_current) + continue; + collected.worktree = *p; + refs_for_each_reflog(get_worktree_ref_store(*p), + collect_reflog, &collected); + } + free_worktrees(worktrees); + + for_each_string_list_item(item, &collected.reflogs) + ret |= refs_delete_reflog(get_main_ref_store(repo), + item->string); + string_list_clear(&collected.reflogs, 0); + + return ret; + } + + for (int i = 0; i < argc; i++) { + char *ref; + if (!repo_dwim_log(repo, argv[i], strlen(argv[i]), NULL, &ref)) { + ret |= error(_("reflog could not be found: '%s'"), argv[i]); + continue; + } + + ret |= refs_delete_reflog(get_main_ref_store(repo), ref); + free(ref); + } + + return ret; +} + /* * main "reflog" */ - int cmd_reflog(int argc, const char **argv, const char *prefix, @@ -465,6 +407,7 @@ int cmd_reflog(int argc, OPT_SUBCOMMAND("expire", &fn, cmd_reflog_expire), OPT_SUBCOMMAND("delete", &fn, cmd_reflog_delete), OPT_SUBCOMMAND("exists", &fn, cmd_reflog_exists), + OPT_SUBCOMMAND("drop", &fn, cmd_reflog_drop), OPT_END() }; diff --git a/builtin/remote.c b/builtin/remote.c index 59481b3a82..b4baa34e66 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -511,7 +511,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0); matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"), - fetch_map, 1); + fetch_map, REMOTE_GUESS_HEAD_ALL); for (ref = matches; ref; ref = ref->next) string_list_append(&states->heads, abbrev_branch(ref->name)); diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 0170d79b62..c4cd4ed5c8 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -16,6 +16,7 @@ #include "object-file.h" #include "object-store.h" #include "pack-bitmap.h" +#include "parse-options.h" #include "log-tree.h" #include "graph.h" #include "bisect.h" @@ -64,6 +65,7 @@ static const char rev_list_usage[] = " --abbrev-commit\n" " --left-right\n" " --count\n" +" -z\n" " special purpose:\n" " --bisect\n" " --bisect-vars\n" @@ -96,6 +98,9 @@ static int arg_show_object_names = 1; #define DEFAULT_OIDSET_SIZE (16*1024) +static char line_term = '\n'; +static char info_term = ' '; + static int show_disk_usage; static off_t total_disk_usage; static int human_readable; @@ -131,24 +136,37 @@ static void print_missing_object(struct missing_objects_map_entry *entry, { struct strbuf sb = STRBUF_INIT; + if (line_term) + printf("?%s", oid_to_hex(&entry->entry.oid)); + else + printf("%s%cmissing=yes", oid_to_hex(&entry->entry.oid), + info_term); + if (!print_missing_info) { - printf("?%s\n", oid_to_hex(&entry->entry.oid)); + putchar(line_term); return; } if (entry->path && *entry->path) { - struct strbuf path = STRBUF_INIT; + strbuf_addf(&sb, "%cpath=", info_term); - strbuf_addstr(&sb, " path="); - quote_path(entry->path, NULL, &path, QUOTE_PATH_QUOTE_SP); - strbuf_addbuf(&sb, &path); + if (line_term) { + struct strbuf path = STRBUF_INIT; - strbuf_release(&path); + quote_path(entry->path, NULL, &path, QUOTE_PATH_QUOTE_SP); + strbuf_addbuf(&sb, &path); + + strbuf_release(&path); + } else { + strbuf_addstr(&sb, entry->path); + } } if (entry->type) - strbuf_addf(&sb, " type=%s", type_name(entry->type)); + strbuf_addf(&sb, "%ctype=%s", info_term, type_name(entry->type)); + + fwrite(sb.buf, sizeof(char), sb.len, stdout); + putchar(line_term); - printf("?%s%s\n", oid_to_hex(&entry->entry.oid), sb.buf); strbuf_release(&sb); } @@ -235,13 +253,18 @@ static void show_commit(struct commit *commit, void *data) fputs(info->header_prefix, stdout); if (revs->include_header) { - if (!revs->graph) + if (!revs->graph && line_term) fputs(get_revision_mark(revs, commit), stdout); if (revs->abbrev_commit && revs->abbrev) fputs(repo_find_unique_abbrev(the_repository, &commit->object.oid, revs->abbrev), stdout); else fputs(oid_to_hex(&commit->object.oid), stdout); + + if (!line_term) { + if (commit->object.flags & BOUNDARY) + printf("%cboundary=yes", info_term); + } } if (revs->print_parents) { struct commit_list *parents = commit->parents; @@ -263,7 +286,7 @@ static void show_commit(struct commit *commit, void *data) if (revs->commit_format == CMIT_FMT_ONELINE) putchar(' '); else if (revs->include_header) - putchar('\n'); + putchar(line_term); if (revs->verbose_header) { struct strbuf buf = STRBUF_INIT; @@ -357,10 +380,19 @@ static void show_object(struct object *obj, const char *name, void *cb_data) return; } - if (arg_show_object_names) - show_object_with_name(stdout, obj, name); - else - printf("%s\n", oid_to_hex(&obj->oid)); + printf("%s", oid_to_hex(&obj->oid)); + + if (arg_show_object_names) { + if (line_term) { + putchar(info_term); + for (const char *p = name; *p && *p != '\n'; p++) + putchar(*p); + } else if (*name) { + printf("%cpath=%s", info_term, name); + } + } + + putchar(line_term); } static void show_edge(struct commit *commit) @@ -429,7 +461,8 @@ static int show_object_fast( int exclude UNUSED, uint32_t name_hash UNUSED, struct packed_git *found_pack UNUSED, - off_t found_offset UNUSED) + off_t found_offset UNUSED, + void *payload UNUSED) { fprintf(stdout, "%s\n", oid_to_hex(oid)); return 1; @@ -634,19 +667,18 @@ int cmd_rev_list(int argc, if (!strcmp(arg, "--exclude-promisor-objects")) { fetch_if_missing = 0; revs.exclude_promisor_objects = 1; - break; - } - } - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; - if (skip_prefix(arg, "--missing=", &arg)) { - if (revs.exclude_promisor_objects) - die(_("options '%s' and '%s' cannot be used together"), "--exclude-promisor-objects", "--missing"); - if (parse_missing_action_value(arg)) - break; + } else if (skip_prefix(arg, "--missing=", &arg)) { + parse_missing_action_value(arg); + } else if (!strcmp(arg, "-z")) { + line_term = '\0'; + info_term = '\0'; } } + die_for_incompatible_opt2(revs.exclude_promisor_objects, + "--exclude_promisor_objects", + arg_missing_action, "--missing"); + if (arg_missing_action) revs.do_not_die_on_missing_objects = 1; @@ -755,6 +787,20 @@ int cmd_rev_list(int argc, usage(rev_list_usage); } + + /* + * Reject options currently incompatible with -z. For some options, this + * is not an inherent limitation and support may be implemented in the + * future. + */ + if (!line_term) { + if (revs.graph || revs.verbose_header || show_disk_usage || + info.show_timestamp || info.header_prefix || bisect_list || + use_bitmap_index || revs.edge_hint || revs.left_right || + revs.cherry_mark) + die(_("-z option used with unsupported option")); + } + if (revs.commit_format != CMIT_FMT_USERFORMAT) revs.include_header = 1; if (revs.commit_format != CMIT_FMT_UNSPECIFIED) { diff --git a/builtin/revert.c b/builtin/revert.c index aca6c293cd..2654f769a8 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -252,8 +252,6 @@ static int run_sequencer(int argc, const char **argv, const char *prefix, free(opts->strategy); opts->strategy = xstrdup_or_null(strategy); } - if (!opts->strategy && getenv("GIT_TEST_MERGE_ALGORITHM")) - opts->strategy = xstrdup(getenv("GIT_TEST_MERGE_ALGORITHM")); free(options); if (cmd == 'q') { diff --git a/builtin/rm.c b/builtin/rm.c index 12ae086a55..a6565a69cf 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -5,7 +5,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "advice.h" @@ -40,14 +39,12 @@ static struct { } *entry; } list; -static int get_ours_cache_pos(const char *path, int pos) +static int get_ours_cache_pos(const char *path, unsigned int pos) { - int i = -pos - 1; - - while ((i < the_repository->index->cache_nr) && !strcmp(the_repository->index->cache[i]->name, path)) { - if (ce_stage(the_repository->index->cache[i]) == 2) - return i; - i++; + while ((pos < the_repository->index->cache_nr) && !strcmp(the_repository->index->cache[pos]->name, path)) { + if (ce_stage(the_repository->index->cache[pos]) == 2) + return pos; + pos++; } return -1; } @@ -58,7 +55,7 @@ static void print_error_files(struct string_list *files_list, int *errs) { if (files_list->nr) { - int i; + unsigned int i; struct strbuf err_msg = STRBUF_INIT; strbuf_addstr(&err_msg, main_msg); @@ -83,7 +80,7 @@ static void submodules_absorb_gitdir_if_needed(void) pos = index_name_pos(the_repository->index, name, strlen(name)); if (pos < 0) { - pos = get_ours_cache_pos(name, pos); + pos = get_ours_cache_pos(name, -pos - 1); if (pos < 0) continue; } @@ -131,7 +128,7 @@ static int check_local_mod(struct object_id *head, int index_only) * Skip unmerged entries except for populated submodules * that could lose history when removed. */ - pos = get_ours_cache_pos(name, pos); + pos = get_ours_cache_pos(name, -pos - 1); if (pos < 0) continue; @@ -314,7 +311,7 @@ int cmd_rm(int argc, if (pathspec_needs_expanded_index(the_repository->index, &pathspec)) ensure_full_index(the_repository->index); - for (i = 0; i < the_repository->index->cache_nr; i++) { + for (unsigned int i = 0; i < the_repository->index->cache_nr; i++) { const struct cache_entry *ce = the_repository->index->cache[i]; if (!include_sparse && diff --git a/builtin/update-ref.c b/builtin/update-ref.c index c3903c104f..2b1e336ba1 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -5,6 +5,7 @@ #include "config.h" #include "gettext.h" #include "hash.h" +#include "hex.h" #include "refs.h" #include "object-name.h" #include "parse-options.h" @@ -13,7 +14,7 @@ static const char * const git_update_ref_usage[] = { N_("git update-ref [<options>] -d <refname> [<old-oid>]"), N_("git update-ref [<options>] <refname> <new-oid> [<old-oid>]"), - N_("git update-ref [<options>] --stdin [-z]"), + N_("git update-ref [<options>] --stdin [-z] [--batch-updates]"), NULL }; @@ -565,6 +566,49 @@ static void parse_cmd_abort(struct ref_transaction *transaction, report_ok("abort"); } +static void print_rejected_refs(const char *refname, + const struct object_id *old_oid, + const struct object_id *new_oid, + const char *old_target, + const char *new_target, + enum ref_transaction_error err, + void *cb_data UNUSED) +{ + struct strbuf sb = STRBUF_INIT; + const char *reason = ""; + + switch (err) { + case REF_TRANSACTION_ERROR_NAME_CONFLICT: + reason = "refname conflict"; + break; + case REF_TRANSACTION_ERROR_CREATE_EXISTS: + reason = "reference already exists"; + break; + case REF_TRANSACTION_ERROR_NONEXISTENT_REF: + reason = "reference does not exist"; + break; + case REF_TRANSACTION_ERROR_INCORRECT_OLD_VALUE: + reason = "incorrect old value provided"; + break; + case REF_TRANSACTION_ERROR_INVALID_NEW_VALUE: + reason = "invalid new value provided"; + break; + case REF_TRANSACTION_ERROR_EXPECTED_SYMREF: + reason = "expected symref but found regular ref"; + break; + default: + reason = "unkown failure"; + } + + strbuf_addf(&sb, "rejected %s %s %s %s\n", refname, + new_oid ? oid_to_hex(new_oid) : new_target, + old_oid ? oid_to_hex(old_oid) : old_target, + reason); + + fwrite(sb.buf, sb.len, 1, stdout); + strbuf_release(&sb); +} + static void parse_cmd_commit(struct ref_transaction *transaction, const char *next, const char *end UNUSED) { @@ -573,6 +617,10 @@ static void parse_cmd_commit(struct ref_transaction *transaction, die("commit: extra input: %s", next); if (ref_transaction_commit(transaction, &error)) die("commit: %s", error.buf); + + ref_transaction_for_each_rejected_update(transaction, + print_rejected_refs, NULL); + report_ok("commit"); ref_transaction_free(transaction); } @@ -609,7 +657,7 @@ static const struct parse_cmd { { "commit", parse_cmd_commit, 0, UPDATE_REFS_CLOSED }, }; -static void update_refs_stdin(void) +static void update_refs_stdin(unsigned int flags) { struct strbuf input = STRBUF_INIT, err = STRBUF_INIT; enum update_refs_state state = UPDATE_REFS_OPEN; @@ -617,7 +665,7 @@ static void update_refs_stdin(void) int i, j; transaction = ref_store_transaction_begin(get_main_ref_store(the_repository), - 0, &err); + flags, &err); if (!transaction) die("%s", err.buf); @@ -685,7 +733,7 @@ static void update_refs_stdin(void) */ state = cmd->state; transaction = ref_store_transaction_begin(get_main_ref_store(the_repository), - 0, &err); + flags, &err); if (!transaction) die("%s", err.buf); @@ -701,6 +749,8 @@ static void update_refs_stdin(void) /* Commit by default if no transaction was requested. */ if (ref_transaction_commit(transaction, &err)) die("%s", err.buf); + ref_transaction_for_each_rejected_update(transaction, + print_rejected_refs, NULL); ref_transaction_free(transaction); break; case UPDATE_REFS_STARTED: @@ -727,6 +777,8 @@ int cmd_update_ref(int argc, struct object_id oid, oldoid; int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0; int create_reflog = 0; + unsigned int flags = 0; + struct option options[] = { OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")), OPT_BOOL('d', NULL, &delete, N_("delete the reference")), @@ -735,6 +787,8 @@ int cmd_update_ref(int argc, OPT_BOOL('z', NULL, &end_null, N_("stdin has NUL-terminated arguments")), OPT_BOOL( 0 , "stdin", &read_stdin, N_("read updates from stdin")), OPT_BOOL( 0 , "create-reflog", &create_reflog, N_("create a reflog")), + OPT_BIT('0', "batch-updates", &flags, N_("batch reference updates"), + REF_TRANSACTION_ALLOW_FAILURE), OPT_END(), }; @@ -756,8 +810,10 @@ int cmd_update_ref(int argc, usage_with_options(git_update_ref_usage, options); if (end_null) line_termination = '\0'; - update_refs_stdin(); + update_refs_stdin(flags); return 0; + } else if (flags & REF_TRANSACTION_ALLOW_FAILURE) { + die("--batch-updates can only be used with --stdin"); } if (end_null) diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c index d7467290a8..ba702d30ef 100644 --- a/builtin/update-server-info.c +++ b/builtin/update-server-info.c @@ -20,8 +20,8 @@ int cmd_update_server_info(int argc, OPT_END() }; - if (repo) - repo_config(repo, git_default_config, NULL); + repo_config(repo, git_default_config, NULL); + argc = parse_options(argc, argv, prefix, options, update_server_info_usage, 0); if (argc > 0) |
