diff options
Diffstat (limited to 'builtin')
35 files changed, 630 insertions, 303 deletions
diff --git a/builtin/add.c b/builtin/add.c index b1dddb4ac6..e8fb80b36e 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -26,10 +26,25 @@ static int patch_interactive, add_interactive, edit_interactive; static int take_worktree_changes; struct update_callback_data { - int flags, force_mode; + int flags; int add_errors; }; +static void chmod_pathspec(struct pathspec *pathspec, int force_mode) +{ + int i; + + for (i = 0; i < active_nr; i++) { + struct cache_entry *ce = active_cache[i]; + + if (pathspec && !ce_path_match(ce, pathspec, NULL)) + continue; + + if (chmod_cache_entry(ce, force_mode) < 0) + fprintf(stderr, "cannot chmod '%s'", ce->name); + } +} + static int fix_unmerged_status(struct diff_filepair *p, struct update_callback_data *data) { @@ -65,8 +80,7 @@ static void update_callback(struct diff_queue_struct *q, die(_("unexpected diff status %c"), p->status); case DIFF_STATUS_MODIFIED: case DIFF_STATUS_TYPE_CHANGED: - if (add_file_to_index(&the_index, path, - data->flags, data->force_mode)) { + if (add_file_to_index(&the_index, path, data->flags)) { if (!(data->flags & ADD_CACHE_IGNORE_ERRORS)) die(_("updating files failed")); data->add_errors++; @@ -84,15 +98,14 @@ static void update_callback(struct diff_queue_struct *q, } } -int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, - int flags, int force_mode) +int add_files_to_cache(const char *prefix, + const struct pathspec *pathspec, int flags) { struct update_callback_data data; struct rev_info rev; memset(&data, 0, sizeof(data)); data.flags = flags; - data.force_mode = force_mode; init_revisions(&rev, prefix); setup_revisions(0, NULL, &rev, NULL); @@ -281,7 +294,7 @@ static int add_config(const char *var, const char *value, void *cb) return git_default_config(var, value, cb); } -static int add_files(struct dir_struct *dir, int flags, int force_mode) +static int add_files(struct dir_struct *dir, int flags) { int i, exit_status = 0; @@ -294,8 +307,7 @@ static int add_files(struct dir_struct *dir, int flags, int force_mode) } for (i = 0; i < dir->nr; i++) - if (add_file_to_index(&the_index, dir->entries[i]->name, - flags, force_mode)) { + if (add_file_to_index(&the_index, dir->entries[i]->name, flags)) { if (!ignore_add_errors) die(_("adding files failed")); exit_status = 1; @@ -308,7 +320,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) int exit_status = 0; struct pathspec pathspec; struct dir_struct dir; - int flags, force_mode; + int flags; int add_new_files; int require_pathspec; char *seen = NULL; @@ -342,13 +354,8 @@ int cmd_add(int argc, const char **argv, const char *prefix) if (!show_only && ignore_missing) die(_("Option --ignore-missing can only be used together with --dry-run")); - if (!chmod_arg) - force_mode = 0; - else if (!strcmp(chmod_arg, "-x")) - force_mode = 0666; - else if (!strcmp(chmod_arg, "+x")) - force_mode = 0777; - else + if (chmod_arg && ((chmod_arg[0] != '-' && chmod_arg[0] != '+') || + chmod_arg[1] != 'x' || chmod_arg[2])) die(_("--chmod param '%s' must be either -x or +x"), chmod_arg); add_new_files = !take_worktree_changes && !refresh_only; @@ -441,11 +448,13 @@ int cmd_add(int argc, const char **argv, const char *prefix) plug_bulk_checkin(); - exit_status |= add_files_to_cache(prefix, &pathspec, flags, force_mode); + exit_status |= add_files_to_cache(prefix, &pathspec, flags); if (add_new_files) - exit_status |= add_files(&dir, flags, force_mode); + exit_status |= add_files(&dir, flags); + if (chmod_arg && pathspec.nr) + chmod_pathspec(&pathspec, chmod_arg[0]); unplug_bulk_checkin(); finish: diff --git a/builtin/blame.c b/builtin/blame.c index 2ff18b168e..4ddfadb71f 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -2111,7 +2111,7 @@ static void find_alignment(struct scoreboard *sb, int *option) unsigned largest_score = 0; struct blame_entry *e; int compute_auto_abbrev = (abbrev < 0); - int auto_abbrev = default_abbrev; + int auto_abbrev = DEFAULT_ABBREV; for (e = sb->ent; e; e = e->next) { struct origin *suspect = e->suspect; @@ -2220,6 +2220,8 @@ static int git_blame_config(const char *var, const char *value, void *cb) return 0; } + if (git_diff_heuristic_config(var, value, cb) < 0) + return -1; if (userdiff_config(var, value) < 0) return -1; @@ -2454,6 +2456,41 @@ static char *prepare_final(struct scoreboard *sb) return xstrdup_or_null(name); } +static const char *dwim_reverse_initial(struct scoreboard *sb) +{ + /* + * DWIM "git blame --reverse ONE -- PATH" as + * "git blame --reverse ONE..HEAD -- PATH" but only do so + * when it makes sense. + */ + struct object *obj; + struct commit *head_commit; + unsigned char head_sha1[20]; + + if (sb->revs->pending.nr != 1) + return NULL; + + /* Is that sole rev a committish? */ + obj = sb->revs->pending.objects[0].item; + obj = deref_tag(obj, NULL, 0); + if (obj->type != OBJ_COMMIT) + return NULL; + + /* Do we have HEAD? */ + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL)) + return NULL; + head_commit = lookup_commit_reference_gently(head_sha1, 1); + if (!head_commit) + return NULL; + + /* Turn "ONE" into "ONE..HEAD" then */ + obj->flags |= UNINTERESTING; + add_pending_object(sb->revs, &head_commit->object, "HEAD"); + + sb->final = (struct commit *)obj; + return sb->revs->pending.objects[0].name; +} + static char *prepare_initial(struct scoreboard *sb) { int i; @@ -2472,14 +2509,17 @@ static char *prepare_initial(struct scoreboard *sb) if (obj->type != OBJ_COMMIT) die("Non commit %s?", revs->pending.objects[i].name); if (sb->final) - die("More than one commit to dig down to %s and %s?", + die("More than one commit to dig up from, %s and %s?", revs->pending.objects[i].name, final_commit_name); sb->final = (struct commit *) obj; final_commit_name = revs->pending.objects[i].name; } + + if (!final_commit_name) + final_commit_name = dwim_reverse_initial(sb); if (!final_commit_name) - die("No commit to dig down to?"); + die("No commit to dig up from?"); return xstrdup(final_commit_name); } @@ -2550,6 +2590,15 @@ int cmd_blame(int argc, const char **argv, const char *prefix) OPT_BIT('s', NULL, &output_option, N_("Suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR), OPT_BIT('e', "show-email", &output_option, N_("Show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL), OPT_BIT('w', NULL, &xdl_opts, N_("Ignore whitespace differences"), XDF_IGNORE_WHITESPACE), + + /* + * The following two options are parsed by parse_revision_opt() + * and are only included here to get included in the "-h" + * output: + */ + { OPTION_LOWLEVEL_CALLBACK, 0, "indent-heuristic", NULL, NULL, N_("Use an experimental indent-based heuristic to improve diffs"), PARSE_OPT_NOARG, parse_opt_unknown_cb }, + { OPTION_LOWLEVEL_CALLBACK, 0, "compaction-heuristic", NULL, NULL, N_("Use an experimental blank-line-based heuristic to improve diffs"), PARSE_OPT_NOARG, parse_opt_unknown_cb }, + OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL), OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")), OPT_STRING(0, "contents", &contents_from, N_("file"), N_("Use <file>'s contents as the final image")), @@ -2596,6 +2645,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) } parse_done: no_whole_file_rename = !DIFF_OPT_TST(&revs.diffopt, FOLLOW_RENAMES); + xdl_opts |= revs.diffopt.xdl_opts & (XDF_COMPACTION_HEURISTIC | XDF_INDENT_HEURISTIC); DIFF_OPT_CLR(&revs.diffopt, FOLLOW_RENAMES); argc = parse_options_end(&ctx); diff --git a/builtin/cat-file.c b/builtin/cat-file.c index cca97a86c0..30383e9eb4 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -53,7 +53,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, char *buf; unsigned long size; struct object_context obj_context; - struct object_info oi = {NULL}; + struct object_info oi = OBJECT_INFO_INIT; struct strbuf sb = STRBUF_INIT; unsigned flags = LOOKUP_REPLACE_OBJECT; const char *path = force_path; @@ -449,8 +449,7 @@ static int batch_objects(struct batch_options *opt) data.split_on_whitespace = 1; if (opt->all_objects) { - struct object_info empty; - memset(&empty, 0, sizeof(empty)); + struct object_info empty = OBJECT_INFO_INIT; if (!memcmp(&data.info, &empty, sizeof(empty))) data.skip_object_info = 1; } diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index 92c69672e9..30a49d9f42 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -16,7 +16,7 @@ static int checkout_stage; /* default to checkout stage0 */ static int to_tempfile; static char topath[4][TEMPORARY_FILENAME_LENGTH + 1]; -static struct checkout state; +static struct checkout state = CHECKOUT_INIT; static void write_tempfile_record(const char *name, const char *prefix) { diff --git a/builtin/checkout.c b/builtin/checkout.c index 9941abc3ac..9b2a5b31d4 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -239,7 +239,7 @@ static int checkout_paths(const struct checkout_opts *opts, const char *revision) { int pos; - struct checkout state; + struct checkout state = CHECKOUT_INIT; static char *ps_matched; struct object_id rev; struct commit *head; @@ -352,7 +352,6 @@ static int checkout_paths(const struct checkout_opts *opts, return 1; /* Now we are committed to check them out */ - memset(&state, 0, sizeof(state)); state.force = 1; state.refresh_cache = 1; state.istate = &the_index; @@ -548,7 +547,7 @@ static int merge_working_tree(const struct checkout_opts *opts, * entries in the index. */ - add_files_to_cache(NULL, NULL, 0, 0); + add_files_to_cache(NULL, NULL, 0); /* * NEEDSWORK: carrying over local changes * when branches have different end-of-line @@ -985,7 +984,7 @@ static int parse_branchname_arg(int argc, const char **argv, int recover_with_dwim = dwim_new_local_branch_ok; if (!has_dash_dash && - (check_filename(NULL, arg) || !no_wildcard(arg))) + (check_filename(opts->prefix, arg) || !no_wildcard(arg))) recover_with_dwim = 0; /* * Accept "git checkout foo" and "git checkout foo --" @@ -1038,7 +1037,7 @@ static int parse_branchname_arg(int argc, const char **argv, if (!*source_tree) /* case (1): want a tree */ die(_("reference is not a tree: %s"), arg); - if (!has_dash_dash) {/* case (3).(d) -> (1) */ + if (!has_dash_dash) { /* case (3).(d) -> (1) */ /* * Do not complain the most common case * git checkout branch @@ -1046,7 +1045,7 @@ static int parse_branchname_arg(int argc, const char **argv, * it would be extremely annoying. */ if (argc) - verify_non_filename(NULL, arg); + verify_non_filename(opts->prefix, arg); } else { argcount++; argv++; diff --git a/builtin/clone.c b/builtin/clone.c index 404c5e8022..6c76a6ed66 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -41,9 +41,11 @@ static const char * const builtin_clone_usage[] = { static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1; static int option_local = -1, option_no_hardlinks, option_shared, option_recursive; static int option_shallow_submodules; -static char *option_template, *option_depth; +static int deepen; +static char *option_template, *option_depth, *option_since; static char *option_origin = NULL; static char *option_branch = NULL; +static struct string_list option_not = STRING_LIST_INIT_NODUP; static const char *real_git_dir; static char *option_upload_pack = "git-upload-pack"; static int option_verbosity; @@ -94,6 +96,10 @@ static struct option builtin_clone_options[] = { N_("path to git-upload-pack on the remote")), OPT_STRING(0, "depth", &option_depth, N_("depth"), N_("create a shallow clone of that depth")), + OPT_STRING(0, "shallow-since", &option_since, N_("time"), + N_("create a shallow clone since a specific time")), + OPT_STRING_LIST(0, "shallow-exclude", &option_not, N_("revision"), + N_("deepen history of shallow clone by excluding rev")), OPT_BOOL(0, "single-branch", &option_single_branch, N_("clone only one branch, HEAD or --branch")), OPT_BOOL(0, "shallow-submodules", &option_shallow_submodules, @@ -345,8 +351,11 @@ static void copy_alternates(struct strbuf *src, struct strbuf *dst, continue; } abs_path = mkpathdup("%s/objects/%s", src_repo, line.buf); - normalize_path_copy(abs_path, abs_path); - add_to_alternates_file(abs_path); + if (!normalize_path_copy(abs_path, abs_path)) + add_to_alternates_file(abs_path); + else + warning("skipping invalid relative alternate: %s/%s", + src_repo, line.buf); free(abs_path); } strbuf_release(&line); @@ -670,7 +679,7 @@ static void update_head(const struct ref *our, const struct ref *remote, } } -static int checkout(void) +static int checkout(int submodule_progress) { unsigned char sha1[20]; char *head; @@ -734,6 +743,9 @@ static int checkout(void) if (max_jobs != -1) argv_array_pushf(&args, "--jobs=%d", max_jobs); + if (submodule_progress) + argv_array_push(&args, "--progress"); + err = run_command_v_opt(args.argv, RUN_GIT_CMD); argv_array_clear(&args); } @@ -841,6 +853,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) const char *src_ref_prefix = "refs/heads/"; struct remote *remote; int err = 0, complete_refs_before_fetch = 1; + int submodule_progress; struct refspec *refspec; const char *fetch_pattern; @@ -857,8 +870,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix) usage_msg_opt(_("You must specify a repository to clone."), builtin_clone_usage, builtin_clone_options); + if (option_depth || option_since || option_not.nr) + deepen = 1; if (option_single_branch == -1) - option_single_branch = option_depth ? 1 : 0; + option_single_branch = deepen ? 1 : 0; if (option_mirror) option_bare = 1; @@ -931,16 +946,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix) set_git_work_tree(work_tree); } - junk_git_dir = git_dir; + junk_git_dir = real_git_dir ? real_git_dir : git_dir; if (safe_create_leading_directories_const(git_dir) < 0) die(_("could not create leading directories of '%s'"), git_dir); - set_git_dir_init(git_dir, real_git_dir, 0); - if (real_git_dir) { - git_dir = real_git_dir; - junk_git_dir = real_git_dir; - } - if (0 <= option_verbosity) { if (option_bare) fprintf(stderr, _("Cloning into bare repository '%s'...\n"), dir); @@ -966,7 +975,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix) } } - init_db(option_template, INIT_DB_QUIET); + init_db(git_dir, real_git_dir, option_template, INIT_DB_QUIET); + + if (real_git_dir) + git_dir = real_git_dir; + write_config(&option_config); git_config(git_default_config, NULL); @@ -1004,6 +1017,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (is_local) { if (option_depth) warning(_("--depth is ignored in local clones; use file:// instead.")); + if (option_since) + warning(_("--shallow-since is ignored in local clones; use file:// instead.")); + if (option_not.nr) + warning(_("--shallow-exclude is ignored in local clones; use file:// instead.")); if (!access(mkpath("%s/shallow", path), F_OK)) { if (option_local > 0) warning(_("source repository is shallow, ignoring --local")); @@ -1022,6 +1039,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (option_depth) transport_set_option(transport, TRANS_OPT_DEPTH, option_depth); + if (option_since) + transport_set_option(transport, TRANS_OPT_DEEPEN_SINCE, + option_since); + if (option_not.nr) + transport_set_option(transport, TRANS_OPT_DEEPEN_NOT, + (const char *)&option_not); if (option_single_branch) transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1"); @@ -1029,7 +1052,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) transport_set_option(transport, TRANS_OPT_UPLOADPACK, option_upload_pack); - if (transport->smart_options && !option_depth) + if (transport->smart_options && !deepen) transport->smart_options->check_self_contained_and_connected = 1; refs = transport_get_remote_refs(transport); @@ -1099,6 +1122,14 @@ int cmd_clone(int argc, const char **argv, const char *prefix) update_head(our_head_points_at, remote_head, reflog_msg.buf); + /* + * We want to show progress for recursive submodule clones iff + * we did so for the main clone. But only the transport knows + * the final decision for this flag, so we need to rescue the value + * before we free the transport. + */ + submodule_progress = transport->progress; + transport_unlock_pack(transport); transport_disconnect(transport); @@ -1108,7 +1139,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) } junk_mode = JUNK_LEAVE_REPO; - err = checkout(); + err = checkout(submodule_progress); strbuf_release(&reflog_msg); strbuf_release(&branch_top); diff --git a/builtin/commit.c b/builtin/commit.c index bb9f79b6ef..1cba3b75c8 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -397,7 +397,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix */ if (all || (also && pathspec.nr)) { hold_locked_index(&index_lock, 1); - add_files_to_cache(also ? prefix : NULL, &pathspec, 0, 0); + add_files_to_cache(also ? prefix : NULL, &pathspec, 0); refresh_cache_or_die(refresh_flags); update_main_cache_tree(WRITE_TREE_SILENT); if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) diff --git a/builtin/count-objects.c b/builtin/count-objects.c index ba9291944f..a04b4f2ef3 100644 --- a/builtin/count-objects.c +++ b/builtin/count-objects.c @@ -8,6 +8,7 @@ #include "dir.h" #include "builtin.h" #include "parse-options.h" +#include "quote.h" static unsigned long garbage; static off_t size_garbage; @@ -73,6 +74,14 @@ static int count_cruft(const char *basename, const char *path, void *data) return 0; } +static int print_alternate(struct alternate_object_database *alt, void *data) +{ + printf("alternate: "); + quote_c_style(alt->path, NULL, stdout, 0); + putchar('\n'); + return 0; +} + static char const * const count_objects_usage[] = { N_("git count-objects [-v] [-H | --human-readable]"), NULL @@ -88,6 +97,8 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix) OPT_END(), }; + git_config(git_default_config, NULL); + argc = parse_options(argc, argv, prefix, opts, count_objects_usage, 0); /* we do not take arguments other than flags for now */ if (argc) @@ -140,6 +151,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix) printf("prune-packable: %lu\n", packed_loose); printf("garbage: %lu\n", garbage); printf("size-garbage: %s\n", garbage_buf.buf); + foreach_alt_odb(print_alternate, NULL); strbuf_release(&loose_buf); strbuf_release(&pack_buf); strbuf_release(&garbage_buf); diff --git a/builtin/describe.c b/builtin/describe.c index 8a25abe0a0..01490a157e 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -352,7 +352,7 @@ static void describe(const char *arg, int last_one) oid_to_hex(oid)); } - qsort(all_matches, match_cnt, sizeof(all_matches[0]), compare_pt); + QSORT(all_matches, match_cnt, compare_pt); if (gave_up_on) { commit_list_insert_by_date(gave_up_on, &list); diff --git a/builtin/fast-export.c b/builtin/fast-export.c index c0652a7ed0..1e815b5577 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -347,7 +347,7 @@ static void show_filemodify(struct diff_queue_struct *q, * Handle files below a directory first, in case they are all deleted * and the directory changes to a file or symlink. */ - qsort(q->queue, q->nr, sizeof(q->queue[0]), depth_first); + QSORT(q->queue, q->nr, depth_first); for (i = 0; i < q->nr; i++) { struct diff_filespec *ospec = q->queue[i]->one; diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index bfd0be44a9..cfe9e447c2 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -51,6 +51,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) struct child_process *conn; struct fetch_pack_args args; struct sha1_array shallow = SHA1_ARRAY_INIT; + struct string_list deepen_not = STRING_LIST_INIT_DUP; packet_trace_identity("fetch-pack"); @@ -60,12 +61,12 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) for (i = 1; i < argc && *argv[i] == '-'; i++) { const char *arg = argv[i]; - if (starts_with(arg, "--upload-pack=")) { - args.uploadpack = arg + 14; + if (skip_prefix(arg, "--upload-pack=", &arg)) { + args.uploadpack = arg; continue; } - if (starts_with(arg, "--exec=")) { - args.uploadpack = arg + 7; + if (skip_prefix(arg, "--exec=", &arg)) { + args.uploadpack = arg; continue; } if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) { @@ -101,8 +102,20 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) args.verbose = 1; continue; } - if (starts_with(arg, "--depth=")) { - args.depth = strtol(arg + 8, NULL, 0); + if (skip_prefix(arg, "--depth=", &arg)) { + args.depth = strtol(arg, NULL, 0); + continue; + } + if (skip_prefix(arg, "--shallow-since=", &arg)) { + args.deepen_since = xstrdup(arg); + continue; + } + if (skip_prefix(arg, "--shallow-exclude=", &arg)) { + string_list_append(&deepen_not, arg); + continue; + } + if (!strcmp(arg, "--deepen-relative")) { + args.deepen_relative = 1; continue; } if (!strcmp("--no-progress", arg)) { @@ -132,6 +145,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) } usage(fetch_pack_usage); } + if (deepen_not.nr) + args.deepen_not = &deepen_not; if (i < argc) dest = argv[i++]; diff --git a/builtin/fetch.c b/builtin/fetch.c index 09813cd826..b6a5597cbf 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -35,13 +35,15 @@ static int fetch_prune_config = -1; /* unspecified */ static int prune = -1; /* unspecified */ #define PRUNE_BY_DEFAULT 0 /* do we prune by default? */ -static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity; +static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative; static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT; -static int tags = TAGS_DEFAULT, unshallow, update_shallow; +static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen; static int max_children = -1; static enum transport_family family; static const char *depth; +static const char *deepen_since; static const char *upload_pack; +static struct string_list deepen_not = STRING_LIST_INIT_NODUP; static struct strbuf default_rla = STRBUF_INIT; static struct transport *gtransport; static struct transport *gsecondary; @@ -117,6 +119,12 @@ static struct option builtin_fetch_options[] = { OPT_BOOL(0, "progress", &progress, N_("force progress reporting")), OPT_STRING(0, "depth", &depth, N_("depth"), N_("deepen history of shallow clone")), + OPT_STRING(0, "shallow-since", &deepen_since, N_("time"), + N_("deepen history of shallow repository based on time")), + OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"), + N_("deepen history of shallow clone by excluding rev")), + OPT_INTEGER(0, "deepen", &deepen_relative, + N_("deepen history of shallow clone")), { OPTION_SET_INT, 0, "unshallow", &unshallow, NULL, N_("convert to a complete repository"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 }, @@ -233,9 +241,10 @@ static void find_non_local_tags(struct transport *transport, * as one to ignore by setting util to NULL. */ if (ends_with(ref->name, "^{}")) { - if (item && !has_object_file(&ref->old_oid) && + if (item && + !has_object_file_with_flags(&ref->old_oid, HAS_SHA1_QUICK) && !will_fetch(head, ref->old_oid.hash) && - !has_sha1_file(item->util) && + !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) && !will_fetch(head, item->util)) item->util = NULL; item = NULL; @@ -248,7 +257,8 @@ static void find_non_local_tags(struct transport *transport, * to check if it is a lightweight tag that we want to * fetch. */ - if (item && !has_sha1_file(item->util) && + if (item && + !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) && !will_fetch(head, item->util)) item->util = NULL; @@ -268,7 +278,8 @@ static void find_non_local_tags(struct transport *transport, * We may have a final lightweight tag that needs to be * checked to see if it needs fetching. */ - if (item && !has_sha1_file(item->util) && + if (item && + !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) && !will_fetch(head, item->util)) item->util = NULL; @@ -881,7 +892,7 @@ static int quickfetch(struct ref *ref_map) * really need to perform. Claiming failure now will ensure * we perform the network exchange to deepen our history. */ - if (depth) + if (deepen) return -1; opt.quiet = 1; return check_connected(iterate_ref_map, &rm, &opt); @@ -991,7 +1002,7 @@ static void set_option(struct transport *transport, const char *name, const char name, transport->url); } -static struct transport *prepare_transport(struct remote *remote) +static struct transport *prepare_transport(struct remote *remote, int deepen) { struct transport *transport; transport = transport_get(remote, NULL); @@ -1003,6 +1014,13 @@ static struct transport *prepare_transport(struct remote *remote) set_option(transport, TRANS_OPT_KEEP, "yes"); if (depth) set_option(transport, TRANS_OPT_DEPTH, depth); + if (deepen && deepen_since) + set_option(transport, TRANS_OPT_DEEPEN_SINCE, deepen_since); + if (deepen && deepen_not.nr) + set_option(transport, TRANS_OPT_DEEPEN_NOT, + (const char *)&deepen_not); + if (deepen_relative) + set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, "yes"); if (update_shallow) set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes"); return transport; @@ -1010,13 +1028,25 @@ static struct transport *prepare_transport(struct remote *remote) static void backfill_tags(struct transport *transport, struct ref *ref_map) { - if (transport->cannot_reuse) { - gsecondary = prepare_transport(transport->remote); + int cannot_reuse; + + /* + * Once we have set TRANS_OPT_DEEPEN_SINCE, we can't unset it + * when remote helper is used (setting it to an empty string + * is not unsetting). We could extend the remote helper + * protocol for that, but for now, just force a new connection + * without deepen-since. Similar story for deepen-not. + */ + cannot_reuse = transport->cannot_reuse || + deepen_since || deepen_not.nr; + if (cannot_reuse) { + gsecondary = prepare_transport(transport->remote, 0); transport = gsecondary; } transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL); transport_set_option(transport, TRANS_OPT_DEPTH, "0"); + transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL); fetch_refs(transport, ref_map); if (gsecondary) { @@ -1227,7 +1257,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv) die(_("No remote repository specified. Please, specify either a URL or a\n" "remote name from which new revisions should be fetched.")); - gtransport = prepare_transport(remote); + gtransport = prepare_transport(remote, 1); if (prune < 0) { /* no command line request */ @@ -1287,6 +1317,13 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, builtin_fetch_options, builtin_fetch_usage, 0); + if (deepen_relative) { + if (deepen_relative < 0) + die(_("Negative depth in --deepen is not supported")); + if (depth) + die(_("--deepen and --depth are mutually exclusive")); + depth = xstrfmt("%d", deepen_relative); + } if (unshallow) { if (depth) die(_("--depth and --unshallow cannot be used together")); @@ -1299,6 +1336,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) /* no need to be strict, transport_set_option() will validate it again */ if (depth && atoi(depth) < 1) die(_("depth %s is not a positive number"), depth); + if (depth || deepen_since || deepen_not.nr) + deepen = 1; if (recurse_submodules != RECURSE_SUBMODULES_OFF) { if (recurse_submodules_default) { diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index ac84e99f3a..efab62fd85 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -314,14 +314,10 @@ static void add_people_info(struct strbuf *out, struct string_list *authors, struct string_list *committers) { - if (authors->nr) - qsort(authors->items, - authors->nr, sizeof(authors->items[0]), - cmp_string_list_util_as_integral); - if (committers->nr) - qsort(committers->items, - committers->nr, sizeof(committers->items[0]), - cmp_string_list_util_as_integral); + QSORT(authors->items, authors->nr, + cmp_string_list_util_as_integral); + QSORT(committers->items, committers->nr, + cmp_string_list_util_as_integral); credit_people(out, authors, 'a'); credit_people(out, committers, 'c'); @@ -395,7 +391,7 @@ static void shortlog(const char *name, for (i = 0; i < subjects.nr; i++) if (i >= limit) - strbuf_addf(out, " ...\n"); + strbuf_addstr(out, " ...\n"); else strbuf_addf(out, " %s\n", subjects.items[i].string); diff --git a/builtin/fsck.c b/builtin/fsck.c index 055dfdcf9e..f01b81eebf 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -644,14 +644,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) fsck_object_dir(get_object_directory()); prepare_alt_odb(); - for (alt = alt_odb_list; alt; alt = alt->next) { - /* directory name, minus trailing slash */ - size_t namelen = alt->name - alt->base - 1; - struct strbuf name = STRBUF_INIT; - strbuf_add(&name, alt->base, namelen); - fsck_object_dir(name.buf); - strbuf_release(&name); - } + for (alt = alt_odb_list; alt; alt = alt->next) + fsck_object_dir(alt->path); } if (check_full) { diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 4a8b4aebba..0a27bab11b 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -1190,10 +1190,8 @@ static void resolve_deltas(void) return; /* Sort deltas by base SHA1/offset for fast searching */ - qsort(ofs_deltas, nr_ofs_deltas, sizeof(struct ofs_delta_entry), - compare_ofs_delta_entry); - qsort(ref_deltas, nr_ref_deltas, sizeof(struct ref_delta_entry), - compare_ref_delta_entry); + QSORT(ofs_deltas, nr_ofs_deltas, compare_ofs_delta_entry); + QSORT(ref_deltas, nr_ref_deltas, compare_ref_delta_entry); if (verbose || show_resolving_progress) progress = start_progress(_("Resolving deltas"), @@ -1356,7 +1354,7 @@ static void fix_unresolved_deltas(struct sha1file *f) ALLOC_ARRAY(sorted_by_pos, nr_ref_deltas); for (i = 0; i < nr_ref_deltas; i++) sorted_by_pos[i] = &ref_deltas[i]; - qsort(sorted_by_pos, nr_ref_deltas, sizeof(*sorted_by_pos), delta_pos_compare); + QSORT(sorted_by_pos, nr_ref_deltas, delta_pos_compare); for (i = 0; i < nr_ref_deltas; i++) { struct ref_delta_entry *d = sorted_by_pos[i]; @@ -1533,8 +1531,7 @@ static void read_v2_anomalous_offsets(struct packed_git *p, opts->anomaly[opts->anomaly_nr++] = ntohl(idx2[off * 2 + 1]); } - if (1 < opts->anomaly_nr) - qsort(opts->anomaly, opts->anomaly_nr, sizeof(uint32_t), cmp_uint32); + QSORT(opts->anomaly, opts->anomaly_nr, cmp_uint32); } static void read_idx_option(struct pack_idx_option *opts, const char *pack_name) diff --git a/builtin/init-db.c b/builtin/init-db.c index 72e81447ae..2399b97d90 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -22,7 +22,6 @@ static int init_is_bare_repository = 0; static int init_shared_repository = -1; static const char *init_db_template_dir; -static const char *git_link; static void copy_templates_1(struct strbuf *path, struct strbuf *template, DIR *dir) @@ -138,7 +137,7 @@ static void copy_templates(const char *template_dir) goto close_free_return; } - strbuf_addstr(&path, get_git_dir()); + strbuf_addstr(&path, get_git_common_dir()); strbuf_complete(&path, '/'); copy_templates_1(&path, &template_path, dir); close_free_return: @@ -171,7 +170,8 @@ static int needs_work_tree_config(const char *git_dir, const char *work_tree) return 1; } -static int create_default_files(const char *template_path) +static int create_default_files(const char *template_path, + const char *original_git_dir) { struct stat st1; struct strbuf buf = STRBUF_INIT; @@ -264,7 +264,7 @@ static int create_default_files(const char *template_path) /* allow template config file to override the default */ if (log_all_ref_updates == -1) git_config_set("core.logallrefupdates", "true"); - if (needs_work_tree_config(get_git_dir(), work_tree)) + if (needs_work_tree_config(original_git_dir, work_tree)) git_config_set("core.worktree", work_tree); } @@ -312,34 +312,7 @@ static void create_object_directory(void) strbuf_release(&path); } -int set_git_dir_init(const char *git_dir, const char *real_git_dir, - int exist_ok) -{ - if (real_git_dir) { - struct stat st; - - if (!exist_ok && !stat(git_dir, &st)) - die(_("%s already exists"), git_dir); - - if (!exist_ok && !stat(real_git_dir, &st)) - die(_("%s already exists"), real_git_dir); - - /* - * make sure symlinks are resolved because we'll be - * moving the target repo later on in separate_git_dir() - */ - git_link = xstrdup(real_path(git_dir)); - set_git_dir(real_path(real_git_dir)); - } - else { - set_git_dir(real_path(git_dir)); - git_link = NULL; - } - startup_info->have_repository = 1; - return 0; -} - -static void separate_git_dir(const char *git_dir) +static void separate_git_dir(const char *git_dir, const char *git_link) { struct stat st; @@ -360,13 +333,31 @@ static void separate_git_dir(const char *git_dir) write_file(git_link, "gitdir: %s", git_dir); } -int init_db(const char *template_dir, unsigned int flags) +int init_db(const char *git_dir, const char *real_git_dir, + const char *template_dir, unsigned int flags) { int reinit; - const char *git_dir = get_git_dir(); + int exist_ok = flags & INIT_DB_EXIST_OK; + char *original_git_dir = xstrdup(real_path(git_dir)); + + if (real_git_dir) { + struct stat st; + + if (!exist_ok && !stat(git_dir, &st)) + die(_("%s already exists"), git_dir); + + if (!exist_ok && !stat(real_git_dir, &st)) + die(_("%s already exists"), real_git_dir); - if (git_link) - separate_git_dir(git_dir); + set_git_dir(real_path(real_git_dir)); + git_dir = get_git_dir(); + separate_git_dir(git_dir, original_git_dir); + } + else { + set_git_dir(real_path(git_dir)); + git_dir = get_git_dir(); + } + startup_info->have_repository = 1; safe_create_dir(git_dir, 0); @@ -379,7 +370,7 @@ int init_db(const char *template_dir, unsigned int flags) */ check_repository_format(); - reinit = create_default_files(template_dir); + reinit = create_default_files(template_dir, original_git_dir); create_object_directory(); @@ -419,6 +410,7 @@ int init_db(const char *template_dir, unsigned int flags) git_dir, len && git_dir[len-1] != '/' ? "/" : ""); } + free(original_git_dir); return 0; } @@ -586,7 +578,6 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) set_git_work_tree(work_tree); } - set_git_dir_init(git_dir, real_git_dir, 1); - - return init_db(template_dir, flags); + flags |= INIT_DB_EXIST_OK; + return init_db(git_dir, real_git_dir, template_dir, flags); } diff --git a/builtin/log.c b/builtin/log.c index b8cdf2b9d9..55d20cc2d8 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -1111,6 +1111,11 @@ static int subject_prefix_callback(const struct option *opt, const char *arg, return 0; } +static int rfc_callback(const struct option *opt, const char *arg, int unset) +{ + return subject_prefix_callback(opt, "RFC PATCH", unset); +} + static int numbered_cmdline_opt = 0; static int numbered_callback(const struct option *opt, const char *arg, @@ -1418,6 +1423,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) N_("start numbering patches at <n> instead of 1")), OPT_INTEGER('v', "reroll-count", &reroll_count, N_("mark the series as Nth re-roll")), + { OPTION_CALLBACK, 0, "rfc", &rev, NULL, + N_("Use [RFC PATCH] instead of [PATCH]"), + PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback }, { OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"), N_("Use [<prefix>] instead of [PATCH]"), PARSE_OPT_NONEG, subject_prefix_callback }, @@ -1556,7 +1564,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (numbered && keep_subject) die (_("-n and -k are mutually exclusive.")); if (keep_subject && subject_prefix) - die (_("--subject-prefix and -k are mutually exclusive.")); + die (_("--subject-prefix/--rfc and -k are mutually exclusive.")); rev.preserve_subject = keep_subject; argc = setup_revisions(argc, argv, &rev, &s_r_opt); diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 197f153f50..1592290815 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -14,6 +14,7 @@ #include "resolve-undo.h" #include "string-list.h" #include "pathspec.h" +#include "run-command.h" static int abbrev; static int show_deleted; @@ -28,8 +29,11 @@ static int show_valid_bit; static int line_terminator = '\n'; static int debug_mode; static int show_eol; +static int recurse_submodules; +static struct argv_array submodules_options = ARGV_ARRAY_INIT; static const char *prefix; +static const char *super_prefix; static int max_prefix_len; static int prefix_len; static struct pathspec pathspec; @@ -68,11 +72,24 @@ static void write_eolinfo(const struct cache_entry *ce, const char *path) static void write_name(const char *name) { /* + * Prepend the super_prefix to name to construct the full_name to be + * written. + */ + struct strbuf full_name = STRBUF_INIT; + if (super_prefix) { + strbuf_addstr(&full_name, super_prefix); + strbuf_addstr(&full_name, name); + name = full_name.buf; + } + + /* * With "--full-name", prefix_len=0; this caller needs to pass * an empty string in that case (a NULL is good for ""). */ write_name_quoted_relative(name, prefix_len ? prefix : NULL, stdout, line_terminator); + + strbuf_release(&full_name); } static void show_dir_entry(const char *tag, struct dir_entry *ent) @@ -152,55 +169,117 @@ static void show_killed_files(struct dir_struct *dir) } } +/* + * Compile an argv_array with all of the options supported by --recurse_submodules + */ +static void compile_submodule_options(const struct dir_struct *dir, int show_tag) +{ + if (line_terminator == '\0') + argv_array_push(&submodules_options, "-z"); + if (show_tag) + argv_array_push(&submodules_options, "-t"); + if (show_valid_bit) + argv_array_push(&submodules_options, "-v"); + if (show_cached) + argv_array_push(&submodules_options, "--cached"); + if (show_eol) + argv_array_push(&submodules_options, "--eol"); + if (debug_mode) + argv_array_push(&submodules_options, "--debug"); +} + +/** + * Recursively call ls-files on a submodule + */ +static void show_gitlink(const struct cache_entry *ce) +{ + struct child_process cp = CHILD_PROCESS_INIT; + int status; + int i; + + argv_array_pushf(&cp.args, "--super-prefix=%s%s/", + super_prefix ? super_prefix : "", + ce->name); + argv_array_push(&cp.args, "ls-files"); + argv_array_push(&cp.args, "--recurse-submodules"); + + /* add supported options */ + argv_array_pushv(&cp.args, submodules_options.argv); + + /* + * Pass in the original pathspec args. The submodule will be + * responsible for prepending the 'submodule_prefix' prior to comparing + * against the pathspec for matches. + */ + argv_array_push(&cp.args, "--"); + for (i = 0; i < pathspec.nr; i++) + argv_array_push(&cp.args, pathspec.items[i].original); + + cp.git_cmd = 1; + cp.dir = ce->name; + status = run_command(&cp); + if (status) + exit(status); +} + static void show_ce_entry(const char *tag, const struct cache_entry *ce) { + struct strbuf name = STRBUF_INIT; int len = max_prefix_len; + if (super_prefix) + strbuf_addstr(&name, super_prefix); + strbuf_addstr(&name, ce->name); if (len >= ce_namelen(ce)) die("git ls-files: internal error - cache entry not superset of prefix"); - if (!match_pathspec(&pathspec, ce->name, ce_namelen(ce), - len, ps_matched, - S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode))) - return; + if (recurse_submodules && S_ISGITLINK(ce->ce_mode) && + submodule_path_match(&pathspec, name.buf, ps_matched)) { + show_gitlink(ce); + } else if (match_pathspec(&pathspec, name.buf, name.len, + len, ps_matched, + S_ISDIR(ce->ce_mode) || + S_ISGITLINK(ce->ce_mode))) { + if (tag && *tag && show_valid_bit && + (ce->ce_flags & CE_VALID)) { + static char alttag[4]; + memcpy(alttag, tag, 3); + if (isalpha(tag[0])) + alttag[0] = tolower(tag[0]); + else if (tag[0] == '?') + alttag[0] = '!'; + else { + alttag[0] = 'v'; + alttag[1] = tag[0]; + alttag[2] = ' '; + alttag[3] = 0; + } + tag = alttag; + } - if (tag && *tag && show_valid_bit && - (ce->ce_flags & CE_VALID)) { - static char alttag[4]; - memcpy(alttag, tag, 3); - if (isalpha(tag[0])) - alttag[0] = tolower(tag[0]); - else if (tag[0] == '?') - alttag[0] = '!'; - else { - alttag[0] = 'v'; - alttag[1] = tag[0]; - alttag[2] = ' '; - alttag[3] = 0; + if (!show_stage) { + fputs(tag, stdout); + } else { + printf("%s%06o %s %d\t", + tag, + ce->ce_mode, + find_unique_abbrev(ce->oid.hash, abbrev), + ce_stage(ce)); + } + write_eolinfo(ce, ce->name); + write_name(ce->name); + if (debug_mode) { + const struct stat_data *sd = &ce->ce_stat_data; + + printf(" ctime: %d:%d\n", sd->sd_ctime.sec, sd->sd_ctime.nsec); + printf(" mtime: %d:%d\n", sd->sd_mtime.sec, sd->sd_mtime.nsec); + printf(" dev: %d\tino: %d\n", sd->sd_dev, sd->sd_ino); + printf(" uid: %d\tgid: %d\n", sd->sd_uid, sd->sd_gid); + printf(" size: %d\tflags: %x\n", sd->sd_size, ce->ce_flags); } - tag = alttag; } - if (!show_stage) { - fputs(tag, stdout); - } else { - printf("%s%06o %s %d\t", - tag, - ce->ce_mode, - find_unique_abbrev(ce->oid.hash,abbrev), - ce_stage(ce)); - } - write_eolinfo(ce, ce->name); - write_name(ce->name); - if (debug_mode) { - const struct stat_data *sd = &ce->ce_stat_data; - - printf(" ctime: %d:%d\n", sd->sd_ctime.sec, sd->sd_ctime.nsec); - printf(" mtime: %d:%d\n", sd->sd_mtime.sec, sd->sd_mtime.nsec); - printf(" dev: %d\tino: %d\n", sd->sd_dev, sd->sd_ino); - printf(" uid: %d\tgid: %d\n", sd->sd_uid, sd->sd_gid); - printf(" size: %d\tflags: %x\n", sd->sd_size, ce->ce_flags); - } + strbuf_release(&name); } static void show_ru_info(void) @@ -468,6 +547,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) { OPTION_SET_INT, 0, "full-name", &prefix_len, NULL, N_("make the output relative to the project top directory"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL }, + OPT_BOOL(0, "recurse-submodules", &recurse_submodules, + N_("recurse through submodules")), OPT_BOOL(0, "error-unmatch", &error_unmatch, N_("if any <file> is not in the index, treat this as an error")), OPT_STRING(0, "with-tree", &with_tree, N_("tree-ish"), @@ -484,6 +565,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) prefix = cmd_prefix; if (prefix) prefix_len = strlen(prefix); + super_prefix = get_super_prefix(); git_config(git_default_config, NULL); if (read_cache() < 0) @@ -519,13 +601,32 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) if (require_work_tree && !is_inside_work_tree()) setup_work_tree(); + if (recurse_submodules) + compile_submodule_options(&dir, show_tag); + + if (recurse_submodules && + (show_stage || show_deleted || show_others || show_unmerged || + show_killed || show_modified || show_resolve_undo || with_tree)) + die("ls-files --recurse-submodules unsupported mode"); + + if (recurse_submodules && error_unmatch) + die("ls-files --recurse-submodules does not support " + "--error-unmatch"); + parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD | PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP, prefix, argv); - /* Find common prefix for all pathspec's */ - max_prefix = common_prefix(&pathspec); + /* + * Find common prefix for all pathspec's + * This is used as a performance optimization which unfortunately cannot + * be done when recursing into submodules + */ + if (recurse_submodules) + max_prefix = NULL; + else + max_prefix = common_prefix(&pathspec); max_prefix_len = max_prefix ? strlen(max_prefix) : 0; /* Treat unmatching pathspec elements as errors */ diff --git a/builtin/merge-base.c b/builtin/merge-base.c index c0d1822eb3..b572a37c26 100644 --- a/builtin/merge-base.c +++ b/builtin/merge-base.c @@ -173,6 +173,9 @@ static int handle_fork_point(int argc, const char **argv) revs.initial = 1; for_each_reflog_ent(refname, collect_one_reflog_ent, &revs); + if (!revs.nr && !get_sha1(refname, sha1)) + add_one_commit(sha1, &revs); + for (i = 0; i < revs.nr; i++) revs.commit[i]->object.flags &= ~TMP_MARK; diff --git a/builtin/merge.c b/builtin/merge.c index 0ae099f746..a8b57c7d98 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -940,7 +940,7 @@ static void write_merge_state(struct commit_list *remoteheads) strbuf_reset(&buf); if (fast_forward == FF_NO) - strbuf_addf(&buf, "no-ff"); + strbuf_addstr(&buf, "no-ff"); write_file_buf(git_path_merge_mode(), buf.buf, buf.len); } diff --git a/builtin/mktree.c b/builtin/mktree.c index 4282b62c59..de9b40fc63 100644 --- a/builtin/mktree.c +++ b/builtin/mktree.c @@ -46,7 +46,7 @@ static void write_tree(unsigned char *sha1) size_t size; int i; - qsort(entries, used, sizeof(*entries), ent_compare); + QSORT(entries, used, ent_compare); for (size = i = 0; i < used; i++) size += 32 + entries[i]->len; diff --git a/builtin/mv.c b/builtin/mv.c index 446a316738..2f43877bc9 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -26,7 +26,7 @@ static const char **internal_copy_pathspec(const char *prefix, int i; const char **result; ALLOC_ARRAY(result, count + 1); - memcpy(result, pathspec, count * sizeof(const char *)); + COPY_ARRAY(result, pathspec, count); result[count] = NULL; for (i = 0; i < count; i++) { int length = strlen(result[i]); diff --git a/builtin/name-rev.c b/builtin/name-rev.c index 57be35faf5..cd89d48b65 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -195,8 +195,7 @@ static const char *get_exact_ref_match(const struct object *o) return NULL; if (!tip_table.sorted) { - qsort(tip_table.table, tip_table.nr, sizeof(*tip_table.table), - tipcmp); + QSORT(tip_table.table, tip_table.nr, tipcmp); tip_table.sorted = 1; } diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 166e52c700..1e7c2a98a5 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -23,6 +23,7 @@ #include "reachable.h" #include "sha1-array.h" #include "argv-array.h" +#include "mru.h" static const char *pack_usage[] = { N_("git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"), @@ -994,7 +995,7 @@ static int want_object_in_pack(const unsigned char *sha1, struct packed_git **found_pack, off_t *found_offset) { - struct packed_git *p; + struct mru_entry *entry; int want; if (!exclude && local && has_loose_object_nonlocal(sha1)) @@ -1011,7 +1012,8 @@ static int want_object_in_pack(const unsigned char *sha1, return want; } - for (p = packed_git; p; p = p->next) { + for (entry = packed_git_mru->head; entry; entry = entry->next) { + struct packed_git *p = entry->item; off_t offset; if (p == *found_pack) @@ -1027,6 +1029,8 @@ static int want_object_in_pack(const unsigned char *sha1, *found_pack = p; } want = want_found_object(exclude, p); + if (!exclude && want > 0) + mru_mark(packed_git_mru, entry); if (want != -1) return want; } @@ -1527,6 +1531,83 @@ static int pack_offset_sort(const void *_a, const void *_b) (a->in_pack_offset > b->in_pack_offset); } +/* + * Drop an on-disk delta we were planning to reuse. Naively, this would + * just involve blanking out the "delta" field, but we have to deal + * with some extra book-keeping: + * + * 1. Removing ourselves from the delta_sibling linked list. + * + * 2. Updating our size/type to the non-delta representation. These were + * either not recorded initially (size) or overwritten with the delta type + * (type) when check_object() decided to reuse the delta. + */ +static void drop_reused_delta(struct object_entry *entry) +{ + struct object_entry **p = &entry->delta->delta_child; + struct object_info oi = OBJECT_INFO_INIT; + + while (*p) { + if (*p == entry) + *p = (*p)->delta_sibling; + else + p = &(*p)->delta_sibling; + } + entry->delta = NULL; + + oi.sizep = &entry->size; + oi.typep = &entry->type; + if (packed_object_info(entry->in_pack, entry->in_pack_offset, &oi) < 0) { + /* + * We failed to get the info from this pack for some reason; + * fall back to sha1_object_info, which may find another copy. + * 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.sha1, &entry->size); + } +} + +/* + * Follow the chain of deltas from this entry onward, throwing away any links + * that cause us to hit a cycle (as determined by the DFS state flags in + * the entries). + */ +static void break_delta_chains(struct object_entry *entry) +{ + /* If it's not a delta, it can't be part of a cycle. */ + if (!entry->delta) { + entry->dfs_state = DFS_DONE; + return; + } + + switch (entry->dfs_state) { + case DFS_NONE: + /* + * This is the first time we've seen the object. We mark it as + * part of the active potential cycle and recurse. + */ + entry->dfs_state = DFS_ACTIVE; + break_delta_chains(entry->delta); + entry->dfs_state = DFS_DONE; + break; + + case DFS_DONE: + /* object already examined, and not part of a cycle */ + break; + + case DFS_ACTIVE: + /* + * We found a cycle that needs broken. It would be correct to + * break any link in the chain, but it's convenient to + * break this one. + */ + drop_reused_delta(entry); + entry->dfs_state = DFS_DONE; + break; + } +} + static void get_object_details(void) { uint32_t i; @@ -1535,7 +1616,7 @@ static void get_object_details(void) sorted_by_offset = xcalloc(to_pack.nr_objects, sizeof(struct object_entry *)); for (i = 0; i < to_pack.nr_objects; i++) sorted_by_offset[i] = to_pack.objects + i; - qsort(sorted_by_offset, to_pack.nr_objects, sizeof(*sorted_by_offset), pack_offset_sort); + QSORT(sorted_by_offset, to_pack.nr_objects, pack_offset_sort); for (i = 0; i < to_pack.nr_objects; i++) { struct object_entry *entry = sorted_by_offset[i]; @@ -1544,6 +1625,13 @@ static void get_object_details(void) entry->no_try_delta = 1; } + /* + * This must happen in a second pass, since we rely on the delta + * information for the whole list being completed. + */ + for (i = 0; i < to_pack.nr_objects; i++) + break_delta_chains(&to_pack.objects[i]); + free(sorted_by_offset); } @@ -2257,7 +2345,7 @@ static void prepare_pack(int window, int depth) if (progress) progress_state = start_progress(_("Compressing objects"), nr_deltas); - qsort(delta_list, n, sizeof(*delta_list), type_size_sort); + QSORT(delta_list, n, type_size_sort); ll_find_deltas(delta_list, n, window+1, depth, &nr_done); stop_progress(&progress_state); if (nr_done != nr_deltas) @@ -2449,8 +2537,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs) } if (in_pack.nr) { - qsort(in_pack.array, in_pack.nr, sizeof(in_pack.array[0]), - ofscmp); + QSORT(in_pack.array, in_pack.nr, ofscmp); for (i = 0; i < in_pack.nr; i++) { struct object *o = in_pack.array[i].object; add_object_entry(o->oid.hash, o->type, "", 0); diff --git a/builtin/pull.c b/builtin/pull.c index 398aae16c0..d6e46ee6d0 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -17,6 +17,7 @@ #include "revision.h" #include "tempfile.h" #include "lockfile.h" +#include "wt-status.h" enum rebase_type { REBASE_INVALID = -1, @@ -326,73 +327,6 @@ static int git_pull_config(const char *var, const char *value, void *cb) } /** - * Returns 1 if there are unstaged changes, 0 otherwise. - */ -static int has_unstaged_changes(const char *prefix) -{ - struct rev_info rev_info; - int result; - - init_revisions(&rev_info, prefix); - DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES); - DIFF_OPT_SET(&rev_info.diffopt, QUICK); - diff_setup_done(&rev_info.diffopt); - result = run_diff_files(&rev_info, 0); - return diff_result_code(&rev_info.diffopt, result); -} - -/** - * Returns 1 if there are uncommitted changes, 0 otherwise. - */ -static int has_uncommitted_changes(const char *prefix) -{ - struct rev_info rev_info; - int result; - - if (is_cache_unborn()) - return 0; - - init_revisions(&rev_info, prefix); - DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES); - DIFF_OPT_SET(&rev_info.diffopt, QUICK); - add_head_to_pending(&rev_info); - diff_setup_done(&rev_info.diffopt); - result = run_diff_index(&rev_info, 1); - return diff_result_code(&rev_info.diffopt, result); -} - -/** - * If the work tree has unstaged or uncommitted changes, dies with the - * appropriate message. - */ -static void die_on_unclean_work_tree(const char *prefix) -{ - struct lock_file *lock_file = xcalloc(1, sizeof(*lock_file)); - int do_die = 0; - - hold_locked_index(lock_file, 0); - refresh_cache(REFRESH_QUIET); - update_index_if_able(&the_index, lock_file); - rollback_lock_file(lock_file); - - if (has_unstaged_changes(prefix)) { - error(_("Cannot pull with rebase: You have unstaged changes.")); - do_die = 1; - } - - if (has_uncommitted_changes(prefix)) { - if (do_die) - error(_("Additionally, your index contains uncommitted changes.")); - else - error(_("Cannot pull with rebase: Your index contains uncommitted changes.")); - do_die = 1; - } - - if (do_die) - exit(1); -} - -/** * Appends merge candidates from FETCH_HEAD that are not marked not-for-merge * into merge_heads. */ @@ -875,7 +809,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix) die(_("Updating an unborn branch with changes added to the index.")); if (!autostash) - die_on_unclean_work_tree(prefix); + require_clean_work_tree(N_("pull with rebase"), + _("please commit or stash them."), 1, 0); if (get_rebase_fork_point(rebase_fork_point, repo, *refspecs)) hashclr(rebase_fork_point); diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index f7cd180252..04ed38e17d 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -20,6 +20,7 @@ #include "gpg-interface.h" #include "sigchain.h" #include "fsck.h" +#include "tmp-objdir.h" static const char * const receive_pack_usage[] = { N_("git receive-pack <git-dir>"), @@ -86,6 +87,8 @@ static enum { } use_keepalive; static int keepalive_in_sec = 5; +static struct tmp_objdir *tmp_objdir; + static enum deny_action parse_deny_action(const char *var, const char *value) { if (value) { @@ -664,6 +667,9 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, } else argv_array_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT"); + if (tmp_objdir) + argv_array_pushv(&proc.env_array, tmp_objdir_env(tmp_objdir)); + if (use_sideband) { memset(&muxer, 0, sizeof(muxer)); muxer.proc = copy_to_sideband; @@ -763,6 +769,7 @@ static int run_update_hook(struct command *cmd) proc.stdout_to_stderr = 1; proc.err = use_sideband ? -1 : 0; proc.argv = argv; + proc.env = tmp_objdir_env(tmp_objdir); code = start_command(&proc); if (code) @@ -834,6 +841,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si) !delayed_reachability_test(si, i)) sha1_array_append(&extra, si->shallow->sha1[i]); + opt.env = tmp_objdir_env(tmp_objdir); setup_alternate_shallow(&shallow_lock, &opt.shallow_file, &extra); if (check_connected(command_singleton_iterator, cmd, &opt)) { rollback_lock_file(&shallow_lock); @@ -1241,12 +1249,17 @@ static void set_connectivity_errors(struct command *commands, for (cmd = commands; cmd; cmd = cmd->next) { struct command *singleton = cmd; + struct check_connected_options opt = CHECK_CONNECTED_INIT; + if (shallow_update && si->shallow_ref[cmd->index]) /* to be checked in update_shallow_ref() */ continue; + + opt.env = tmp_objdir_env(tmp_objdir); if (!check_connected(command_singleton_iterator, &singleton, - NULL)) + &opt)) continue; + cmd->error_string = "missing necessary objects"; } } @@ -1429,6 +1442,7 @@ static void execute_commands(struct command *commands, data.si = si; opt.err_fd = err_fd; opt.progress = err_fd && !quiet; + opt.env = tmp_objdir_env(tmp_objdir); if (check_connected(iterate_receive_command_list, &data, &opt)) set_connectivity_errors(commands, si); @@ -1445,6 +1459,19 @@ static void execute_commands(struct command *commands, return; } + /* + * Now we'll start writing out refs, which means the objects need + * to be in their final positions so that other processes can see them. + */ + if (tmp_objdir_migrate(tmp_objdir) < 0) { + for (cmd = commands; cmd; cmd = cmd->next) { + if (!cmd->error_string) + cmd->error_string = "unable to migrate objects to permanent storage"; + } + return; + } + tmp_objdir = NULL; + check_aliased_updates(commands); free(head_name_to_free); @@ -1640,6 +1667,18 @@ static const char *unpack(int err_fd, struct shallow_info *si) argv_array_push(&child.args, alt_shallow_file); } + tmp_objdir = tmp_objdir_create(); + if (!tmp_objdir) + return "unable to create temporary object directory"; + child.env = tmp_objdir_env(tmp_objdir); + + /* + * Normally we just pass the tmp_objdir environment to the child + * processes that do the heavy lifting, but we may need to see these + * objects ourselves to set up shallow information. + */ + tmp_objdir_add_as_alternate(tmp_objdir); + if (ntohl(hdr.hdr_entries) < unpack_limit) { argv_array_pushl(&child.args, "unpack-objects", hdr_arg, NULL); if (quiet) diff --git a/builtin/remote.c b/builtin/remote.c index 9f6a6b3a9c..e52cf3925b 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -1197,8 +1197,7 @@ static int show(int argc, const char **argv) info.width = info.width2 = 0; for_each_string_list(&states.push, add_push_to_show_info, &info); - qsort(info.list->items, info.list->nr, - sizeof(*info.list->items), cmp_string_with_push); + QSORT(info.list->items, info.list->nr, cmp_string_with_push); if (info.list->nr) printf_ln(Q_(" Local ref configured for 'git push'%s:", " Local refs configured for 'git push'%s:", diff --git a/builtin/reset.c b/builtin/reset.c index 5aa86079d3..c04ac076dc 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -24,7 +24,7 @@ static const char * const git_reset_usage[] = { N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"), - N_("git reset [-q] <tree-ish> [--] <paths>..."), + N_("git reset [-q] [<tree-ish>] [--] <paths>..."), N_("git reset --patch [<tree-ish>] [--] [<paths>...]"), NULL }; diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 8479f6ed28..c43decda70 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -145,7 +145,7 @@ static void show_commit(struct commit *commit, void *data) */ if (buf.len && buf.buf[buf.len - 1] == '\n') graph_show_padding(revs->graph); - putchar('\n'); + putchar(info->hdr_termination); } else { /* * If the message buffer is empty, just show diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 17cbfabdde..cfb0f1510c 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -298,14 +298,30 @@ static int try_parent_shorthands(const char *arg) unsigned char sha1[20]; struct commit *commit; struct commit_list *parents; - int parents_only; - - if ((dotdot = strstr(arg, "^!"))) - parents_only = 0; - else if ((dotdot = strstr(arg, "^@"))) - parents_only = 1; - - if (!dotdot || dotdot[2]) + int parent_number; + int include_rev = 0; + int include_parents = 0; + int exclude_parent = 0; + + if ((dotdot = strstr(arg, "^!"))) { + include_rev = 1; + if (dotdot[2]) + return 0; + } else if ((dotdot = strstr(arg, "^@"))) { + include_parents = 1; + if (dotdot[2]) + return 0; + } else if ((dotdot = strstr(arg, "^-"))) { + include_rev = 1; + exclude_parent = 1; + + if (dotdot[2]) { + char *end; + exclude_parent = strtoul(dotdot + 2, &end, 10); + if (*end != '\0' || !exclude_parent) + return 0; + } + } else return 0; *dotdot = 0; @@ -314,12 +330,24 @@ static int try_parent_shorthands(const char *arg) return 0; } - if (!parents_only) - show_rev(NORMAL, sha1, arg); commit = lookup_commit_reference(sha1); - for (parents = commit->parents; parents; parents = parents->next) - show_rev(parents_only ? NORMAL : REVERSED, - parents->item->object.oid.hash, arg); + if (exclude_parent && + exclude_parent > commit_list_count(commit->parents)) { + *dotdot = '^'; + return 0; + } + + if (include_rev) + show_rev(NORMAL, sha1, arg); + for (parents = commit->parents, parent_number = 1; + parents; + parents = parents->next, parent_number++) { + if (exclude_parent && parent_number != exclude_parent) + continue; + + show_rev(include_parents ? NORMAL : REVERSED, + parents->item->object.oid.hash, arg); + } *dotdot = '^'; return 1; diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 25fa8a6aed..ba0e1154a9 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -308,7 +308,7 @@ void shortlog_output(struct shortlog *log) struct strbuf sb = STRBUF_INIT; if (log->sort_by_number) - qsort(log->list.items, log->list.nr, sizeof(struct string_list_item), + QSORT(log->list.items, log->list.nr, log->summary ? compare_by_counter : compare_by_list); for (i = 0; i < log->list.nr; i++) { const struct string_list_item *item = &log->list.items[i]; diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 623ca563a2..974f3403ab 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -353,8 +353,7 @@ static int compare_ref_name(const void *a_, const void *b_) static void sort_ref_range(int bottom, int top) { - qsort(ref_name + bottom, top - bottom, sizeof(ref_name[0]), - compare_ref_name); + QSORT(ref_name + bottom, top - bottom, compare_ref_name); } static int append_ref(const char *refname, const struct object_id *oid, @@ -540,8 +539,7 @@ static void append_one_rev(const char *av) if (saved_matches == ref_name_cnt && ref_name_cnt < MAX_REVS) error(_("no matching refs with %s"), av); - if (saved_matches + 1 < ref_name_cnt) - sort_ref_range(saved_matches, ref_name_cnt); + sort_ref_range(saved_matches, ref_name_cnt); return; } die("bad sha1 reference %s", av); diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 7b8ddfe6cf..6182eb3197 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -443,7 +443,8 @@ static int module_name(int argc, const char **argv, const char *prefix) } static int clone_submodule(const char *path, const char *gitdir, const char *url, - const char *depth, struct string_list *reference, int quiet) + const char *depth, struct string_list *reference, + int quiet, int progress) { struct child_process cp = CHILD_PROCESS_INIT; @@ -451,6 +452,8 @@ static int clone_submodule(const char *path, const char *gitdir, const char *url argv_array_push(&cp.args, "--no-checkout"); if (quiet) argv_array_push(&cp.args, "--quiet"); + if (progress) + argv_array_push(&cp.args, "--progress"); if (depth && *depth) argv_array_pushl(&cp.args, "--depth", depth, NULL); if (reference->nr) { @@ -489,20 +492,16 @@ static int add_possible_reference_from_superproject( { struct submodule_alternate_setup *sas = sas_cb; - /* directory name, minus trailing slash */ - size_t namelen = alt->name - alt->base - 1; - struct strbuf name = STRBUF_INIT; - strbuf_add(&name, alt->base, namelen); - /* * If the alternate object store is another repository, try the * standard layout with .git/modules/<name>/objects */ - if (ends_with(name.buf, ".git/objects")) { + if (ends_with(alt->path, ".git/objects")) { char *sm_alternate; struct strbuf sb = STRBUF_INIT; struct strbuf err = STRBUF_INIT; - strbuf_add(&sb, name.buf, name.len - strlen("objects")); + strbuf_add(&sb, alt->path, strlen(alt->path) - strlen("objects")); + /* * We need to end the new path with '/' to mark it as a dir, * otherwise a submodule name containing '/' will be broken @@ -530,7 +529,6 @@ static int add_possible_reference_from_superproject( strbuf_release(&sb); } - strbuf_release(&name); return 0; } @@ -575,6 +573,7 @@ static int module_clone(int argc, const char **argv, const char *prefix) { const char *name = NULL, *url = NULL, *depth = NULL; int quiet = 0; + int progress = 0; FILE *submodule_dot_git; char *p, *path = NULL, *sm_gitdir; struct strbuf rel_path = STRBUF_INIT; @@ -601,6 +600,8 @@ static int module_clone(int argc, const char **argv, const char *prefix) N_("string"), N_("depth for shallow clones")), OPT__QUIET(&quiet, "Suppress output for cloning a submodule"), + OPT_BOOL(0, "progress", &progress, + N_("force cloning progress")), OPT_END() }; @@ -634,7 +635,8 @@ static int module_clone(int argc, const char **argv, const char *prefix) prepare_possible_alternates(name, &reference); - if (clone_submodule(path, sm_gitdir, url, depth, &reference, quiet)) + if (clone_submodule(path, sm_gitdir, url, depth, &reference, + quiet, progress)) die(_("clone of '%s' into submodule path '%s' failed"), url, path); } else { @@ -684,6 +686,7 @@ struct submodule_update_clone { struct submodule_update_strategy update; /* configuration parameters which are passed on to the children */ + int progress; int quiet; int recommend_shallow; struct string_list references; @@ -702,7 +705,7 @@ struct submodule_update_clone { int failed_clones_nr, failed_clones_alloc; }; #define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \ - SUBMODULE_UPDATE_STRATEGY_INIT, 0, -1, STRING_LIST_INIT_DUP, \ + SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, \ NULL, NULL, NULL, \ STRING_LIST_INIT_DUP, 0, NULL, 0, 0} @@ -745,7 +748,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, if (suc->recursive_prefix) strbuf_addf(&sb, "%s/%s", suc->recursive_prefix, ce->name); else - strbuf_addf(&sb, "%s", ce->name); + strbuf_addstr(&sb, ce->name); strbuf_addf(out, _("Skipping unmerged submodule %s"), sb.buf); strbuf_addch(out, '\n'); goto cleanup; @@ -804,6 +807,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, child->err = -1; argv_array_push(&child->args, "submodule--helper"); argv_array_push(&child->args, "clone"); + if (suc->progress) + argv_array_push(&child->args, "--progress"); if (suc->quiet) argv_array_push(&child->args, "--quiet"); if (suc->prefix) @@ -860,8 +865,9 @@ static int update_clone_get_next_task(struct child_process *child, ce = suc->failed_clones[index]; if (!prepare_to_clone_next_submodule(ce, child, suc, err)) { suc->current ++; - strbuf_addf(err, "BUG: submodule considered for cloning," - "doesn't need cloning any more?\n"); + strbuf_addstr(err, "BUG: submodule considered for " + "cloning, doesn't need cloning " + "any more?\n"); return 0; } p = xmalloc(sizeof(*p)); @@ -950,6 +956,8 @@ static int update_clone(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow, N_("whether the initial clone should follow the shallow recommendation")), OPT__QUIET(&suc.quiet, N_("don't print cloning progress")), + OPT_BOOL(0, "progress", &suc.progress, + N_("force cloning progress")), OPT_END() }; diff --git a/builtin/update-index.c b/builtin/update-index.c index 73f6b3e1be..f3f07e7f1c 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -419,30 +419,18 @@ static int add_cacheinfo(unsigned int mode, const struct object_id *oid, return 0; } -static void chmod_path(int flip, const char *path) +static void chmod_path(char flip, const char *path) { int pos; struct cache_entry *ce; - unsigned int mode; pos = cache_name_pos(path, strlen(path)); if (pos < 0) goto fail; ce = active_cache[pos]; - mode = ce->ce_mode; - if (!S_ISREG(mode)) - goto fail; - switch (flip) { - case '+': - ce->ce_mode |= 0111; break; - case '-': - ce->ce_mode &= ~0111; break; - default: + if (chmod_cache_entry(ce, flip) < 0) goto fail; - } - cache_tree_invalidate_path(&the_index, path); - ce->ce_flags |= CE_UPDATE_IN_BASE; - active_cache_changed |= CE_ENTRY_CHANGED; + report("chmod %cx '%s'", flip, path); return; fail: diff --git a/builtin/worktree.c b/builtin/worktree.c index 6dcf7bd9d2..5c4854d3e4 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -528,6 +528,8 @@ int cmd_worktree(int ac, const char **av, const char *prefix) OPT_END() }; + git_config(git_default_config, NULL); + if (ac < 2) usage_with_options(worktree_usage, options); if (!prefix) |