diff options
Diffstat (limited to 'builtin')
37 files changed, 623 insertions, 253 deletions
diff --git a/builtin/add.c b/builtin/add.c index 773b7224a4..7d35307792 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -385,7 +385,8 @@ int cmd_add(int argc, char *ps_matched = NULL; struct lock_file lock_file = LOCK_INIT; - repo_config(repo, add_config, NULL); + if (repo) + repo_config(repo, add_config, NULL); argc = parse_options(argc, argv, prefix, builtin_add_options, builtin_add_usage, PARSE_OPT_KEEP_ARGV0); diff --git a/builtin/annotate.c b/builtin/annotate.c index a99179fe4d..7f754f2309 100644 --- a/builtin/annotate.c +++ b/builtin/annotate.c @@ -4,7 +4,6 @@ * Copyright (C) 2006 Ryan Anderson */ -#define USE_THE_REPOSITORY_VARIABLE #include "git-compat-util.h" #include "builtin.h" #include "strvec.h" @@ -12,16 +11,26 @@ int cmd_annotate(int argc, const char **argv, const char *prefix, - struct repository *repo UNUSED) + struct repository *repo) { struct strvec args = STRVEC_INIT; - int i; + const char **args_copy; + int ret; strvec_pushl(&args, "annotate", "-c", NULL); - - for (i = 1; i < argc; i++) { + for (int i = 1; i < argc; i++) strvec_push(&args, argv[i]); - } - return cmd_blame(args.nr, args.v, prefix, the_repository); + /* + * `cmd_blame()` ends up modifying the array, which causes memory leaks + * if we didn't copy the array here. + */ + CALLOC_ARRAY(args_copy, args.nr + 1); + COPY_ARRAY(args_copy, args.v, args.nr); + + ret = cmd_blame(args.nr, args_copy, prefix, repo); + + strvec_clear(&args); + free(args_copy); + return ret; } diff --git a/builtin/archive.c b/builtin/archive.c index dc926d1a3d..13ea7308c8 100644 --- a/builtin/archive.c +++ b/builtin/archive.c @@ -2,7 +2,6 @@ * Copyright (c) 2006 Franck Bui-Huu * Copyright (c) 2006 Rene Scharfe */ -#define USE_THE_REPOSITORY_VARIABLE #include "builtin.h" #include "archive.h" #include "gettext.h" @@ -79,7 +78,7 @@ static int run_remote_archiver(int argc, const char **argv, int cmd_archive(int argc, const char **argv, const char *prefix, - struct repository *repo UNUSED) + struct repository *repo) { const char *exec = "git-upload-archive"; char *output = NULL; @@ -110,7 +109,7 @@ int cmd_archive(int argc, setvbuf(stderr, NULL, _IOLBF, BUFSIZ); - ret = write_archive(argc, argv, prefix, the_repository, output, 0); + ret = write_archive(argc, argv, prefix, repo, output, 0); out: free(output); diff --git a/builtin/checkout.c b/builtin/checkout.c index 9c30000d3a..c449558e66 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -1716,7 +1716,7 @@ static struct option *add_common_switch_branch_options( N_("update ignored files (default)"), PARSE_OPT_NOCOMPLETE), OPT_BOOL(0, "ignore-other-worktrees", &opts->ignore_other_worktrees, - N_("do not check if another worktree is holding the given ref")), + N_("do not check if another worktree is using this branch")), OPT_END() }; struct option *newopts = parse_options_concat(prevopts, options); diff --git a/builtin/clone.c b/builtin/clone.c index e77339c847..c0013c75cd 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -147,8 +147,8 @@ static struct option builtin_clone_options[] = { 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, excluding rev")), + OPT_STRING_LIST(0, "shallow-exclude", &option_not, N_("ref"), + N_("deepen history of shallow clone, excluding ref")), OPT_BOOL(0, "single-branch", &option_single_branch, N_("clone only one branch, HEAD or --branch")), OPT_BOOL(0, "no-tags", &option_no_tags, @@ -1403,8 +1403,17 @@ int cmd_clone(int argc, * data from the --bundle-uri option. */ if (bundle_uri) { + struct remote_state *state; int has_heuristic = 0; + /* + * We need to save the remote state as our remote's lifetime is + * tied to it. + */ + state = the_repository->remote_state; + the_repository->remote_state = NULL; + repo_clear(the_repository); + /* At this point, we need the_repository to match the cloned repo. */ if (repo_init(the_repository, git_dir, work_tree)) warning(_("failed to initialize the repo, skipping bundle URI")); @@ -1413,6 +1422,10 @@ int cmd_clone(int argc, bundle_uri); else if (has_heuristic) git_config_set_gently("fetch.bundleuri", bundle_uri); + + remote_state_clear(the_repository->remote_state); + free(the_repository->remote_state); + the_repository->remote_state = state; } else { /* * Populate transport->got_remote_bundle_uri and @@ -1422,12 +1435,26 @@ int cmd_clone(int argc, if (transport->bundles && hashmap_get_size(&transport->bundles->bundles)) { + struct remote_state *state; + + /* + * We need to save the remote state as our remote's + * lifetime is tied to it. + */ + state = the_repository->remote_state; + the_repository->remote_state = NULL; + repo_clear(the_repository); + /* At this point, we need the_repository to match the cloned repo. */ if (repo_init(the_repository, git_dir, work_tree)) warning(_("failed to initialize the repo, skipping bundle URI")); else if (fetch_bundle_list(the_repository, transport->bundles)) warning(_("failed to fetch advertised bundles")); + + remote_state_clear(the_repository->remote_state); + free(the_repository->remote_state); + the_repository->remote_state = state; } else { clear_bundle_list(transport->bundles); FREE_AND_NULL(transport->bundles); diff --git a/builtin/commit.c b/builtin/commit.c index 8db4e9df0c..71d674138c 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -135,7 +135,7 @@ static struct strvec trailer_args = STRVEC_INIT; * is specified explicitly. */ static enum commit_msg_cleanup_mode cleanup_mode; -static char *cleanup_arg; +static char *cleanup_config; static enum commit_whence whence; static int use_editor = 1, include_status = 1; @@ -728,6 +728,13 @@ static void prepare_amend_commit(struct commit *commit, struct strbuf *sb, repo_unuse_commit_buffer(the_repository, commit, buffer); } +static void change_data_free(void *util, const char *str UNUSED) +{ + struct wt_status_change_data *d = util; + free(d->rename_source); + free(d); +} + static int prepare_to_commit(const char *index_file, const char *prefix, struct commit *current_head, struct wt_status *s, @@ -991,7 +998,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, s->use_color = 0; committable = run_status(s->fp, index_file, prefix, 1, s); s->use_color = saved_color_setting; - string_list_clear(&s->change, 1); + string_list_clear_func(&s->change, change_data_free); } else { struct object_id oid; const char *parent = "HEAD"; @@ -1380,8 +1387,6 @@ static int parse_and_validate_options(int argc, const char *argv[], if (0 <= edit_flag) use_editor = edit_flag; - cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor); - handle_untracked_files_arg(s); if (all && argc > 0) @@ -1629,8 +1634,10 @@ static int git_commit_config(const char *k, const char *v, include_status = git_config_bool(k, v); return 0; } - if (!strcmp(k, "commit.cleanup")) - return git_config_string(&cleanup_arg, k, v); + if (!strcmp(k, "commit.cleanup")) { + FREE_AND_NULL(cleanup_config); + return git_config_string(&cleanup_config, k, v); + } if (!strcmp(k, "commit.gpgsign")) { sign_commit = git_config_bool(k, v) ? "" : NULL; return 0; @@ -1651,6 +1658,7 @@ int cmd_commit(int argc, struct repository *repo UNUSED) { static struct wt_status s; + static const char *cleanup_arg = NULL; static struct option builtin_commit_options[] = { OPT__QUIET(&quiet, N_("suppress summary after successful commit")), OPT__VERBOSE(&verbose, N_("show diff in commit message template")), @@ -1750,6 +1758,12 @@ int cmd_commit(int argc, if (verbose == -1) verbose = (config_commit_verbose < 0) ? 0 : config_commit_verbose; + if (cleanup_arg) { + free(cleanup_config); + cleanup_config = xstrdup(cleanup_arg); + } + cleanup_mode = get_cleanup_mode(cleanup_config, use_editor); + if (dry_run) return dry_run_commit(argv, prefix, current_head, &s); index_file = prepare_index(argv, prefix, current_head, 0); diff --git a/builtin/config.c b/builtin/config.c index d8fd3def0e..cba7022108 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -19,7 +19,7 @@ static const char *const builtin_config_usage[] = { N_("git config list [<file-option>] [<display-option>] [--includes]"), N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"), N_("git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>"), - N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> <value>"), + N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"), N_("git config rename-section [<file-option>] <old-name> <new-name>"), N_("git config remove-section [<file-option>] <name>"), N_("git config edit [<file-option>]"), @@ -43,7 +43,7 @@ static const char *const builtin_config_set_usage[] = { }; static const char *const builtin_config_unset_usage[] = { - N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> <value>"), + N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"), NULL }; diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c index 5de8b9123b..7f733cb756 100644 --- a/builtin/credential-cache.c +++ b/builtin/credential-cache.c @@ -30,7 +30,7 @@ static int connection_fatally_broken(int error) static int connection_closed(int error) { - return (error == ECONNRESET); + return error == ECONNRESET || error == ECONNABORTED; } static int connection_fatally_broken(int error) @@ -189,7 +189,8 @@ int cmd_credential_cache(int argc, #else -int cmd_credential_cache(int argc, const char **argv, const char *prefix) +int cmd_credential_cache(int argc, const char **argv, const char *prefix, + struct repository *repo UNUSED) { const char * const usage[] = { "git credential-cache [options] <action>", diff --git a/builtin/difftool.c b/builtin/difftool.c index 4b416743ff..40e971e225 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -340,7 +340,7 @@ static void write_file_in_directory(struct strbuf *dir, size_t dir_len, /* Write the file contents for the left and right sides of the difftool * dir-diff representation for submodules and symlinks. Symlinks and submodules * are written as regular text files so that external diff tools can diff them - * as text files, resulting in behavior that is analogous to to what "git diff" + * as text files, resulting in behavior that is analogous to what "git diff" * displays for symlink and submodule diffs. */ static void write_standin_files(struct pair_entry *entry, @@ -376,7 +376,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, struct checkout lstate, rstate; int err = 0; struct child_process cmd = CHILD_PROCESS_INIT; - struct hashmap wt_modified, tmp_modified; + struct hashmap wt_modified = HASHMAP_INIT(path_entry_cmp, NULL); + struct hashmap tmp_modified = HASHMAP_INIT(path_entry_cmp, NULL); int indices_loaded = 0; workdir = repo_get_work_tree(the_repository); @@ -601,9 +602,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, * in the common case of --symlinks and the difftool updating * files through the symlink. */ - hashmap_init(&wt_modified, path_entry_cmp, NULL, wtindex.cache_nr); - hashmap_init(&tmp_modified, path_entry_cmp, NULL, wtindex.cache_nr); - for (i = 0; i < wtindex.cache_nr; i++) { struct hashmap_entry dummy; const char *name = wtindex.cache[i]->name; @@ -662,6 +660,12 @@ finish: if (fp) fclose(fp); + hashmap_clear_and_free(&working_tree_dups, struct working_tree_entry, entry); + hashmap_clear_and_free(&wt_modified, struct path_entry, entry); + hashmap_clear_and_free(&tmp_modified, struct path_entry, entry); + hashmap_clear_and_free(&submodules, struct pair_entry, entry); + hashmap_clear_and_free(&symlinks2, struct pair_entry, entry); + release_index(&wtindex); free(lbase_dir); free(rbase_dir); strbuf_release(&info); diff --git a/builtin/fast-import.c b/builtin/fast-import.c index 1e7ab67f6e..51c8228cb7 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -179,6 +179,7 @@ static unsigned long branch_load_count; static int failure; static FILE *pack_edges; static unsigned int show_stats = 1; +static unsigned int quiet; static int global_argc; static const char **global_argv; static const char *global_prefix; @@ -966,8 +967,7 @@ static int store_object( if (e->idx.offset) { duplicate_count_by_type[type]++; return 1; - } else if (find_sha1_pack(oid.hash, - get_all_packs(the_repository))) { + } else if (find_oid_pack(&oid, get_all_packs(the_repository))) { e->type = type; e->pack_id = MAX_PACK_ID; e->idx.offset = 1; /* just not zero! */ @@ -1167,8 +1167,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark) duplicate_count_by_type[OBJ_BLOB]++; truncate_pack(&checkpoint); - } else if (find_sha1_pack(oid.hash, - get_all_packs(the_repository))) { + } else if (find_oid_pack(&oid, get_all_packs(the_repository))) { e->type = OBJ_BLOB; e->pack_id = MAX_PACK_ID; e->idx.offset = 1; /* just not zero! */ @@ -1604,7 +1603,19 @@ static int update_branch(struct branch *b) struct ref_transaction *transaction; struct object_id old_oid; struct strbuf err = STRBUF_INIT; - + static const char *replace_prefix = "refs/replace/"; + + if (starts_with(b->name, replace_prefix) && + !strcmp(b->name + strlen(replace_prefix), + oid_to_hex(&b->oid))) { + if (!quiet) + warning("Dropping %s since it would point to " + "itself (i.e. to %s)", + b->name, oid_to_hex(&b->oid)); + refs_delete_ref(get_main_ref_store(the_repository), + NULL, b->name, NULL, 0); + return 0; + } if (is_null_oid(&b->oid)) { if (b->delete) refs_delete_ref(get_main_ref_store(the_repository), @@ -3390,6 +3401,7 @@ static int parse_one_option(const char *option) option_export_pack_edges(option); } else if (!strcmp(option, "quiet")) { show_stats = 0; + quiet = 1; } else if (!strcmp(option, "stats")) { show_stats = 1; } else if (!strcmp(option, "allow-unsafe-features")) { diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index 49222a36fa..62e8c3aa6b 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -53,6 +53,7 @@ int cmd_fetch_pack(int argc, struct ref *fetched_refs = NULL, *remote_refs = NULL; const char *dest = NULL; struct ref **sought = NULL; + struct ref **sought_to_free = NULL; int nr_sought = 0, alloc_sought = 0; int fd[2]; struct string_list pack_lockfiles = STRING_LIST_INIT_DUP; @@ -243,6 +244,13 @@ int cmd_fetch_pack(int argc, BUG("unknown protocol version"); } + /* + * Create a shallow copy of `sought` so that we can free all of its entries. + * This is because `fetch_pack()` will modify the array to evict some + * entries, but won't free those. + */ + DUP_ARRAY(sought_to_free, sought, nr_sought); + fetched_refs = fetch_pack(&args, fd, remote_refs, sought, nr_sought, &shallow, pack_lockfiles_ptr, version); @@ -280,9 +288,13 @@ int cmd_fetch_pack(int argc, oid_to_hex(&ref->old_oid), ref->name); for (size_t i = 0; i < nr_sought; i++) - free_one_ref(sought[i]); + free_one_ref(sought_to_free[i]); + free(sought_to_free); free(sought); free_refs(fetched_refs); free_refs(remote_refs); + list_objects_filter_release(&args.filter_options); + oid_array_clear(&shallow); + string_list_clear(&pack_lockfiles, 0); return ret; } diff --git a/builtin/fetch.c b/builtin/fetch.c index a64de4485f..2f416cf867 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -454,13 +454,10 @@ static void filter_prefetch_refspec(struct refspec *rs) ref_namespace[NAMESPACE_TAGS].ref))) { int j; - free(rs->items[i].src); - free(rs->items[i].dst); + refspec_item_clear(&rs->items[i]); - for (j = i + 1; j < rs->nr; j++) { + for (j = i + 1; j < rs->nr; j++) rs->items[j - 1] = rs->items[j]; - rs->raw[j - 1] = rs->raw[j]; - } rs->nr--; i--; continue; @@ -2054,6 +2051,8 @@ static int fetch_multiple(struct string_list *list, int max_children, strvec_pushl(&argv, "-c", "fetch.bundleURI=", "fetch", "--append", "--no-auto-gc", "--no-write-commit-graph", NULL); + for (i = 0; i < server_options.nr; i++) + strvec_pushf(&argv, "--server-option=%s", server_options.items[i].string); add_options_to_argv(&argv, config); if (max_children != 1 && list->nr != 1) { @@ -2287,8 +2286,8 @@ int cmd_fetch(int argc, 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, excluding rev")), + OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("ref"), + N_("deepen history of shallow clone, excluding ref")), OPT_INTEGER(0, "deepen", &deepen_relative, N_("deepen history of shallow clone")), OPT_SET_INT_F(0, "unshallow", &unshallow, diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index dce8a3b248..f3f6bd330b 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -1208,9 +1208,9 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state) * system event listener thread so that we have the IPC handle * before we need it. */ - if (ipc_server_run_async(&state->ipc_server_data, - state->path_ipc.buf, &ipc_opts, - handle_client, state)) + if (ipc_server_init_async(&state->ipc_server_data, + state->path_ipc.buf, &ipc_opts, + handle_client, state)) return error_errno( _("could not start IPC thread pool on '%s'"), state->path_ipc.buf); @@ -1314,6 +1314,7 @@ static int fsmonitor_run_daemon(void) strbuf_reset(&state.path_gitdir_watch); strbuf_addstr(&state.path_gitdir_watch, absolute_path(repo_get_git_dir(the_repository))); + strbuf_strip_suffix(&state.path_gitdir_watch, "/."); state.nr_paths_watching = 2; } diff --git a/builtin/gc.c b/builtin/gc.c index 7da6d1966b..d52735354c 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -1478,9 +1478,9 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts, static void initialize_maintenance_strategy(void) { - char *config_str; + const char *config_str; - if (git_config_get_string("maintenance.strategy", &config_str)) + if (git_config_get_string_tmp("maintenance.strategy", &config_str)) return; if (!strcasecmp(config_str, "incremental")) { @@ -1818,39 +1818,43 @@ static const char *get_extra_launchctl_strings(void) { * * If $GIT_TEST_MAINT_SCHEDULER is set, return true. * In this case, the *cmd value is read as input. * - * * if the input value *cmd is the key of one of the comma-separated list - * item, then *is_available is set to true and *cmd is modified and becomes + * * if the input value cmd is the key of one of the comma-separated list + * item, then *is_available is set to true and *out is set to * the mock command. * * * if the input value *cmd isn’t the key of any of the comma-separated list - * item, then *is_available is set to false. + * item, then *is_available is set to false and *out is set to the original + * command. * * Ex.: * GIT_TEST_MAINT_SCHEDULER not set * +-------+-------------------------------------------------+ * | Input | Output | - * | *cmd | return code | *cmd | *is_available | + * | *cmd | return code | *out | *is_available | * +-------+-------------+-------------------+---------------+ - * | "foo" | false | "foo" (unchanged) | (unchanged) | + * | "foo" | false | "foo" (allocated) | (unchanged) | * +-------+-------------+-------------------+---------------+ * * GIT_TEST_MAINT_SCHEDULER set to “foo:./mock_foo.sh,bar:./mock_bar.sh” * +-------+-------------------------------------------------+ * | Input | Output | - * | *cmd | return code | *cmd | *is_available | + * | *cmd | return code | *out | *is_available | * +-------+-------------+-------------------+---------------+ * | "foo" | true | "./mock.foo.sh" | true | - * | "qux" | true | "qux" (unchanged) | false | + * | "qux" | true | "qux" (allocated) | false | * +-------+-------------+-------------------+---------------+ */ -static int get_schedule_cmd(const char **cmd, int *is_available) +static int get_schedule_cmd(const char *cmd, int *is_available, char **out) { char *testing = xstrdup_or_null(getenv("GIT_TEST_MAINT_SCHEDULER")); struct string_list_item *item; struct string_list list = STRING_LIST_INIT_NODUP; - if (!testing) + if (!testing) { + if (out) + *out = xstrdup(cmd); return 0; + } if (is_available) *is_available = 0; @@ -1862,16 +1866,22 @@ static int get_schedule_cmd(const char **cmd, int *is_available) if (string_list_split_in_place(&pair, item->string, ":", 2) != 2) continue; - if (!strcmp(*cmd, pair.items[0].string)) { - *cmd = pair.items[1].string; + if (!strcmp(cmd, pair.items[0].string)) { + if (out) + *out = xstrdup(pair.items[1].string); if (is_available) *is_available = 1; - string_list_clear(&list, 0); - UNLEAK(testing); - return 1; + string_list_clear(&pair, 0); + goto out; } + + string_list_clear(&pair, 0); } + if (out) + *out = xstrdup(cmd); + +out: string_list_clear(&list, 0); free(testing); return 1; @@ -1888,9 +1898,8 @@ static int get_random_minute(void) static int is_launchctl_available(void) { - const char *cmd = "launchctl"; int is_available; - if (get_schedule_cmd(&cmd, &is_available)) + if (get_schedule_cmd("launchctl", &is_available, NULL)) return is_available; #ifdef __APPLE__ @@ -1928,12 +1937,12 @@ static char *launchctl_get_uid(void) static int launchctl_boot_plist(int enable, const char *filename) { - const char *cmd = "launchctl"; + char *cmd; int result; struct child_process child = CHILD_PROCESS_INIT; char *uid = launchctl_get_uid(); - get_schedule_cmd(&cmd, NULL); + get_schedule_cmd("launchctl", NULL, &cmd); strvec_split(&child.args, cmd); strvec_pushl(&child.args, enable ? "bootstrap" : "bootout", uid, filename, NULL); @@ -1946,6 +1955,7 @@ static int launchctl_boot_plist(int enable, const char *filename) result = finish_command(&child); + free(cmd); free(uid); return result; } @@ -1997,10 +2007,10 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit static unsigned long lock_file_timeout_ms = ULONG_MAX; struct strbuf plist = STRBUF_INIT, plist2 = STRBUF_INIT; struct stat st; - const char *cmd = "launchctl"; + char *cmd; int minute = get_random_minute(); - get_schedule_cmd(&cmd, NULL); + get_schedule_cmd("launchctl", NULL, &cmd); preamble = "<?xml version=\"1.0\"?>\n" "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" "<plist version=\"1.0\">" @@ -2092,6 +2102,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit free(filename); free(name); + free(cmd); strbuf_release(&plist); strbuf_release(&plist2); return 0; @@ -2116,9 +2127,8 @@ static int launchctl_update_schedule(int run_maintenance, int fd UNUSED) static int is_schtasks_available(void) { - const char *cmd = "schtasks"; int is_available; - if (get_schedule_cmd(&cmd, &is_available)) + if (get_schedule_cmd("schtasks", &is_available, NULL)) return is_available; #ifdef GIT_WINDOWS_NATIVE @@ -2137,15 +2147,16 @@ static char *schtasks_task_name(const char *frequency) static int schtasks_remove_task(enum schedule_priority schedule) { - const char *cmd = "schtasks"; + char *cmd; struct child_process child = CHILD_PROCESS_INIT; const char *frequency = get_frequency(schedule); char *name = schtasks_task_name(frequency); - get_schedule_cmd(&cmd, NULL); + get_schedule_cmd("schtasks", NULL, &cmd); strvec_split(&child.args, cmd); strvec_pushl(&child.args, "/delete", "/tn", name, "/f", NULL); free(name); + free(cmd); return run_command(&child); } @@ -2159,7 +2170,7 @@ static int schtasks_remove_tasks(void) static int schtasks_schedule_task(const char *exec_path, enum schedule_priority schedule) { - const char *cmd = "schtasks"; + char *cmd; int result; struct child_process child = CHILD_PROCESS_INIT; const char *xml; @@ -2169,7 +2180,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority struct strbuf tfilename = STRBUF_INIT; int minute = get_random_minute(); - get_schedule_cmd(&cmd, NULL); + get_schedule_cmd("schtasks", NULL, &cmd); strbuf_addf(&tfilename, "%s/schedule_%s_XXXXXX", repo_get_common_dir(the_repository), frequency); @@ -2276,6 +2287,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority delete_tempfile(&tfile); free(name); + free(cmd); return result; } @@ -2317,21 +2329,28 @@ static int check_crontab_process(const char *cmd) static int is_crontab_available(void) { - const char *cmd = "crontab"; + char *cmd; int is_available; + int ret; - if (get_schedule_cmd(&cmd, &is_available)) - return is_available; + if (get_schedule_cmd("crontab", &is_available, &cmd)) { + ret = is_available; + goto out; + } #ifdef __APPLE__ /* * macOS has cron, but it requires special permissions and will * create a UI alert when attempting to run this command. */ - return 0; + ret = 0; #else - return check_crontab_process(cmd); + ret = check_crontab_process(cmd); #endif + +out: + free(cmd); + return ret; } #define BEGIN_LINE "# BEGIN GIT MAINTENANCE SCHEDULE" @@ -2339,7 +2358,7 @@ static int is_crontab_available(void) static int crontab_update_schedule(int run_maintenance, int fd) { - const char *cmd = "crontab"; + char *cmd; int result = 0; int in_old_region = 0; struct child_process crontab_list = CHILD_PROCESS_INIT; @@ -2349,15 +2368,17 @@ static int crontab_update_schedule(int run_maintenance, int fd) struct tempfile *tmpedit = NULL; int minute = get_random_minute(); - get_schedule_cmd(&cmd, NULL); + get_schedule_cmd("crontab", NULL, &cmd); strvec_split(&crontab_list.args, cmd); strvec_push(&crontab_list.args, "-l"); crontab_list.in = -1; crontab_list.out = dup(fd); crontab_list.git_cmd = 0; - if (start_command(&crontab_list)) - return error(_("failed to run 'crontab -l'; your system might not support 'cron'")); + if (start_command(&crontab_list)) { + result = error(_("failed to run 'crontab -l'; your system might not support 'cron'")); + goto out; + } /* Ignore exit code, as an empty crontab will return error. */ finish_command(&crontab_list); @@ -2427,8 +2448,10 @@ static int crontab_update_schedule(int run_maintenance, int fd) result = error(_("'crontab' died")); else fclose(cron_list); + out: delete_tempfile(&tmpedit); + free(cmd); return result; } @@ -2451,10 +2474,9 @@ static int real_is_systemd_timer_available(void) static int is_systemd_timer_available(void) { - const char *cmd = "systemctl"; int is_available; - if (get_schedule_cmd(&cmd, &is_available)) + if (get_schedule_cmd("systemctl", &is_available, NULL)) return is_available; return real_is_systemd_timer_available(); @@ -2635,9 +2657,10 @@ static int systemd_timer_enable_unit(int enable, enum schedule_priority schedule, int minute) { - const char *cmd = "systemctl"; + char *cmd = NULL; struct child_process child = CHILD_PROCESS_INIT; const char *frequency = get_frequency(schedule); + int ret; /* * Disabling the systemd unit while it is already disabled makes @@ -2648,20 +2671,25 @@ static int systemd_timer_enable_unit(int enable, * On the other hand, enabling a systemd unit which is already enabled * produces no error. */ - if (!enable) + if (!enable) { child.no_stderr = 1; - else if (systemd_timer_write_timer_file(schedule, minute)) - return -1; + } else if (systemd_timer_write_timer_file(schedule, minute)) { + ret = -1; + goto out; + } - get_schedule_cmd(&cmd, NULL); + get_schedule_cmd("systemctl", NULL, &cmd); strvec_split(&child.args, cmd); strvec_pushl(&child.args, "--user", enable ? "enable" : "disable", "--now", NULL); strvec_pushf(&child.args, SYSTEMD_UNIT_FORMAT, frequency, "timer"); - if (start_command(&child)) - return error(_("failed to start systemctl")); - if (finish_command(&child)) + if (start_command(&child)) { + ret = error(_("failed to start systemctl")); + goto out; + } + + if (finish_command(&child)) { /* * Disabling an already disabled systemd unit makes * systemctl fail. @@ -2669,9 +2697,17 @@ static int systemd_timer_enable_unit(int enable, * * Enabling an enabled systemd unit doesn't fail. */ - if (enable) - return error(_("failed to run systemctl")); - return 0; + if (enable) { + ret = error(_("failed to run systemctl")); + goto out; + } + } + + ret = 0; + +out: + free(cmd); + return ret; } /* diff --git a/builtin/grep.c b/builtin/grep.c index f17d46a06e..98b85c7fca 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -906,6 +906,7 @@ int cmd_grep(int argc, int dummy; int use_index = 1; int allow_revs; + int ret; struct option options[] = { OPT_BOOL(0, "cached", &cached, @@ -1172,8 +1173,10 @@ int cmd_grep(int argc, * Optimize out the case where the amount of matches is limited to zero. * We do this to keep results consistent with GNU grep(1). */ - if (opt.max_count == 0) - return 1; + if (opt.max_count == 0) { + ret = 1; + goto out; + } if (show_in_pager) { if (num_threads > 1) @@ -1267,10 +1270,14 @@ int cmd_grep(int argc, hit |= wait_all(); if (hit && show_in_pager) run_pager(&opt, prefix); + + ret = !hit; + +out: clear_pathspec(&pathspec); string_list_clear(&path_list, 0); free_grep_patterns(&opt); object_array_clear(&list); free_repos(); - return !hit; + return ret; } diff --git a/builtin/help.c b/builtin/help.c index a509241a80..4a5a079070 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -54,7 +54,7 @@ static enum help_action { HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION, } cmd_mode; -static const char *html_path; +static char *html_path; static int verbose = 1; static enum help_format help_format = HELP_FORMAT_NONE; static int exclude_guides; @@ -411,6 +411,7 @@ static int git_help_config(const char *var, const char *value, if (!strcmp(var, "help.htmlpath")) { if (!value) return config_error_nonbool(var); + free(html_path); html_path = xstrdup(value); return 0; } @@ -515,23 +516,24 @@ static void show_info_page(const char *page) static void get_html_page_path(struct strbuf *page_path, const char *page) { struct stat st; + const char *path = html_path; char *to_free = NULL; - if (!html_path) - html_path = to_free = system_path(GIT_HTML_PATH); + if (!path) + path = to_free = system_path(GIT_HTML_PATH); /* * Check that the page we're looking for exists. */ - if (!strstr(html_path, "://")) { - if (stat(mkpath("%s/%s.html", html_path, page), &st) + if (!strstr(path, "://")) { + if (stat(mkpath("%s/%s.html", path, page), &st) || !S_ISREG(st.st_mode)) die("'%s/%s.html': documentation file not found.", - html_path, page); + path, page); } strbuf_init(page_path, 0); - strbuf_addf(page_path, "%s/%s.html", html_path, page); + strbuf_addf(page_path, "%s/%s.html", path, page); free(to_free); } diff --git a/builtin/index-pack.c b/builtin/index-pack.c index e228c56ff2..95babdc5ea 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -9,6 +9,7 @@ #include "csum-file.h" #include "blob.h" #include "commit.h" +#include "tag.h" #include "tree.h" #include "progress.h" #include "fsck.h" @@ -20,9 +21,14 @@ #include "object-file.h" #include "object-store-ll.h" #include "oid-array.h" +#include "oidset.h" +#include "path.h" #include "replace-object.h" +#include "tree-walk.h" #include "promisor-remote.h" +#include "run-command.h" #include "setup.h" +#include "strvec.h" static const char index_pack_usage[] = "git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--[no-]rev-index] [--verify] [--strict[=<msg-id>=<severity>...]] [--fsck-objects[=<msg-id>=<severity>...]] (<pack-file> | --stdin [--fix-thin] [<pack-file>])"; @@ -94,7 +100,7 @@ static LIST_HEAD(done_head); static size_t base_cache_used; static size_t base_cache_limit; -struct thread_local { +struct thread_local_data { pthread_t thread; int pack_fd; }; @@ -117,7 +123,7 @@ static struct object_entry *objects; static struct object_stat *obj_stat; static struct ofs_delta_entry *ofs_deltas; static struct ref_delta_entry *ref_deltas; -static struct thread_local nothread_data; +static struct thread_local_data nothread_data; static int nr_objects; static int nr_ofs_deltas; static int nr_ref_deltas; @@ -148,7 +154,14 @@ static uint32_t input_crc32; static int input_fd, output_fd; static const char *curr_pack; -static struct thread_local *thread_data; +/* + * local_links is guarded by read_mutex, and record_local_links is read-only in + * a thread. + */ +static struct oidset local_links = OIDSET_INIT; +static int record_local_links; + +static struct thread_local_data *thread_data; static int nr_dispatched; static int threads_active; @@ -390,7 +403,7 @@ static NORETURN void bad_object(off_t offset, const char *format, ...) (uintmax_t)offset, buf); } -static inline struct thread_local *get_thread_data(void) +static inline struct thread_local_data *get_thread_data(void) { if (HAVE_THREADS) { if (threads_active) @@ -401,7 +414,7 @@ static inline struct thread_local *get_thread_data(void) return ¬hread_data; } -static void set_thread_data(struct thread_local *data) +static void set_thread_data(struct thread_local_data *data) { if (threads_active) pthread_setspecific(key, data); @@ -799,6 +812,44 @@ static int check_collison(struct object_entry *entry) return 0; } +static void record_if_local_object(const struct object_id *oid) +{ + struct object_info info = OBJECT_INFO_INIT; + if (oid_object_info_extended(the_repository, oid, &info, 0)) + /* Missing; assume it is a promisor object */ + return; + if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor) + return; + oidset_insert(&local_links, oid); +} + +static void do_record_local_links(struct object *obj) +{ + if (obj->type == OBJ_TREE) { + struct tree *tree = (struct tree *)obj; + struct tree_desc desc; + struct name_entry entry; + if (init_tree_desc_gently(&desc, &tree->object.oid, + tree->buffer, tree->size, 0)) + /* + * Error messages are given when packs are + * verified, so do not print any here. + */ + return; + while (tree_entry_gently(&desc, &entry)) + record_if_local_object(&entry.oid); + } else if (obj->type == OBJ_COMMIT) { + struct commit *commit = (struct commit *) obj; + struct commit_list *parents = commit->parents; + + for (; parents; parents = parents->next) + record_if_local_object(&parents->item->object.oid); + } else if (obj->type == OBJ_TAG) { + struct tag *tag = (struct tag *) obj; + record_if_local_object(get_tagged_oid(tag)); + } +} + static void sha1_object(const void *data, struct object_entry *obj_entry, unsigned long size, enum object_type type, const struct object_id *oid) @@ -845,7 +896,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, free(has_data); } - if (strict || do_fsck_object) { + if (strict || do_fsck_object || record_local_links) { read_lock(); if (type == OBJ_BLOB) { struct blob *blob = lookup_blob(the_repository, oid); @@ -877,6 +928,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, die(_("fsck error in packed object")); if (strict && fsck_walk(obj, NULL, &fsck_options)) die(_("Not all child objects of %s are reachable"), oid_to_hex(&obj->oid)); + if (record_local_links) + do_record_local_links(obj); if (obj->type == OBJ_TREE) { struct tree *item = (struct tree *) obj; @@ -1505,7 +1558,7 @@ static void rename_tmp_packfile(const char **final_name, struct strbuf *name, unsigned char *hash, const char *ext, int make_read_only_if_same) { - if (*final_name != curr_name) { + if (!*final_name || strcmp(*final_name, curr_name)) { if (!*final_name) *final_name = odb_pack_name(name, hash, ext); if (finalize_object_file(curr_name, *final_name)) @@ -1719,6 +1772,58 @@ static void show_pack_info(int stat_only) free(chain_histogram); } +static void repack_local_links(void) +{ + struct child_process cmd = CHILD_PROCESS_INIT; + FILE *out; + struct strbuf line = STRBUF_INIT; + struct oidset_iter iter; + struct object_id *oid; + char *base_name; + + if (!oidset_size(&local_links)) + return; + + base_name = mkpathdup("%s/pack/pack", repo_get_object_directory(the_repository)); + + strvec_push(&cmd.args, "pack-objects"); + strvec_push(&cmd.args, "--exclude-promisor-objects-best-effort"); + strvec_push(&cmd.args, base_name); + cmd.git_cmd = 1; + cmd.in = -1; + cmd.out = -1; + if (start_command(&cmd)) + die(_("could not start pack-objects to repack local links")); + + oidset_iter_init(&local_links, &iter); + while ((oid = oidset_iter_next(&iter))) { + if (write_in_full(cmd.in, oid_to_hex(oid), the_hash_algo->hexsz) < 0 || + write_in_full(cmd.in, "\n", 1) < 0) + die(_("failed to feed local object to pack-objects")); + } + close(cmd.in); + + out = xfdopen(cmd.out, "r"); + while (strbuf_getline_lf(&line, out) != EOF) { + unsigned char binary[GIT_MAX_RAWSZ]; + if (line.len != the_hash_algo->hexsz || + !hex_to_bytes(binary, line.buf, line.len)) + die(_("index-pack: Expecting full hex object ID lines only from pack-objects.")); + + /* + * pack-objects creates the .pack and .idx files, but not the + * .promisor file. Create the .promisor file, which is empty. + */ + write_special_file("promisor", "", NULL, binary, NULL); + } + + fclose(out); + if (finish_command(&cmd)) + die(_("could not finish pack-objects to repack local links")); + strbuf_release(&line); + free(base_name); +} + int cmd_index_pack(int argc, const char **argv, const char *prefix, @@ -1726,7 +1831,7 @@ int cmd_index_pack(int argc, { int i, fix_thin_pack = 0, verify = 0, stat_only = 0, rev_index; const char *curr_index; - const char *curr_rev_index = NULL; + char *curr_rev_index = NULL; const char *index_name = NULL, *pack_name = NULL, *rev_index_name = NULL; const char *keep_msg = NULL; const char *promisor_msg = NULL; @@ -1794,7 +1899,7 @@ int cmd_index_pack(int argc, } else if (skip_to_optional_arg(arg, "--keep", &keep_msg)) { ; /* nothing to do */ } else if (skip_to_optional_arg(arg, "--promisor", &promisor_msg)) { - ; /* already parsed */ + record_local_links = 1; } else if (starts_with(arg, "--threads=")) { char *end; nr_threads = strtoul(arg+10, &end, 0); @@ -1865,6 +1970,8 @@ int cmd_index_pack(int argc, usage(index_pack_usage); if (fix_thin_pack && !from_stdin) die(_("the option '%s' requires '%s'"), "--fix-thin", "--stdin"); + if (promisor_msg && pack_name) + die(_("--promisor cannot be used with a pack name")); if (from_stdin && !startup_info->have_repository) die(_("--stdin requires a git repository")); if (from_stdin && hash_algo) @@ -1968,8 +2075,9 @@ int cmd_index_pack(int argc, free((void *) curr_pack); if (!index_name) free((void *) curr_index); - if (!rev_index_name) - free((void *) curr_rev_index); + free(curr_rev_index); + + repack_local_links(); /* * Let the caller know this pack is not self contained diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c index c5e56e2cd3..44d8ccddc9 100644 --- a/builtin/interpret-trailers.c +++ b/builtin/interpret-trailers.c @@ -141,8 +141,8 @@ static void interpret_trailers(const struct process_trailer_options *opts, { LIST_HEAD(head); struct strbuf sb = STRBUF_INIT; - struct strbuf trailer_block = STRBUF_INIT; - struct trailer_info *info; + struct strbuf trailer_block_sb = STRBUF_INIT; + struct trailer_block *trailer_block; FILE *outfile = stdout; trailer_config_init(); @@ -152,13 +152,13 @@ static void interpret_trailers(const struct process_trailer_options *opts, if (opts->in_place) outfile = create_in_place_tempfile(file); - info = parse_trailers(opts, sb.buf, &head); + trailer_block = parse_trailers(opts, sb.buf, &head); - /* Print the lines before the trailers */ + /* Print the lines before the trailer block */ if (!opts->only_trailers) - fwrite(sb.buf, 1, trailer_block_start(info), outfile); + fwrite(sb.buf, 1, trailer_block_start(trailer_block), outfile); - if (!opts->only_trailers && !blank_line_before_trailer_block(info)) + if (!opts->only_trailers && !blank_line_before_trailer_block(trailer_block)) fprintf(outfile, "\n"); @@ -172,15 +172,16 @@ static void interpret_trailers(const struct process_trailer_options *opts, } /* Print trailer block. */ - format_trailers(opts, &head, &trailer_block); + format_trailers(opts, &head, &trailer_block_sb); free_trailers(&head); - fwrite(trailer_block.buf, 1, trailer_block.len, outfile); - strbuf_release(&trailer_block); + fwrite(trailer_block_sb.buf, 1, trailer_block_sb.len, outfile); + strbuf_release(&trailer_block_sb); - /* Print the lines after the trailers as is */ + /* Print the lines after the trailer block as is. */ if (!opts->only_trailers) - fwrite(sb.buf + trailer_block_end(info), 1, sb.len - trailer_block_end(info), outfile); - trailer_info_release(info); + fwrite(sb.buf + trailer_block_end(trailer_block), 1, + sb.len - trailer_block_end(trailer_block), outfile); + trailer_block_release(trailer_block); if (opts->in_place) if (rename_tempfile(&trailers_tempfile, file)) diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c index f723b3bf3b..42f34e1236 100644 --- a/builtin/ls-remote.c +++ b/builtin/ls-remote.c @@ -166,6 +166,7 @@ int cmd_ls_remote(int argc, status = 0; /* we found something */ } + string_list_clear(&server_options, 0); ref_sorting_release(sorting); ref_array_clear(&ref_array); if (transport_disconnect(transport)) @@ -173,5 +174,6 @@ int cmd_ls_remote(int argc, transport_ls_refs_options_release(&transport_options); strvec_clear(&pattern); + string_list_clear(&server_options, 0); return status; } diff --git a/builtin/merge.c b/builtin/merge.c index 84d0f3604b..51038eaca8 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -754,6 +754,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, clean = merge_recursive(&o, head, remoteheads->item, reversed, &result); free_commit_list(reversed); + strbuf_release(&o.obuf); if (clean < 0) { rollback_lock_file(&lock); diff --git a/builtin/notes.c b/builtin/notes.c index 8c26e45526..72c8a51cfa 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -32,9 +32,9 @@ static const char *separator = "\n"; static const char * const git_notes_usage[] = { N_("git notes [--ref <notes-ref>] [list [<object>]]"), - N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), + N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>] [-e]"), N_("git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"), - N_("git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), + N_("git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>] [-e]"), N_("git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"), N_("git notes [--ref <notes-ref>] show [<object>]"), N_("git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"), @@ -489,6 +489,8 @@ static int add(int argc, const char **argv, const char *prefix) OPT_CALLBACK_F('c', "reedit-message", &d, N_("object"), N_("reuse and edit specified note object"), PARSE_OPT_NONEG, parse_reedit_arg), + OPT_BOOL('e', "edit", &d.use_editor, + N_("edit note message in editor")), OPT_CALLBACK_F('C', "reuse-message", &d, N_("object"), N_("reuse specified note object"), PARSE_OPT_NONEG, parse_reuse_arg), @@ -667,6 +669,8 @@ static int append_edit(int argc, const char **argv, const char *prefix) OPT_CALLBACK_F('C', "reuse-message", &d, N_("object"), N_("reuse specified note object"), PARSE_OPT_NONEG, parse_reuse_arg), + OPT_BOOL('e', "edit", &d.use_editor, + N_("edit note message in editor")), OPT_BOOL(0, "allow-empty", &allow_empty, N_("allow storing empty note")), OPT_CALLBACK_F(0, "separator", &separator, diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 0fc0680b40..676a586709 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -239,6 +239,7 @@ static enum { static uint16_t write_bitmap_options = BITMAP_OPT_HASH_CACHE; static int exclude_promisor_objects; +static int exclude_promisor_objects_best_effort; static int use_delta_islands; @@ -1100,78 +1101,64 @@ static void write_reused_pack_one(struct packed_git *reuse_packfile, static size_t write_reused_pack_verbatim(struct bitmapped_pack *reuse_packfile, struct hashfile *out, - off_t pack_start, struct pack_window **w_curs) { - size_t pos = reuse_packfile->bitmap_pos; + size_t pos = 0; size_t end; - if (pos % BITS_IN_EWORD) { - size_t word_pos = (pos / BITS_IN_EWORD); - size_t offset = pos % BITS_IN_EWORD; - size_t last; - eword_t word = reuse_packfile_bitmap->words[word_pos]; - - if (offset + reuse_packfile->bitmap_nr < BITS_IN_EWORD) - last = offset + reuse_packfile->bitmap_nr; - else - last = BITS_IN_EWORD; - - for (; offset < last; offset++) { - if (word >> offset == 0) - return word_pos; - if (!bitmap_get(reuse_packfile_bitmap, - word_pos * BITS_IN_EWORD + offset)) - return word_pos; - } - - pos += BITS_IN_EWORD - (pos % BITS_IN_EWORD); + if (reuse_packfile->bitmap_pos) { + /* + * We can't reuse whole chunks verbatim out of + * non-preferred packs since we can't guarantee that + * all duplicate objects were resolved in favor of + * that pack. + * + * Even if we have a whole eword_t worth of bits that + * could be reused, there may be objects between the + * objects corresponding to the first and last bit of + * that word which were selected from a different + * pack, causing us to send duplicate or unwanted + * objects. + * + * Handle non-preferred packs from within + * write_reused_pack(), which inspects and reuses + * individual bits. + */ + return reuse_packfile->bitmap_pos / BITS_IN_EWORD; } /* - * Now we're going to copy as many whole eword_t's as possible. - * "end" is the index of the last whole eword_t we copy, but - * there may be additional bits to process. Those are handled - * individually by write_reused_pack(). + * Only read through the last word whose bits all correspond + * to objects in the given packfile, since we must stop at a + * word boundary. * - * Begin by advancing to the first word boundary in range of the - * bit positions occupied by objects in "reuse_packfile". Then - * pick the last word boundary in the same range. If we have at - * least one word's worth of bits to process, continue on. + * If there is no whole word to read (i.e. the packfile + * contains fewer than BITS_IN_EWORD objects), then we'll + * inspect bits one-by-one in write_reused_pack(). */ - end = reuse_packfile->bitmap_pos + reuse_packfile->bitmap_nr; - if (end % BITS_IN_EWORD) - end -= end % BITS_IN_EWORD; - if (pos >= end) - return reuse_packfile->bitmap_pos / BITS_IN_EWORD; + end = reuse_packfile->bitmap_nr / BITS_IN_EWORD; + if (reuse_packfile_bitmap->word_alloc < end) + BUG("fewer words than expected in reuse_packfile_bitmap"); - while (pos < end && - reuse_packfile_bitmap->words[pos / BITS_IN_EWORD] == (eword_t)~0) - pos += BITS_IN_EWORD; + while (pos < end && reuse_packfile_bitmap->words[pos] == (eword_t)~0) + pos++; - if (pos > end) - pos = end; + if (pos) { + off_t to_write; - if (reuse_packfile->bitmap_pos < pos) { - off_t pack_start_off = pack_pos_to_offset(reuse_packfile->p, 0); - off_t pack_end_off = pack_pos_to_offset(reuse_packfile->p, - pos - reuse_packfile->bitmap_pos); - - written += pos - reuse_packfile->bitmap_pos; + written = (pos * BITS_IN_EWORD); + to_write = pack_pos_to_offset(reuse_packfile->p, written) + - sizeof(struct pack_header); /* We're recording one chunk, not one object. */ - record_reused_object(pack_start_off, - pack_start_off - (hashfile_total(out) - pack_start)); + record_reused_object(sizeof(struct pack_header), 0); hashflush(out); copy_pack_data(out, reuse_packfile->p, w_curs, - pack_start_off, pack_end_off - pack_start_off); + sizeof(struct pack_header), to_write); display_progress(progress_state, written); } - if (pos % BITS_IN_EWORD) - BUG("attempted to jump past a word boundary to %"PRIuMAX, - (uintmax_t)pos); - return pos / BITS_IN_EWORD; + return pos; } static void write_reused_pack(struct bitmapped_pack *reuse_packfile, @@ -1183,8 +1170,7 @@ static void write_reused_pack(struct bitmapped_pack *reuse_packfile, struct pack_window *w_curs = NULL; if (allow_ofs_delta) - i = write_reused_pack_verbatim(reuse_packfile, f, pack_start, - &w_curs); + i = write_reused_pack_verbatim(reuse_packfile, f, &w_curs); for (; i < reuse_packfile_bitmap->word_alloc; ++i) { eword_t word = reuse_packfile_bitmap->words[i]; @@ -1556,7 +1542,7 @@ static int want_object_in_pack_one(struct packed_git *p, if (p == *found_pack) offset = *found_offset; else - offset = find_pack_entry_one(oid->hash, p); + offset = find_pack_entry_one(oid, p); if (offset) { if (!*found_pack) { @@ -3984,7 +3970,7 @@ static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid) while (p) { if ((!p->pack_local || p->pack_keep || p->pack_keep_in_core) && - find_pack_entry_one(oid->hash, p)) { + find_pack_entry_one(oid, p)) { last_found = p; return 1; } @@ -4312,6 +4298,18 @@ static int option_parse_cruft_expiration(const struct option *opt UNUSED, return 0; } +static int is_not_in_promisor_pack_obj(struct object *obj, void *data UNUSED) +{ + struct object_info info = OBJECT_INFO_INIT; + if (oid_object_info_extended(the_repository, &obj->oid, &info, 0)) + BUG("should_include_obj should only be called on existing objects"); + return info.whence != OI_PACKED || !info.u.packed.pack->pack_promisor; +} + +static int is_not_in_promisor_pack(struct commit *commit, void *data) { + return is_not_in_promisor_pack_obj((struct object *) commit, data); +} + int cmd_pack_objects(int argc, const char **argv, const char *prefix, @@ -4424,6 +4422,9 @@ int cmd_pack_objects(int argc, option_parse_missing_action), OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects, N_("do not pack objects in promisor packfiles")), + OPT_BOOL(0, "exclude-promisor-objects-best-effort", + &exclude_promisor_objects_best_effort, + N_("implies --missing=allow-any")), OPT_BOOL(0, "delta-islands", &use_delta_islands, N_("respect islands during delta compression")), OPT_STRING_LIST(0, "uri-protocol", &uri_protocols, @@ -4504,10 +4505,18 @@ int cmd_pack_objects(int argc, strvec_push(&rp, "--unpacked"); } + if (exclude_promisor_objects && exclude_promisor_objects_best_effort) + die(_("options '%s' and '%s' cannot be used together"), + "--exclude-promisor-objects", "--exclude-promisor-objects-best-effort"); if (exclude_promisor_objects) { use_internal_rev_list = 1; fetch_if_missing = 0; strvec_push(&rp, "--exclude-promisor-objects"); + } else if (exclude_promisor_objects_best_effort) { + use_internal_rev_list = 1; + fetch_if_missing = 0; + option_parse_missing_action(NULL, "allow-any", 0); + /* revs configured below */ } if (unpack_unreachable || keep_unreachable || pack_loose_unreachable) use_internal_rev_list = 1; @@ -4627,6 +4636,10 @@ int cmd_pack_objects(int argc, repo_init_revisions(the_repository, &revs, NULL); list_objects_filter_copy(&revs.filter, &filter_options); + if (exclude_promisor_objects_best_effort) { + revs.include_check = is_not_in_promisor_pack; + revs.include_check_obj = is_not_in_promisor_pack_obj; + } get_object_list(&revs, rp.nr, rp.v); release_revisions(&revs); } diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c index 81f4494d46..d2c1c4e5ec 100644 --- a/builtin/pack-redundant.c +++ b/builtin/pack-redundant.c @@ -13,6 +13,7 @@ #include "packfile.h" #include "object-store-ll.h" +#include "strbuf.h" #define BLKSIZE 512 @@ -69,6 +70,15 @@ static inline void llist_init(struct llist **list) (*list)->size = 0; } +static void llist_free(struct llist *list) +{ + for (struct llist_item *i = list->front, *next; i; i = next) { + next = i->next; + llist_item_put(i); + } + free(list); +} + static struct llist * llist_copy(struct llist *list) { struct llist *ret; @@ -206,6 +216,14 @@ static inline struct pack_list * pack_list_insert(struct pack_list **pl, return p; } +static void pack_list_free(struct pack_list *pl) +{ + for (struct pack_list *next; pl; pl = next) { + next = pl->next; + free(pl); + } +} + static inline size_t pack_list_size(struct pack_list *pl) { size_t ret = 0; @@ -419,7 +437,8 @@ static void minimize(struct pack_list **min) /* return if there are no objects missing from the unique set */ if (missing->size == 0) { - free(missing); + llist_free(missing); + pack_list_free(non_unique); return; } @@ -434,6 +453,8 @@ static void minimize(struct pack_list **min) } while (non_unique) { + struct pack_list *next; + /* sort the non_unique packs, greater size of remaining_objects first */ sort_pack_list(&non_unique); if (non_unique->remaining_objects->size == 0) @@ -444,8 +465,14 @@ static void minimize(struct pack_list **min) for (pl = non_unique->next; pl && pl->remaining_objects->size > 0; pl = pl->next) llist_sorted_difference_inplace(pl->remaining_objects, non_unique->remaining_objects); - non_unique = non_unique->next; + next = non_unique->next; + free(non_unique); + non_unique = next; } + + pack_list_free(non_unique); + llist_free(unique_pack_objects); + llist_free(missing); } static void load_all_objects(void) @@ -565,7 +592,7 @@ static void load_all(void) int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, struct repository *repo UNUSED) { int i; int i_still_use_this = 0; struct pack_list *min = NULL, *red, *pl; struct llist *ignore; - struct object_id *oid; + struct strbuf idx_name = STRBUF_INIT; char buf[GIT_MAX_HEXSZ + 2]; /* hex hash + \n + \0 */ if (argc == 2 && !strcmp(argv[1], "-h")) @@ -625,11 +652,11 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, s /* ignore objects given on stdin */ llist_init(&ignore); if (!isatty(0)) { + struct object_id oid; while (fgets(buf, sizeof(buf), stdin)) { - oid = xmalloc(sizeof(*oid)); - if (get_oid_hex(buf, oid)) + if (get_oid_hex(buf, &oid)) die("Bad object ID on stdin: %s", buf); - llist_insert_sorted_unique(ignore, oid, NULL); + llist_insert_sorted_unique(ignore, &oid, NULL); } } llist_sorted_difference_inplace(all_objects, ignore); @@ -663,7 +690,7 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, s pl = red = pack_list_difference(local_packs, min); while (pl) { printf("%s\n%s\n", - sha1_pack_index_name(pl->pack->hash), + odb_pack_name(&idx_name, pl->pack->hash, "idx"), pl->pack->pack_name); pl = pl->next; } @@ -671,5 +698,9 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, s fprintf(stderr, "%luMB of redundant packs in total.\n", (unsigned long)pack_set_bytecount(red)/(1024*1024)); + pack_list_free(red); + pack_list_free(min); + llist_free(ignore); + strbuf_release(&idx_name); return 0; } diff --git a/builtin/pull.c b/builtin/pull.c index 149f201320..edc56907aa 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -85,7 +85,7 @@ static const char *opt_squash; static const char *opt_commit; static const char *opt_edit; static const char *cleanup_arg; -static const char *opt_ff; +static char *opt_ff; static const char *opt_verify_signatures; static const char *opt_verify; static int opt_autostash = -1; @@ -218,8 +218,8 @@ static struct option pull_options[] = { OPT_PASSTHRU_ARGV(0, "shallow-since", &opt_fetch, N_("time"), N_("deepen history of shallow repository based on time"), 0), - OPT_PASSTHRU_ARGV(0, "shallow-exclude", &opt_fetch, N_("revision"), - N_("deepen history of shallow clone, excluding rev"), + OPT_PASSTHRU_ARGV(0, "shallow-exclude", &opt_fetch, N_("ref"), + N_("deepen history of shallow clone, excluding ref"), 0), OPT_PASSTHRU_ARGV(0, "deepen", &opt_fetch, N_("n"), N_("deepen history of shallow clone"), @@ -1028,8 +1028,10 @@ int cmd_pull(int argc, * "--rebase" can override a config setting of * pull.ff=only. */ - if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only")) - opt_ff = "--ff"; + if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only")) { + free(opt_ff); + opt_ff = xstrdup("--ff"); + } } if (opt_rebase < 0) @@ -1139,7 +1141,8 @@ int cmd_pull(int argc, if (can_ff) { /* we can fast-forward this without invoking rebase */ - opt_ff = "--ff-only"; + free(opt_ff); + opt_ff = xstrdup("--ff-only"); ret = run_merge(); } else { ret = run_rebase(&newbase, &upstream); diff --git a/builtin/push.c b/builtin/push.c index e6f48969b8..51c609f208 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -519,14 +519,7 @@ static int git_push_config(const char *k, const char *v, RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF; recurse_submodules = val; } else if (!strcmp(k, "push.pushoption")) { - if (!v) - return config_error_nonbool(k); - else - if (!*v) - string_list_clear(&push_options_config, 0); - else - string_list_append(&push_options_config, v); - return 0; + return parse_transport_option(k, v, &push_options_config); } else if (!strcmp(k, "color.push")) { push_use_color = git_config_colorbool(k, v); return 0; @@ -669,6 +662,7 @@ int cmd_push(int argc, rc = do_push(flags, push_options, remote); string_list_clear(&push_options_cmdline, 0); string_list_clear(&push_options_config, 0); + clear_cas_option(&cas); if (rc == -1) usage_with_options(push_usage, options); else diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 536d22761d..ab5b20e39c 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -374,6 +374,7 @@ static void write_head_info(void) struct command { struct command *next; const char *error_string; + char *error_string_owned; struct ref_push_report *report; unsigned int skip_update:1, did_not_exist:1, @@ -1083,7 +1084,7 @@ static int read_proc_receive_report(struct packet_reader *reader, hint->run_proc_receive |= RUN_PROC_RECEIVE_RETURNED; if (!strcmp(head, "ng")) { if (p) - hint->error_string = xstrdup(p); + hint->error_string = hint->error_string_owned = xstrdup(p); else hint->error_string = "failed"; code = -1; @@ -2054,6 +2055,8 @@ static void free_commands(struct command *commands) while (commands) { struct command *next = commands->next; + ref_push_report_free(commands->report); + free(commands->error_string_owned); free(commands); commands = next; } diff --git a/builtin/remote.c b/builtin/remote.c index 3dc1135b5c..4a8b2ef678 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -377,7 +377,7 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat for (i = 0; i < states->remote->fetch.nr; i++) if (get_fetch_map(remote_refs, &states->remote->fetch.items[i], &tail, 1)) die(_("Could not get fetch map for refspec %s"), - states->remote->fetch.raw[i]); + states->remote->fetch.items[i].raw); for (ref = fetch_map; ref; ref = ref->next) { if (omit_name_by_refspec(ref->name, &states->remote->fetch)) @@ -633,12 +633,12 @@ static int migrate_file(struct remote *remote) git_config_set_multivar(buf.buf, remote->url.v[i], "^$", 0); strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.push", remote->name); - for (i = 0; i < remote->push.raw_nr; i++) - git_config_set_multivar(buf.buf, remote->push.raw[i], "^$", 0); + for (i = 0; i < remote->push.nr; i++) + git_config_set_multivar(buf.buf, remote->push.items[i].raw, "^$", 0); strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.fetch", remote->name); - for (i = 0; i < remote->fetch.raw_nr; i++) - git_config_set_multivar(buf.buf, remote->fetch.raw[i], "^$", 0); + for (i = 0; i < remote->fetch.nr; i++) + git_config_set_multivar(buf.buf, remote->fetch.items[i].raw, "^$", 0); if (remote->origin == REMOTE_REMOTES) unlink_or_warn(git_path("remotes/%s", remote->name)); else if (remote->origin == REMOTE_BRANCHES) @@ -759,16 +759,16 @@ static int mv(int argc, const char **argv, const char *prefix) goto out; } - if (oldremote->fetch.raw_nr) { + if (oldremote->fetch.nr) { strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.fetch", rename.new_name); git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE); strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name); - for (i = 0; i < oldremote->fetch.raw_nr; i++) { + for (i = 0; i < oldremote->fetch.nr; i++) { char *ptr; strbuf_reset(&buf2); - strbuf_addstr(&buf2, oldremote->fetch.raw[i]); + strbuf_addstr(&buf2, oldremote->fetch.items[i].raw); ptr = strstr(buf2.buf, old_remote_context.buf); if (ptr) { refspec_updated = 1; diff --git a/builtin/repack.c b/builtin/repack.c index cb4420f085..d6bb37e84a 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -86,17 +86,34 @@ static int repack_config(const char *var, const char *value, run_update_server_info = git_config_bool(var, value); return 0; } - if (!strcmp(var, "repack.cruftwindow")) + if (!strcmp(var, "repack.cruftwindow")) { + free(cruft_po_args->window); return git_config_string(&cruft_po_args->window, var, value); - if (!strcmp(var, "repack.cruftwindowmemory")) + } + if (!strcmp(var, "repack.cruftwindowmemory")) { + free(cruft_po_args->window_memory); return git_config_string(&cruft_po_args->window_memory, var, value); - if (!strcmp(var, "repack.cruftdepth")) + } + if (!strcmp(var, "repack.cruftdepth")) { + free(cruft_po_args->depth); return git_config_string(&cruft_po_args->depth, var, value); - if (!strcmp(var, "repack.cruftthreads")) + } + if (!strcmp(var, "repack.cruftthreads")) { + free(cruft_po_args->threads); return git_config_string(&cruft_po_args->threads, var, value); + } return git_default_config(var, value, ctx, cb); } +static void pack_objects_args_release(struct pack_objects_args *args) +{ + free(args->window); + free(args->window_memory); + free(args->depth); + free(args->threads); + list_objects_filter_release(&args->filter_options); +} + struct existing_packs { struct string_list kept_packs; struct string_list non_kept_packs; @@ -1156,12 +1173,16 @@ int cmd_repack(int argc, const char *unpack_unreachable = NULL; int keep_unreachable = 0; struct string_list keep_pack_list = STRING_LIST_INIT_NODUP; - struct pack_objects_args po_args = {NULL}; - struct pack_objects_args cruft_po_args = {NULL}; + struct pack_objects_args po_args = { 0 }; + struct pack_objects_args cruft_po_args = { 0 }; int write_midx = 0; const char *cruft_expiration = NULL; const char *expire_to = NULL; const char *filter_to = NULL; + const char *opt_window = NULL; + const char *opt_window_memory = NULL; + const char *opt_depth = NULL; + const char *opt_threads = NULL; struct option builtin_repack_options[] = { OPT_BIT('a', NULL, &pack_everything, @@ -1195,13 +1216,13 @@ int cmd_repack(int argc, N_("with -A, do not loosen objects older than this")), OPT_BOOL('k', "keep-unreachable", &keep_unreachable, N_("with -a, repack unreachable objects")), - OPT_STRING(0, "window", &po_args.window, N_("n"), + OPT_STRING(0, "window", &opt_window, N_("n"), N_("size of the window used for delta compression")), - OPT_STRING(0, "window-memory", &po_args.window_memory, N_("bytes"), + OPT_STRING(0, "window-memory", &opt_window_memory, N_("bytes"), N_("same as the above, but limit memory size instead of entries count")), - OPT_STRING(0, "depth", &po_args.depth, N_("n"), + OPT_STRING(0, "depth", &opt_depth, N_("n"), N_("limits the maximum delta depth")), - OPT_STRING(0, "threads", &po_args.threads, N_("n"), + OPT_STRING(0, "threads", &opt_threads, N_("n"), N_("limits the maximum number of threads")), OPT_MAGNITUDE(0, "max-pack-size", &po_args.max_pack_size, N_("maximum size of each packfile")), @@ -1228,6 +1249,11 @@ int cmd_repack(int argc, argc = parse_options(argc, argv, prefix, builtin_repack_options, git_repack_usage, 0); + po_args.window = xstrdup_or_null(opt_window); + po_args.window_memory = xstrdup_or_null(opt_window_memory); + po_args.depth = xstrdup_or_null(opt_depth); + po_args.threads = xstrdup_or_null(opt_threads); + if (delete_redundant && repository_format_precious_objects) die(_("cannot delete packs in a precious-objects repo")); @@ -1393,13 +1419,13 @@ int cmd_repack(int argc, const char *pack_prefix = find_pack_prefix(packdir, packtmp); if (!cruft_po_args.window) - cruft_po_args.window = po_args.window; + cruft_po_args.window = xstrdup_or_null(po_args.window); if (!cruft_po_args.window_memory) - cruft_po_args.window_memory = po_args.window_memory; + cruft_po_args.window_memory = xstrdup_or_null(po_args.window_memory); if (!cruft_po_args.depth) - cruft_po_args.depth = po_args.depth; + cruft_po_args.depth = xstrdup_or_null(po_args.depth); if (!cruft_po_args.threads) - cruft_po_args.threads = po_args.threads; + cruft_po_args.threads = xstrdup_or_null(po_args.threads); if (!cruft_po_args.max_pack_size) cruft_po_args.max_pack_size = po_args.max_pack_size; @@ -1552,7 +1578,8 @@ cleanup: string_list_clear(&names, 1); existing_packs_release(&existing); free_pack_geometry(&geometry); - list_objects_filter_release(&po_args.filter_options); + pack_objects_args_release(&po_args); + pack_objects_args_release(&cruft_po_args); return ret; } diff --git a/builtin/rev-list.c b/builtin/rev-list.c index f62bcbf2b1..3078787115 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -485,6 +485,13 @@ static int try_bitmap_traversal(struct rev_info *revs, if (revs->max_count >= 0) return -1; + /* + * We can't know which commits were left/right in a single traversal, + * and we don't yet know how to traverse them separately. + */ + if (revs->left_right) + return -1; + bitmap_git = prepare_bitmap_walk(revs, filter_provided_objects); if (!bitmap_git) return -1; diff --git a/builtin/revert.c b/builtin/revert.c index 55ba1092c5..b7917dddd3 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -110,6 +110,9 @@ static int run_sequencer(int argc, const char **argv, const char *prefix, const char * const * usage_str = revert_or_cherry_pick_usage(opts); const char *me = action_name(opts); const char *cleanup_arg = NULL; + const char sentinel_value; + const char *strategy = &sentinel_value; + const char *gpg_sign = &sentinel_value; enum empty_action empty_opt = EMPTY_COMMIT_UNSPECIFIED; int cmd = 0; struct option base_options[] = { @@ -125,10 +128,10 @@ static int run_sequencer(int argc, const char **argv, const char *prefix, OPT_CALLBACK('m', "mainline", opts, N_("parent-number"), N_("select mainline parent"), option_parse_m), OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto), - OPT_STRING(0, "strategy", &opts->strategy, N_("strategy"), N_("merge strategy")), + OPT_STRING(0, "strategy", &strategy, N_("strategy"), N_("merge strategy")), OPT_STRVEC('X', "strategy-option", &opts->xopts, N_("option"), N_("option for merge strategy")), - { OPTION_STRING, 'S', "gpg-sign", &opts->gpg_sign, N_("key-id"), + { OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"), N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, OPT_END() }; @@ -240,8 +243,14 @@ static int run_sequencer(int argc, const char **argv, const char *prefix, usage_with_options(usage_str, options); /* These option values will be free()d */ - opts->gpg_sign = xstrdup_or_null(opts->gpg_sign); - opts->strategy = xstrdup_or_null(opts->strategy); + if (gpg_sign != &sentinel_value) { + free(opts->gpg_sign); + opts->gpg_sign = xstrdup_or_null(gpg_sign); + } + if (strategy != &sentinel_value) { + 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); diff --git a/builtin/send-pack.c b/builtin/send-pack.c index 81fc96d423..59b626aae8 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -340,8 +340,11 @@ int cmd_send_pack(int argc, /* stable plumbing output; do not modify or localize */ fprintf(stderr, "Everything up-to-date\n"); + string_list_clear(&push_options, 0); free_refs(remote_refs); free_refs(local_refs); refspec_clear(&rs); + oid_array_clear(&shallow); + clear_cas_option(&cas); return ret; } diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 3ed5c46078..c86b75d981 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -407,6 +407,18 @@ int cmd_shortlog(int argc, struct parse_opt_ctx_t ctx; + /* + * NEEDSWORK: Later on we'll call parse_revision_opt which relies on + * the hash algorithm being set but since we are operating outside of a + * Git repository we cannot determine one. This is only needed because + * parse_revision_opt expects hexsz for --abbrev which is irrelevant + * for shortlog outside of a git repository. For now explicitly set + * SHA1, but ideally the parsing machinery would be split between + * git/nongit so that we do not have to do this. + */ + if (nongit && !the_hash_algo) + repo_set_hash_algo(the_repository, GIT_HASH_SHA1); + git_config(git_default_config, NULL); shortlog_init(&log); repo_init_revisions(the_repository, &rev, prefix); diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index e4e791a4c9..49aedc1de8 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -924,6 +924,11 @@ static int sparse_checkout_disable(int argc, const char **argv, builtin_sparse_checkout_disable_options, builtin_sparse_checkout_disable_usage, 0); + /* + * Disable the advice message for expanding a sparse index, as we + * are expecting to do that when disabling sparse-checkout. + */ + give_advice_on_expansion = 0; repo_read_index(the_repository); memset(&pl, 0, sizeof(pl)); diff --git a/builtin/stash.c b/builtin/stash.c index f1acc918d0..1399a1bbe2 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -1759,7 +1759,7 @@ static int push_stash(int argc, const char **argv, const char *prefix, int quiet = 0; int pathspec_file_nul = 0; const char *stash_msg = NULL; - const char *pathspec_from_file = NULL; + char *pathspec_from_file = NULL; struct pathspec ps; struct option options[] = { OPT_BOOL('k', "keep-index", &keep_index, @@ -1821,7 +1821,9 @@ static int push_stash(int argc, const char **argv, const char *prefix, ret = do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode, include_untracked, only_staged); + clear_pathspec(&ps); + free(pathspec_from_file); return ret; } diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 8d36aefbe6..b6b5f1ebde 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -364,9 +364,13 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item, if (!info->quiet) printf(_("Entering '%s'\n"), displaypath); - if (info->argv[0] && run_command(&cp)) - die(_("run_command returned non-zero status for %s\n."), - displaypath); + if (info->argv[0]) { + if (run_command(&cp)) + die(_("run_command returned non-zero status for %s\n."), + displaypath); + } else { + child_process_clear(&cp); + } if (info->recursive) { struct child_process cpr = CHILD_PROCESS_INIT; @@ -1622,6 +1626,8 @@ static int add_possible_reference_from_superproject( ; /* nothing */ } } + + strbuf_release(&err); strbuf_release(&sb); } @@ -2026,6 +2032,7 @@ struct update_data { static void update_data_release(struct update_data *ud) { free(ud->displaypath); + submodule_update_strategy_release(&ud->update_strategy); module_list_release(&ud->list); } @@ -2326,7 +2333,14 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, strvec_pushf(&cp.args, "--depth=%d", depth); if (oid) { char *hex = oid_to_hex(oid); - char *remote = get_default_remote(); + char *remote; + int code; + + code = get_default_remote_submodule(module_path, &remote); + if (code) { + child_process_clear(&cp); + return code; + } strvec_pushl(&cp.args, remote, hex, NULL); free(remote); @@ -2646,15 +2660,20 @@ static int update_submodule(struct update_data *update_data) if (!update_data->nofetch) { if (fetch_in_submodule(update_data->sm_path, update_data->depth, - 0, NULL)) + 0, NULL)) { + free(remote_ref); return die_message(_("Unable to fetch in submodule path '%s'"), update_data->sm_path); + } } if (repo_resolve_gitlink_ref(the_repository, update_data->sm_path, - remote_ref, &update_data->oid)) - return die_message(_("Unable to find %s revision in submodule path '%s'"), - remote_ref, update_data->sm_path); + remote_ref, &update_data->oid)) { + ret = die_message(_("Unable to find %s revision in submodule path '%s'"), + remote_ref, update_data->sm_path); + free(remote_ref); + return ret; + } free(remote_ref); } diff --git a/builtin/tag.c b/builtin/tag.c index 93d10d5915..c37c0a68fd 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -164,7 +164,7 @@ static int do_sign(struct strbuf *buffer, struct object_id **compat_oid, int ret = -1; if (sign_buffer(buffer, &sig, keyid)) - return -1; + goto out; if (compat) { const struct git_hash_algo *algo = the_repository->hash_algo; diff --git a/builtin/worktree.c b/builtin/worktree.c index fc31d072a6..dae63dedf4 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -414,7 +414,8 @@ static int add_worktree(const char *path, const char *refname, const struct add_opts *opts) { struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT; - struct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT; + struct strbuf sb = STRBUF_INIT, sb_tmp = STRBUF_INIT; + struct strbuf sb_path_realpath = STRBUF_INIT, sb_repo_realpath = STRBUF_INIT; const char *name; struct strvec child_env = STRVEC_INIT; unsigned int counter = 0; @@ -490,11 +491,10 @@ static int add_worktree(const char *path, const char *refname, strbuf_reset(&sb); strbuf_addf(&sb, "%s/gitdir", sb_repo.buf); - strbuf_realpath(&realpath, sb_git.buf, 1); - write_file(sb.buf, "%s", realpath.buf); - strbuf_realpath(&realpath, repo_get_common_dir(the_repository), 1); - write_file(sb_git.buf, "gitdir: %s/worktrees/%s", - realpath.buf, name); + strbuf_realpath(&sb_path_realpath, path, 1); + strbuf_realpath(&sb_repo_realpath, sb_repo.buf, 1); + write_file(sb.buf, "%s/.git", relative_path(sb_path_realpath.buf, sb_repo_realpath.buf, &sb_tmp)); + write_file(sb_git.buf, "gitdir: %s", relative_path(sb_repo_realpath.buf, sb_path_realpath.buf, &sb_tmp)); strbuf_reset(&sb); strbuf_addf(&sb, "%s/commondir", sb_repo.buf); write_file(sb.buf, "../.."); @@ -578,11 +578,13 @@ done: strvec_clear(&child_env); strbuf_release(&sb); + strbuf_release(&sb_tmp); strbuf_release(&symref); strbuf_release(&sb_repo); + strbuf_release(&sb_repo_realpath); strbuf_release(&sb_git); + strbuf_release(&sb_path_realpath); strbuf_release(&sb_name); - strbuf_release(&realpath); free_worktree(wt); return ret; } |