diff options
Diffstat (limited to 'builtin')
50 files changed, 810 insertions, 368 deletions
diff --git a/builtin/am.c b/builtin/am.c index 370f5593f2..d8875ad402 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -490,7 +490,8 @@ static int run_applypatch_msg_hook(struct am_state *state) assert(state->msg); if (!state->no_verify) - ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL); + ret = run_hooks_l(the_repository, "applypatch-msg", + am_path(state, "final-commit"), NULL); if (!ret) { FREE_AND_NULL(state->msg); @@ -512,7 +513,7 @@ static int run_post_rewrite_hook(const struct am_state *state) strvec_push(&opt.args, "rebase"); opt.path_to_stdin = am_path(state, "rewritten"); - return run_hooks_opt("post-rewrite", &opt); + return run_hooks_opt(the_repository, "post-rewrite", &opt); } /** @@ -1630,7 +1631,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa * changes. */ - init_merge_options(&o, the_repository); + init_ui_merge_options(&o, the_repository); o.branch1 = "HEAD"; their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg); @@ -1663,7 +1664,7 @@ static void do_commit(const struct am_state *state) const char *reflog_msg, *author, *committer = NULL; struct strbuf sb = STRBUF_INIT; - if (!state->no_verify && run_hooks("pre-applypatch")) + if (!state->no_verify && run_hooks(the_repository, "pre-applypatch")) exit(1); if (write_index_as_tree(&tree, the_repository->index, get_index_file(), 0, NULL)) @@ -1716,7 +1717,7 @@ static void do_commit(const struct am_state *state) fclose(fp); } - run_hooks("post-applypatch"); + run_hooks(the_repository, "post-applypatch"); free_commit_list(parents); strbuf_release(&sb); diff --git a/builtin/bisect.c b/builtin/bisect.c index dabce9b542..453a6cccd7 100644 --- a/builtin/bisect.c +++ b/builtin/bisect.c @@ -356,6 +356,7 @@ static int check_and_set_terms(struct bisect_terms *terms, const char *cmd) } static int inc_nr(const char *refname UNUSED, + const char *referent UNUSED, const struct object_id *oid UNUSED, int flag UNUSED, void *cb_data) { @@ -545,7 +546,7 @@ finish: return res; } -static int add_bisect_ref(const char *refname, const struct object_id *oid, +static int add_bisect_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid, int flags UNUSED, void *cb) { struct add_bisect_ref_data *data = cb; @@ -1162,6 +1163,7 @@ static int bisect_visualize(struct bisect_terms *terms, int argc, } static int get_first_good(const char *refname UNUSED, + const char *referent UNUSED, const struct object_id *oid, int flag UNUSED, void *cb_data) { diff --git a/builtin/branch.c b/builtin/branch.c index 48cac74f97..3f870741bf 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -210,7 +210,7 @@ static void delete_branch_config(const char *branchname) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "branch.%s", branchname); - if (git_config_rename_section(buf.buf, NULL) < 0) + if (repo_config_rename_section(the_repository, buf.buf, NULL) < 0) warning(_("update of config-file failed")); strbuf_release(&buf); } @@ -659,9 +659,10 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int strbuf_addf(&oldsection, "branch.%s", interpreted_oldname); strbuf_addf(&newsection, "branch.%s", interpreted_newname); - if (!copy && git_config_rename_section(oldsection.buf, newsection.buf) < 0) + if (!copy && repo_config_rename_section(the_repository, oldsection.buf, newsection.buf) < 0) die(_("branch is renamed, but update of config-file failed")); - if (copy && strcmp(interpreted_oldname, interpreted_newname) && git_config_copy_section(oldsection.buf, newsection.buf) < 0) + if (copy && strcmp(interpreted_oldname, interpreted_newname) && + repo_config_copy_section(the_repository, oldsection.buf, newsection.buf) < 0) die(_("branch is copied, but update of config-file failed")); strbuf_release(&oldref); strbuf_release(&newref); diff --git a/builtin/bugreport.c b/builtin/bugreport.c index b3cc77af53..bdfed3d8f1 100644 --- a/builtin/bugreport.c +++ b/builtin/bugreport.c @@ -58,7 +58,7 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit) for (p = hook_name_list; *p; p++) { const char *hook = *p; - if (hook_exists(hook)) + if (hook_exists(the_repository, hook)) strbuf_addf(hook_info, "%s\n", hook); } } diff --git a/builtin/bundle.c b/builtin/bundle.c index d5d41a8f67..86d0ed7049 100644 --- a/builtin/bundle.c +++ b/builtin/bundle.c @@ -207,12 +207,13 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix) builtin_bundle_unbundle_usage, options, &bundle_file); /* bundle internals use argv[1] as further parameters */ + if (!startup_info->have_repository) + die(_("Need a repository to unbundle.")); + if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) { ret = 1; goto cleanup; } - if (!startup_info->have_repository) - die(_("Need a repository to unbundle.")); if (progress) strvec_pushl(&extra_index_pack_args, "-v", "--progress-title", _("Unbundling objects"), NULL); diff --git a/builtin/checkout.c b/builtin/checkout.c index 3cf44b4683..4cfe6fab50 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -125,7 +125,7 @@ static void branch_info_release(struct branch_info *info) static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit, int changed) { - return run_hooks_l("post-checkout", + return run_hooks_l(the_repository, "post-checkout", oid_to_hex(old_commit ? &old_commit->object.oid : null_oid()), oid_to_hex(new_commit ? &new_commit->object.oid : null_oid()), changed ? "1" : "0", NULL); @@ -884,7 +884,7 @@ static int merge_working_tree(const struct checkout_opts *opts, add_files_to_cache(the_repository, NULL, NULL, NULL, 0, 0); - init_merge_options(&o, the_repository); + init_ui_merge_options(&o, the_repository); o.verbosity = 0; work = write_in_core_index_as_tree(the_repository); @@ -1045,7 +1045,7 @@ static void update_refs_for_switch(const struct checkout_opts *opts, report_tracking(new_branch_info); } -static int add_pending_uninteresting_ref(const char *refname, +static int add_pending_uninteresting_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid, int flags UNUSED, void *cb_data) { @@ -1572,6 +1572,10 @@ static void die_if_switching_to_a_branch_in_use(struct checkout_opts *opts, static int checkout_branch(struct checkout_opts *opts, struct branch_info *new_branch_info) { + int noop_switch = (!new_branch_info->name && + !opts->new_branch && + !opts->force_detach); + if (opts->pathspec.nr) die(_("paths cannot be used with switching branches")); @@ -1583,9 +1587,14 @@ static int checkout_branch(struct checkout_opts *opts, die(_("'%s' cannot be used with switching branches"), "--[no]-overlay"); - if (opts->writeout_stage) - die(_("'%s' cannot be used with switching branches"), - "--ours/--theirs"); + if (opts->writeout_stage) { + const char *msg; + if (noop_switch) + msg = _("'%s' needs the paths to check out"); + else + msg = _("'%s' cannot be used with switching branches"); + die(msg, "--ours/--theirs"); + } if (opts->force && opts->merge) die(_("'%s' cannot be used with '%s'"), "-f", "-m"); @@ -1612,10 +1621,8 @@ static int checkout_branch(struct checkout_opts *opts, die(_("Cannot switch branch to a non-commit '%s'"), new_branch_info->name); - if (!opts->switch_branch_doing_nothing_is_ok && - !new_branch_info->name && - !opts->new_branch && - !opts->force_detach) + if (noop_switch && + !opts->switch_branch_doing_nothing_is_ok) die(_("missing branch or commit argument")); if (!opts->implicit_detach && diff --git a/builtin/clone.c b/builtin/clone.c index af6017d41a..269b6e18a4 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -729,7 +729,8 @@ static int git_sparse_checkout_init(const char *repo) return result; } -static int checkout(int submodule_progress, int filter_submodules) +static int checkout(int submodule_progress, int filter_submodules, + enum ref_storage_format ref_storage_format) { struct object_id oid; char *head; @@ -788,7 +789,7 @@ static int checkout(int submodule_progress, int filter_submodules) if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); - err |= run_hooks_l("post-checkout", oid_to_hex(null_oid()), + err |= run_hooks_l(the_repository, "post-checkout", oid_to_hex(null_oid()), oid_to_hex(&oid), "1", NULL); if (!err && (option_recurse_submodules.nr > 0)) { @@ -813,6 +814,10 @@ static int checkout(int submodule_progress, int filter_submodules) strvec_push(&cmd.args, "--no-fetch"); } + if (ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN) + strvec_pushf(&cmd.args, "--ref-format=%s", + ref_storage_format_to_name(ref_storage_format)); + if (filter_submodules && filter_options.choice) strvec_pushf(&cmd.args, "--filter=%s", expand_list_objects_filter_spec(&filter_options)); @@ -1536,7 +1541,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) return 1; junk_mode = JUNK_LEAVE_REPO; - err = checkout(submodule_progress, filter_submodules); + err = checkout(submodule_progress, filter_submodules, + ref_storage_format); free(remote_name); strbuf_release(&reflog_msg); diff --git a/builtin/commit.c b/builtin/commit.c index dec78dfb86..b2033c4887 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -41,7 +41,7 @@ static const char * const builtin_commit_usage[] = { N_("git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n" - " [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>)]\n" + " [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>]\n" " [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n" " [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n" " [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n" @@ -684,7 +684,9 @@ static void adjust_comment_line_char(const struct strbuf *sb) const char *p; if (!memchr(sb->buf, candidates[0], sb->len)) { - comment_line_str = xstrfmt("%c", candidates[0]); + free(comment_line_str_to_free); + comment_line_str = comment_line_str_to_free = + xstrfmt("%c", candidates[0]); return; } @@ -705,7 +707,8 @@ static void adjust_comment_line_char(const struct strbuf *sb) if (!*p) die(_("unable to select a comment character that is not used\n" "in the current commit message")); - comment_line_str = xstrfmt("%c", *p); + free(comment_line_str_to_free); + comment_line_str = comment_line_str_to_free = xstrfmt("%c", *p); } static void prepare_amend_commit(struct commit *commit, struct strbuf *sb, diff --git a/builtin/config.c b/builtin/config.c index 20a0b64090..e00d983596 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -1026,8 +1026,8 @@ static int cmd_config_rename_section(int argc, const char **argv, const char *pr location_options_init(&location_opts, prefix); check_write(&location_opts.source); - ret = git_config_rename_section_in_file(location_opts.source.file, - argv[0], argv[1]); + ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file, + argv[0], argv[1]); if (ret < 0) goto out; else if (!ret) @@ -1055,8 +1055,8 @@ static int cmd_config_remove_section(int argc, const char **argv, const char *pr location_options_init(&location_opts, prefix); check_write(&location_opts.source); - ret = git_config_rename_section_in_file(location_opts.source.file, - argv[0], NULL); + ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file, + argv[0], NULL); if (ret < 0) goto out; else if (!ret) @@ -1353,8 +1353,8 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix) else if (actions == ACTION_RENAME_SECTION) { check_write(&location_opts.source); check_argc(argc, 2, 2); - ret = git_config_rename_section_in_file(location_opts.source.file, - argv[0], argv[1]); + ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file, + argv[0], argv[1]); if (ret < 0) goto out; else if (!ret) @@ -1365,8 +1365,8 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix) else if (actions == ACTION_REMOVE_SECTION) { check_write(&location_opts.source); check_argc(argc, 1, 1); - ret = git_config_rename_section_in_file(location_opts.source.file, - argv[0], NULL); + ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file, + argv[0], NULL); if (ret < 0) goto out; else if (!ret) diff --git a/builtin/count-objects.c b/builtin/count-objects.c index 2d4bb5e8d0..ec6098a149 100644 --- a/builtin/count-objects.c +++ b/builtin/count-objects.c @@ -113,7 +113,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix) usage_with_options(count_objects_usage, opts); if (verbose) { report_garbage = real_report_garbage; - report_linked_checkout_garbage(); + report_linked_checkout_garbage(the_repository); } for_each_loose_file_in_objdir(get_object_directory(), diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c index 3db8df70a9..aaf2f8438b 100644 --- a/builtin/credential-cache.c +++ b/builtin/credential-cache.c @@ -88,6 +88,8 @@ static void spawn_daemon(const char *socket) die_errno("unable to read result code from cache daemon"); if (r != 3 || memcmp(buf, "ok\n", 3)) die("cache daemon did not start: %.*s", r, buf); + + child_process_clear(&daemon); close(daemon.out); } @@ -137,7 +139,8 @@ static void announce_capabilities(void) int cmd_credential_cache(int argc, const char **argv, const char *prefix) { - char *socket_path = NULL; + const char *socket_path_arg = NULL; + char *socket_path; int timeout = 900; const char *op; const char * const usage[] = { @@ -147,7 +150,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix) struct option options[] = { OPT_INTEGER(0, "timeout", &timeout, "number of seconds to cache credentials"), - OPT_STRING(0, "socket", &socket_path, "path", + OPT_STRING(0, "socket", &socket_path_arg, "path", "path of cache-daemon socket"), OPT_END() }; @@ -160,6 +163,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix) if (!have_unix_sockets()) die(_("credential-cache unavailable; no unix socket support")); + socket_path = xstrdup_or_null(socket_path_arg); if (!socket_path) socket_path = get_socket_path(); if (!socket_path) @@ -176,6 +180,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix) else ; /* ignore unknown operation */ + free(socket_path); return 0; } diff --git a/builtin/credential-store.c b/builtin/credential-store.c index 494c809332..97968bfa1c 100644 --- a/builtin/credential-store.c +++ b/builtin/credential-store.c @@ -218,5 +218,6 @@ int cmd_credential_store(int argc, const char **argv, const char *prefix) ; /* Ignore unknown operation. */ string_list_clear(&fns, 0); + credential_clear(&c); return 0; } diff --git a/builtin/describe.c b/builtin/describe.c index cf8edc4222..b43093c099 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -149,7 +149,7 @@ static void add_to_known_names(const char *path, } } -static int get_name(const char *path, const struct object_id *oid, +static int get_name(const char *path, const char *referent UNUSED, const struct object_id *oid, int flag UNUSED, void *cb_data UNUSED) { int is_tag = 0; @@ -529,6 +529,7 @@ static void describe_blob(struct object_id oid, struct strbuf *dst) traverse_commit_list(&revs, process_commit, process_object, &pcd); reset_revision_walk(); release_revisions(&revs); + strvec_clear(&args); } static void describe(const char *arg, int last_one) @@ -619,6 +620,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix) if (contains) { struct string_list_item *item; struct strvec args; + const char **argv_copy; + int ret; strvec_init(&args); strvec_pushl(&args, "name-rev", @@ -637,7 +640,21 @@ int cmd_describe(int argc, const char **argv, const char *prefix) strvec_pushv(&args, argv); else strvec_push(&args, "HEAD"); - return cmd_name_rev(args.nr, args.v, prefix); + + /* + * `cmd_name_rev()` modifies the array, so we'd leak its + * contained strings if we didn't do a copy here. + */ + ALLOC_ARRAY(argv_copy, args.nr + 1); + for (size_t i = 0; i < args.nr; i++) + argv_copy[i] = args.v[i]; + argv_copy[args.nr] = NULL; + + ret = cmd_name_rev(args.nr, argv_copy, prefix); + + strvec_clear(&args); + free(argv_copy); + return ret; } hashmap_init(&names, commit_name_neq, NULL, 0); @@ -679,7 +696,6 @@ int cmd_describe(int argc, const char **argv, const char *prefix) } else if (dirty) { struct lock_file index_lock = LOCK_INIT; struct rev_info revs; - struct strvec args = STRVEC_INIT; int fd; setup_work_tree(); @@ -694,8 +710,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix) repo_update_index_if_able(the_repository, &index_lock); repo_init_revisions(the_repository, &revs, prefix); - strvec_pushv(&args, diff_index_args); - if (setup_revisions(args.nr, args.v, &revs, NULL) != 1) + + if (setup_revisions(ARRAY_SIZE(diff_index_args) - 1, + diff_index_args, &revs, NULL) != 1) BUG("malformed internal diff-index command line"); run_diff_index(&revs, 0); diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index 0d3c611aac..b8df1d4b79 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -8,6 +8,7 @@ #include "read-cache-ll.h" #include "repository.h" #include "revision.h" +#include "tmp-objdir.h" #include "tree.h" static struct rev_info log_tree_opt; @@ -166,6 +167,13 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) opt->diffopt.rotate_to_strict = 1; + if (opt->remerge_diff) { + opt->remerge_objdir = tmp_objdir_create("remerge-diff"); + if (!opt->remerge_objdir) + die(_("unable to create temporary object directory")); + tmp_objdir_replace_primary_odb(opt->remerge_objdir, 1); + } + /* * NOTE! We expect "a..b" to expand to "^a b" but it is * perfectly valid for revision range parser to yield "b ^a", @@ -230,5 +238,10 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) diff_free(&opt->diffopt); } + if (opt->remerge_diff) { + tmp_objdir_destroy(opt->remerge_objdir); + opt->remerge_objdir = NULL; + } + return diff_result_code(&opt->diffopt); } diff --git a/builtin/diff.c b/builtin/diff.c index 9b6cdabe15..6eac445579 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -388,6 +388,11 @@ static void symdiff_prepare(struct rev_info *rev, struct symdiff *sym) sym->skip = map; } +static void symdiff_release(struct symdiff *sdiff) +{ + bitmap_free(sdiff->skip); +} + int cmd_diff(int argc, const char **argv, const char *prefix) { int i; @@ -619,6 +624,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) refresh_index_quietly(); release_revisions(&rev); object_array_clear(&ent); + symdiff_release(&sdiff); UNLEAK(blob); return result; } diff --git a/builtin/fast-export.c b/builtin/fast-export.c index 4b6e8c6832..f253b79322 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -42,8 +42,8 @@ static int full_tree; static int reference_excluded_commits; static int show_original_ids; static int mark_tags; -static struct string_list extra_refs = STRING_LIST_INIT_NODUP; -static struct string_list tag_refs = STRING_LIST_INIT_NODUP; +static struct string_list extra_refs = STRING_LIST_INIT_DUP; +static struct string_list tag_refs = STRING_LIST_INIT_DUP; static struct refspec refspecs = REFSPEC_INIT_FETCH; static int anonymize; static struct hashmap anonymized_seeds; @@ -901,7 +901,7 @@ static void handle_tag(const char *name, struct tag *tag) free(buf); } -static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name) +static struct commit *get_commit(struct rev_cmdline_entry *e, const char *full_name) { switch (e->item->type) { case OBJ_COMMIT: @@ -932,14 +932,16 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info) struct rev_cmdline_entry *e = info->rev + i; struct object_id oid; struct commit *commit; - char *full_name; + char *full_name = NULL; if (e->flags & UNINTERESTING) continue; if (repo_dwim_ref(the_repository, e->name, strlen(e->name), - &oid, &full_name, 0) != 1) + &oid, &full_name, 0) != 1) { + free(full_name); continue; + } if (refspecs.nr) { char *private; @@ -955,6 +957,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info) warning("%s: Unexpected object of type %s, skipping.", e->name, type_name(e->item->type)); + free(full_name); continue; } @@ -963,10 +966,12 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info) break; case OBJ_BLOB: export_blob(&commit->object.oid); + free(full_name); continue; default: /* OBJ_TAG (nested tags) is already handled */ warning("Tag points to object of unexpected type %s, skipping.", type_name(commit->object.type)); + free(full_name); continue; } @@ -979,6 +984,8 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info) if (!*revision_sources_at(&revision_sources, commit)) *revision_sources_at(&revision_sources, commit) = full_name; + else + free(full_name); } string_list_sort(&extra_refs); @@ -1278,9 +1285,11 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) revs.diffopt.format_callback = show_filemodify; revs.diffopt.format_callback_data = &paths_of_changed_objects; revs.diffopt.flags.recursive = 1; + revs.diffopt.no_free = 1; while ((commit = get_revision(&revs))) handle_commit(commit, &revs, &paths_of_changed_objects); + revs.diffopt.no_free = 0; handle_tags_and_duplicates(&extra_refs); handle_tags_and_duplicates(&tag_refs); diff --git a/builtin/fast-import.c b/builtin/fast-import.c index d21c4053a7..2214c105f1 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -206,8 +206,8 @@ static unsigned int object_entry_alloc = 5000; static struct object_entry_pool *blocks; static struct hashmap object_table; static struct mark_set *marks; -static const char *export_marks_file; -static const char *import_marks_file; +static char *export_marks_file; +static char *import_marks_file; static int import_marks_file_from_stream; static int import_marks_file_ignore_missing; static int import_marks_file_done; @@ -3274,6 +3274,7 @@ static void option_import_marks(const char *marks, read_marks(); } + free(import_marks_file); import_marks_file = make_fast_import_path(marks); import_marks_file_from_stream = from_stream; import_marks_file_ignore_missing = ignore_missing; @@ -3316,6 +3317,7 @@ static void option_active_branches(const char *branches) static void option_export_marks(const char *marks) { + free(export_marks_file); export_marks_file = make_fast_import_path(marks); } @@ -3357,6 +3359,8 @@ static void option_rewrite_submodules(const char *arg, struct string_list *list) free(f); string_list_insert(list, s)->util = ms; + + free(s); } static int parse_one_option(const char *option) @@ -3481,8 +3485,8 @@ static void git_pack_config(void) if (!git_config_get_int("pack.indexversion", &indexversion_value)) { pack_idx_opts.version = indexversion_value; if (pack_idx_opts.version > 2) - git_die_config("pack.indexversion", - "bad pack.indexVersion=%"PRIu32, pack_idx_opts.version); + git_die_config(the_repository, "pack.indexversion", + "bad pack.indexVersion=%"PRIu32, pack_idx_opts.version); } if (!git_config_get_ulong("pack.packsizelimit", &packsizelimit_value)) max_packsize = packsizelimit_value; diff --git a/builtin/fetch.c b/builtin/fetch.c index 693f02b958..c297569a47 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -286,7 +286,7 @@ static struct refname_hash_entry *refname_hash_add(struct hashmap *map, return ent; } -static int add_one_refname(const char *refname, +static int add_one_refname(const char *refname, const char *referent UNUSED, const struct object_id *oid, int flag UNUSED, void *cbdata) { @@ -1464,6 +1464,7 @@ static void set_option(struct transport *transport, const char *name, const char static int add_oid(const char *refname UNUSED, + const char *referent UNUSED, const struct object_id *oid, int flags UNUSED, void *cb_data) { diff --git a/builtin/fsck.c b/builtin/fsck.c index d13a226c2e..60f4e6fad9 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -89,13 +89,16 @@ static int objerror(struct object *obj, const char *err) return -1; } -static int fsck_error_func(struct fsck_options *o UNUSED, - const struct object_id *oid, - enum object_type object_type, - enum fsck_msg_type msg_type, - enum fsck_msg_id msg_id UNUSED, - const char *message) +static int fsck_objects_error_func(struct fsck_options *o UNUSED, + void *fsck_report, + enum fsck_msg_type msg_type, + enum fsck_msg_id msg_id UNUSED, + const char *message) { + struct fsck_object_report *report = fsck_report; + const struct object_id *oid = report->oid; + enum object_type object_type = report->object_type; + switch (msg_type) { case FSCK_WARN: /* TRANSLATORS: e.g. warning in tree 01bfda: <more explanation> */ @@ -521,7 +524,7 @@ static int fsck_handle_reflog(const char *logname, void *cb_data) return 0; } -static int fsck_handle_ref(const char *refname, const struct object_id *oid, +static int fsck_handle_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid, int flag UNUSED, void *cb_data UNUSED) { struct object *obj; @@ -576,7 +579,7 @@ static void get_default_heads(void) strbuf_worktree_ref(wt, &ref, "HEAD"); fsck_head_link(ref.buf, &head_points_at, &head_oid); if (head_points_at && !is_null_oid(&head_oid)) - fsck_handle_ref(ref.buf, &head_oid, 0, NULL); + fsck_handle_ref(ref.buf, NULL, &head_oid, 0, NULL); strbuf_release(&ref); if (include_reflogs) @@ -938,7 +941,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) fsck_walk_options.walk = mark_object; fsck_obj_options.walk = mark_used; - fsck_obj_options.error_func = fsck_error_func; + fsck_obj_options.error_func = fsck_objects_error_func; if (check_strict) fsck_obj_options.strict = 1; @@ -1050,7 +1053,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) * and may get overwritten by other calls * while we're examining the index. */ - path = xstrdup(worktree_git_path(wt, "index")); + path = xstrdup(worktree_git_path(the_repository, wt, "index")); read_index_from(&istate, path, get_worktree_git_dir(wt)); fsck_index(&istate, path, wt->is_current); discard_index(&istate); diff --git a/builtin/gc.c b/builtin/gc.c index 72bac2554f..427faf1cfe 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -49,23 +49,7 @@ static const char * const builtin_gc_usage[] = { NULL }; -static int pack_refs = 1; -static int prune_reflogs = 1; -static int cruft_packs = 1; -static unsigned long max_cruft_size; -static int aggressive_depth = 50; -static int aggressive_window = 250; -static int gc_auto_threshold = 6700; -static int gc_auto_pack_limit = 50; -static int detach_auto = 1; static timestamp_t gc_log_expire_time; -static const char *gc_log_expire = "1.day.ago"; -static const char *prune_expire = "2.weeks.ago"; -static const char *prune_worktrees_expire = "3.months.ago"; -static char *repack_filter; -static char *repack_filter_to; -static unsigned long big_pack_threshold; -static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE; static struct strvec reflog = STRVEC_INIT; static struct strvec repack = STRVEC_INIT; @@ -125,13 +109,6 @@ static void process_log_file_at_exit(void) process_log_file(); } -static void process_log_file_on_signal(int signo) -{ - process_log_file(); - sigchain_pop(signo); - raise(signo); -} - static int gc_config_is_timestamp_never(const char *var) { const char *value; @@ -145,37 +122,100 @@ static int gc_config_is_timestamp_never(const char *var) return 0; } -static void gc_config(void) +struct gc_config { + int pack_refs; + int prune_reflogs; + int cruft_packs; + unsigned long max_cruft_size; + int aggressive_depth; + int aggressive_window; + int gc_auto_threshold; + int gc_auto_pack_limit; + int detach_auto; + char *gc_log_expire; + char *prune_expire; + char *prune_worktrees_expire; + char *repack_filter; + char *repack_filter_to; + unsigned long big_pack_threshold; + unsigned long max_delta_cache_size; +}; + +#define GC_CONFIG_INIT { \ + .pack_refs = 1, \ + .prune_reflogs = 1, \ + .cruft_packs = 1, \ + .aggressive_depth = 50, \ + .aggressive_window = 250, \ + .gc_auto_threshold = 6700, \ + .gc_auto_pack_limit = 50, \ + .detach_auto = 1, \ + .gc_log_expire = xstrdup("1.day.ago"), \ + .prune_expire = xstrdup("2.weeks.ago"), \ + .prune_worktrees_expire = xstrdup("3.months.ago"), \ + .max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE, \ +} + +static void gc_config_release(struct gc_config *cfg) +{ + free(cfg->gc_log_expire); + free(cfg->prune_expire); + free(cfg->prune_worktrees_expire); + free(cfg->repack_filter); + free(cfg->repack_filter_to); +} + +static void gc_config(struct gc_config *cfg) { const char *value; + char *owned = NULL; if (!git_config_get_value("gc.packrefs", &value)) { if (value && !strcmp(value, "notbare")) - pack_refs = -1; + cfg->pack_refs = -1; else - pack_refs = git_config_bool("gc.packrefs", value); + cfg->pack_refs = git_config_bool("gc.packrefs", value); } if (gc_config_is_timestamp_never("gc.reflogexpire") && gc_config_is_timestamp_never("gc.reflogexpireunreachable")) - prune_reflogs = 0; + cfg->prune_reflogs = 0; + + git_config_get_int("gc.aggressivewindow", &cfg->aggressive_window); + git_config_get_int("gc.aggressivedepth", &cfg->aggressive_depth); + git_config_get_int("gc.auto", &cfg->gc_auto_threshold); + git_config_get_int("gc.autopacklimit", &cfg->gc_auto_pack_limit); + git_config_get_bool("gc.autodetach", &cfg->detach_auto); + git_config_get_bool("gc.cruftpacks", &cfg->cruft_packs); + git_config_get_ulong("gc.maxcruftsize", &cfg->max_cruft_size); + + if (!repo_config_get_expiry(the_repository, "gc.pruneexpire", &owned)) { + free(cfg->prune_expire); + cfg->prune_expire = owned; + } - git_config_get_int("gc.aggressivewindow", &aggressive_window); - git_config_get_int("gc.aggressivedepth", &aggressive_depth); - git_config_get_int("gc.auto", &gc_auto_threshold); - git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit); - git_config_get_bool("gc.autodetach", &detach_auto); - git_config_get_bool("gc.cruftpacks", &cruft_packs); - git_config_get_ulong("gc.maxcruftsize", &max_cruft_size); - git_config_get_expiry("gc.pruneexpire", &prune_expire); - git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire); - git_config_get_expiry("gc.logexpiry", &gc_log_expire); + if (!repo_config_get_expiry(the_repository, "gc.worktreepruneexpire", &owned)) { + free(cfg->prune_worktrees_expire); + cfg->prune_worktrees_expire = owned; + } - git_config_get_ulong("gc.bigpackthreshold", &big_pack_threshold); - git_config_get_ulong("pack.deltacachesize", &max_delta_cache_size); + if (!repo_config_get_expiry(the_repository, "gc.logexpiry", &owned)) { + free(cfg->gc_log_expire); + cfg->gc_log_expire = owned; + } + + git_config_get_ulong("gc.bigpackthreshold", &cfg->big_pack_threshold); + git_config_get_ulong("pack.deltacachesize", &cfg->max_delta_cache_size); + + if (!git_config_get_string("gc.repackfilter", &owned)) { + free(cfg->repack_filter); + cfg->repack_filter = owned; + } - git_config_get_string("gc.repackfilter", &repack_filter); - git_config_get_string("gc.repackfilterto", &repack_filter_to); + if (!git_config_get_string("gc.repackfilterto", &owned)) { + free(cfg->repack_filter_to); + cfg->repack_filter_to = owned; + } git_config(git_default_config, NULL); } @@ -202,11 +242,15 @@ static enum schedule_priority parse_schedule(const char *value) struct maintenance_run_opts { int auto_flag; + int detach; int quiet; enum schedule_priority schedule; }; +#define MAINTENANCE_RUN_OPTS_INIT { \ + .detach = -1, \ +} -static int pack_refs_condition(void) +static int pack_refs_condition(UNUSED struct gc_config *cfg) { /* * The auto-repacking logic for refs is handled by the ref backends and @@ -216,7 +260,8 @@ static int pack_refs_condition(void) return 1; } -static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts) +static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts, + UNUSED struct gc_config *cfg) { struct child_process cmd = CHILD_PROCESS_INIT; @@ -228,7 +273,7 @@ static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts * return run_command(&cmd); } -static int too_many_loose_objects(void) +static int too_many_loose_objects(struct gc_config *cfg) { /* * Quickly check if a "gc" is needed, by estimating how @@ -247,7 +292,7 @@ static int too_many_loose_objects(void) if (!dir) return 0; - auto_threshold = DIV_ROUND_UP(gc_auto_threshold, 256); + auto_threshold = DIV_ROUND_UP(cfg->gc_auto_threshold, 256); while ((ent = readdir(dir)) != NULL) { if (strspn(ent->d_name, "0123456789abcdef") != hexsz_loose || ent->d_name[hexsz_loose] != '\0') @@ -283,12 +328,12 @@ static struct packed_git *find_base_packs(struct string_list *packs, return base; } -static int too_many_packs(void) +static int too_many_packs(struct gc_config *cfg) { struct packed_git *p; int cnt; - if (gc_auto_pack_limit <= 0) + if (cfg->gc_auto_pack_limit <= 0) return 0; for (cnt = 0, p = get_all_packs(the_repository); p; p = p->next) { @@ -302,7 +347,7 @@ static int too_many_packs(void) */ cnt++; } - return gc_auto_pack_limit < cnt; + return cfg->gc_auto_pack_limit < cnt; } static uint64_t total_ram(void) @@ -336,7 +381,8 @@ static uint64_t total_ram(void) return 0; } -static uint64_t estimate_repack_memory(struct packed_git *pack) +static uint64_t estimate_repack_memory(struct gc_config *cfg, + struct packed_git *pack) { unsigned long nr_objects = repo_approximate_object_count(the_repository); size_t os_cache, heap; @@ -373,7 +419,7 @@ static uint64_t estimate_repack_memory(struct packed_git *pack) */ heap += delta_base_cache_limit; /* and of course pack-objects has its own delta cache */ - heap += max_delta_cache_size; + heap += cfg->max_delta_cache_size; return os_cache + heap; } @@ -384,30 +430,31 @@ static int keep_one_pack(struct string_list_item *item, void *data UNUSED) return 0; } -static void add_repack_all_option(struct string_list *keep_pack) +static void add_repack_all_option(struct gc_config *cfg, + struct string_list *keep_pack) { - if (prune_expire && !strcmp(prune_expire, "now")) + if (cfg->prune_expire && !strcmp(cfg->prune_expire, "now")) strvec_push(&repack, "-a"); - else if (cruft_packs) { + else if (cfg->cruft_packs) { strvec_push(&repack, "--cruft"); - if (prune_expire) - strvec_pushf(&repack, "--cruft-expiration=%s", prune_expire); - if (max_cruft_size) + if (cfg->prune_expire) + strvec_pushf(&repack, "--cruft-expiration=%s", cfg->prune_expire); + if (cfg->max_cruft_size) strvec_pushf(&repack, "--max-cruft-size=%lu", - max_cruft_size); + cfg->max_cruft_size); } else { strvec_push(&repack, "-A"); - if (prune_expire) - strvec_pushf(&repack, "--unpack-unreachable=%s", prune_expire); + if (cfg->prune_expire) + strvec_pushf(&repack, "--unpack-unreachable=%s", cfg->prune_expire); } if (keep_pack) for_each_string_list(keep_pack, keep_one_pack, NULL); - if (repack_filter && *repack_filter) - strvec_pushf(&repack, "--filter=%s", repack_filter); - if (repack_filter_to && *repack_filter_to) - strvec_pushf(&repack, "--filter-to=%s", repack_filter_to); + if (cfg->repack_filter && *cfg->repack_filter) + strvec_pushf(&repack, "--filter=%s", cfg->repack_filter); + if (cfg->repack_filter_to && *cfg->repack_filter_to) + strvec_pushf(&repack, "--filter-to=%s", cfg->repack_filter_to); } static void add_repack_incremental_option(void) @@ -415,13 +462,13 @@ static void add_repack_incremental_option(void) strvec_push(&repack, "--no-write-bitmap-index"); } -static int need_to_gc(void) +static int need_to_gc(struct gc_config *cfg) { /* * Setting gc.auto to 0 or negative can disable the * automatic gc. */ - if (gc_auto_threshold <= 0) + if (cfg->gc_auto_threshold <= 0) return 0; /* @@ -430,13 +477,13 @@ static int need_to_gc(void) * we run "repack -A -d -l". Otherwise we tell the caller * there is no need. */ - if (too_many_packs()) { + if (too_many_packs(cfg)) { struct string_list keep_pack = STRING_LIST_INIT_NODUP; - if (big_pack_threshold) { - find_base_packs(&keep_pack, big_pack_threshold); - if (keep_pack.nr >= gc_auto_pack_limit) { - big_pack_threshold = 0; + if (cfg->big_pack_threshold) { + find_base_packs(&keep_pack, cfg->big_pack_threshold); + if (keep_pack.nr >= cfg->gc_auto_pack_limit) { + cfg->big_pack_threshold = 0; string_list_clear(&keep_pack, 0); find_base_packs(&keep_pack, 0); } @@ -445,7 +492,7 @@ static int need_to_gc(void) uint64_t mem_have, mem_want; mem_have = total_ram(); - mem_want = estimate_repack_memory(p); + mem_want = estimate_repack_memory(cfg, p); /* * Only allow 1/2 of memory for pack-objects, leave @@ -456,14 +503,14 @@ static int need_to_gc(void) string_list_clear(&keep_pack, 0); } - add_repack_all_option(&keep_pack); + add_repack_all_option(cfg, &keep_pack); string_list_clear(&keep_pack, 0); - } else if (too_many_loose_objects()) + } else if (too_many_loose_objects(cfg)) add_repack_incremental_option(); else return 0; - if (run_hooks("pre-auto-gc")) + if (run_hooks(the_repository, "pre-auto-gc")) return 0; return 1; } @@ -585,7 +632,8 @@ done: return ret; } -static void gc_before_repack(struct maintenance_run_opts *opts) +static void gc_before_repack(struct maintenance_run_opts *opts, + struct gc_config *cfg) { /* * We may be called twice, as both the pre- and @@ -596,10 +644,10 @@ static void gc_before_repack(struct maintenance_run_opts *opts) if (done++) return; - if (pack_refs && maintenance_task_pack_refs(opts)) + if (cfg->pack_refs && maintenance_task_pack_refs(opts, cfg)) die(FAILED_RUN, "pack-refs"); - if (prune_reflogs) { + if (cfg->prune_reflogs) { struct child_process cmd = CHILD_PROCESS_INIT; cmd.git_cmd = 1; @@ -620,19 +668,25 @@ int cmd_gc(int argc, const char **argv, const char *prefix) int keep_largest_pack = -1; timestamp_t dummy; struct child_process rerere_cmd = CHILD_PROCESS_INIT; - struct maintenance_run_opts opts = {0}; + struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT; + struct gc_config cfg = GC_CONFIG_INIT; + const char *prune_expire_sentinel = "sentinel"; + const char *prune_expire_arg = prune_expire_sentinel; + int ret; struct option builtin_gc_options[] = { OPT__QUIET(&quiet, N_("suppress progress reporting")), - { OPTION_STRING, 0, "prune", &prune_expire, N_("date"), + { OPTION_STRING, 0, "prune", &prune_expire_arg, N_("date"), N_("prune unreferenced objects"), - PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire }, - OPT_BOOL(0, "cruft", &cruft_packs, N_("pack unreferenced objects separately")), - OPT_MAGNITUDE(0, "max-cruft-size", &max_cruft_size, + PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire_arg }, + OPT_BOOL(0, "cruft", &cfg.cruft_packs, N_("pack unreferenced objects separately")), + OPT_MAGNITUDE(0, "max-cruft-size", &cfg.max_cruft_size, N_("with --cruft, limit the size of new cruft packs")), OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")), OPT_BOOL_F(0, "auto", &opts.auto_flag, N_("enable auto-gc mode"), PARSE_OPT_NOCOMPLETE), + OPT_BOOL(0, "detach", &opts.detach, + N_("perform garbage collection in the background")), OPT_BOOL_F(0, "force", &force, N_("force running gc even if there may be another gc running"), PARSE_OPT_NOCOMPLETE), @@ -650,84 +704,103 @@ int cmd_gc(int argc, const char **argv, const char *prefix) strvec_pushl(&prune_worktrees, "worktree", "prune", "--expire", NULL); strvec_pushl(&rerere, "rerere", "gc", NULL); - /* default expiry time, overwritten in gc_config */ - gc_config(); - if (parse_expiry_date(gc_log_expire, &gc_log_expire_time)) - die(_("failed to parse gc.logExpiry value %s"), gc_log_expire); + gc_config(&cfg); - if (pack_refs < 0) - pack_refs = !is_bare_repository(); + if (parse_expiry_date(cfg.gc_log_expire, &gc_log_expire_time)) + die(_("failed to parse gc.logExpiry value %s"), cfg.gc_log_expire); + + if (cfg.pack_refs < 0) + cfg.pack_refs = !is_bare_repository(); argc = parse_options(argc, argv, prefix, builtin_gc_options, builtin_gc_usage, 0); if (argc > 0) usage_with_options(builtin_gc_usage, builtin_gc_options); - if (prune_expire && parse_expiry_date(prune_expire, &dummy)) - die(_("failed to parse prune expiry value %s"), prune_expire); + if (prune_expire_arg != prune_expire_sentinel) { + free(cfg.prune_expire); + cfg.prune_expire = xstrdup_or_null(prune_expire_arg); + } + if (cfg.prune_expire && parse_expiry_date(cfg.prune_expire, &dummy)) + die(_("failed to parse prune expiry value %s"), cfg.prune_expire); if (aggressive) { strvec_push(&repack, "-f"); - if (aggressive_depth > 0) - strvec_pushf(&repack, "--depth=%d", aggressive_depth); - if (aggressive_window > 0) - strvec_pushf(&repack, "--window=%d", aggressive_window); + if (cfg.aggressive_depth > 0) + strvec_pushf(&repack, "--depth=%d", cfg.aggressive_depth); + if (cfg.aggressive_window > 0) + strvec_pushf(&repack, "--window=%d", cfg.aggressive_window); } if (quiet) strvec_push(&repack, "-q"); if (opts.auto_flag) { + if (cfg.detach_auto && opts.detach < 0) + opts.detach = 1; + /* * Auto-gc should be least intrusive as possible. */ - if (!need_to_gc()) - return 0; + if (!need_to_gc(&cfg)) { + ret = 0; + goto out; + } + if (!quiet) { - if (detach_auto) + if (opts.detach > 0) fprintf(stderr, _("Auto packing the repository in background for optimum performance.\n")); else fprintf(stderr, _("Auto packing the repository for optimum performance.\n")); fprintf(stderr, _("See \"git help gc\" for manual housekeeping.\n")); } - if (detach_auto) { - int ret = report_last_gc_error(); - - if (ret == 1) - /* Last gc --auto failed. Skip this one. */ - return 0; - else if (ret) - /* an I/O error occurred, already reported */ - return ret; - - if (lock_repo_for_gc(force, &pid)) - return 0; - gc_before_repack(&opts); /* dies on failure */ - delete_tempfile(&pidfile); - - /* - * failure to daemonize is ok, we'll continue - * in foreground - */ - daemonized = !daemonize(); - } } else { struct string_list keep_pack = STRING_LIST_INIT_NODUP; if (keep_largest_pack != -1) { if (keep_largest_pack) find_base_packs(&keep_pack, 0); - } else if (big_pack_threshold) { - find_base_packs(&keep_pack, big_pack_threshold); + } else if (cfg.big_pack_threshold) { + find_base_packs(&keep_pack, cfg.big_pack_threshold); } - add_repack_all_option(&keep_pack); + add_repack_all_option(&cfg, &keep_pack); string_list_clear(&keep_pack, 0); } + if (opts.detach > 0) { + ret = report_last_gc_error(); + if (ret == 1) { + /* Last gc --auto failed. Skip this one. */ + ret = 0; + goto out; + + } else if (ret) { + /* an I/O error occurred, already reported */ + goto out; + } + + if (lock_repo_for_gc(force, &pid)) { + ret = 0; + goto out; + } + + gc_before_repack(&opts, &cfg); /* dies on failure */ + delete_tempfile(&pidfile); + + /* + * failure to daemonize is ok, we'll continue + * in foreground + */ + daemonized = !daemonize(); + } + name = lock_repo_for_gc(force, &pid); if (name) { - if (opts.auto_flag) - return 0; /* be quiet on --auto */ + if (opts.auto_flag) { + ret = 0; + goto out; /* be quiet on --auto */ + } + die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"), name, (uintmax_t)pid); } @@ -737,11 +810,10 @@ int cmd_gc(int argc, const char **argv, const char *prefix) git_path("gc.log"), LOCK_DIE_ON_ERROR); dup2(get_lock_file_fd(&log_lock), 2); - sigchain_push_common(process_log_file_on_signal); atexit(process_log_file_at_exit); } - gc_before_repack(&opts); + gc_before_repack(&opts, &cfg); if (!repository_format_precious_objects) { struct child_process repack_cmd = CHILD_PROCESS_INIT; @@ -752,11 +824,11 @@ int cmd_gc(int argc, const char **argv, const char *prefix) if (run_command(&repack_cmd)) die(FAILED_RUN, repack.v[0]); - if (prune_expire) { + if (cfg.prune_expire) { struct child_process prune_cmd = CHILD_PROCESS_INIT; /* run `git prune` even if using cruft packs */ - strvec_push(&prune, prune_expire); + strvec_push(&prune, cfg.prune_expire); if (quiet) strvec_push(&prune, "--no-progress"); if (repo_has_promisor_remote(the_repository)) @@ -769,10 +841,10 @@ int cmd_gc(int argc, const char **argv, const char *prefix) } } - if (prune_worktrees_expire) { + if (cfg.prune_worktrees_expire) { struct child_process prune_worktrees_cmd = CHILD_PROCESS_INIT; - strvec_push(&prune_worktrees, prune_worktrees_expire); + strvec_push(&prune_worktrees, cfg.prune_worktrees_expire); prune_worktrees_cmd.git_cmd = 1; strvec_pushv(&prune_worktrees_cmd.args, prune_worktrees.v); if (run_command(&prune_worktrees_cmd)) @@ -796,13 +868,15 @@ int cmd_gc(int argc, const char **argv, const char *prefix) !quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0, NULL); - if (opts.auto_flag && too_many_loose_objects()) + if (opts.auto_flag && too_many_loose_objects(&cfg)) warning(_("There are too many unreachable loose objects; " "run 'git prune' to remove them.")); if (!daemonized) unlink(git_path("gc.log")); +out: + gc_config_release(&cfg); return 0; } @@ -836,6 +910,7 @@ struct cg_auto_data { }; static int dfs_on_ref(const char *refname UNUSED, + const char *referent UNUSED, const struct object_id *oid, int flags UNUSED, void *cb_data) @@ -892,7 +967,7 @@ static int dfs_on_ref(const char *refname UNUSED, return result; } -static int should_write_commit_graph(void) +static int should_write_commit_graph(struct gc_config *cfg) { int result; struct cg_auto_data data; @@ -929,7 +1004,8 @@ static int run_write_commit_graph(struct maintenance_run_opts *opts) return !!run_command(&child); } -static int maintenance_task_commit_graph(struct maintenance_run_opts *opts) +static int maintenance_task_commit_graph(struct maintenance_run_opts *opts, + struct gc_config *cfg) { prepare_repo_settings(the_repository); if (!the_repository->settings.core_commit_graph) @@ -963,7 +1039,8 @@ static int fetch_remote(struct remote *remote, void *cbdata) return !!run_command(&child); } -static int maintenance_task_prefetch(struct maintenance_run_opts *opts) +static int maintenance_task_prefetch(struct maintenance_run_opts *opts, + struct gc_config *cfg) { if (for_each_remote(fetch_remote, opts)) { error(_("failed to prefetch remotes")); @@ -973,7 +1050,8 @@ static int maintenance_task_prefetch(struct maintenance_run_opts *opts) return 0; } -static int maintenance_task_gc(struct maintenance_run_opts *opts) +static int maintenance_task_gc(struct maintenance_run_opts *opts, + struct gc_config *cfg) { struct child_process child = CHILD_PROCESS_INIT; @@ -986,6 +1064,7 @@ static int maintenance_task_gc(struct maintenance_run_opts *opts) strvec_push(&child.args, "--quiet"); else strvec_push(&child.args, "--no-quiet"); + strvec_push(&child.args, "--no-detach"); return run_command(&child); } @@ -1021,7 +1100,7 @@ static int loose_object_count(const struct object_id *oid UNUSED, return 0; } -static int loose_object_auto_condition(void) +static int loose_object_auto_condition(struct gc_config *cfg) { int count = 0; @@ -1081,6 +1160,12 @@ static int pack_loose(struct maintenance_run_opts *opts) pack_proc.in = -1; + /* + * git-pack-objects(1) ends up writing the pack hash to stdout, which + * we do not care for. + */ + pack_proc.out = -1; + if (start_command(&pack_proc)) { error(_("failed to start 'git pack-objects' process")); return 1; @@ -1106,12 +1191,13 @@ static int pack_loose(struct maintenance_run_opts *opts) return result; } -static int maintenance_task_loose_objects(struct maintenance_run_opts *opts) +static int maintenance_task_loose_objects(struct maintenance_run_opts *opts, + struct gc_config *cfg) { return prune_packed(opts) || pack_loose(opts); } -static int incremental_repack_auto_condition(void) +static int incremental_repack_auto_condition(struct gc_config *cfg) { struct packed_git *p; int incremental_repack_auto_limit = 10; @@ -1230,7 +1316,8 @@ static int multi_pack_index_repack(struct maintenance_run_opts *opts) return 0; } -static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts) +static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts, + struct gc_config *cfg) { prepare_repo_settings(the_repository); if (!the_repository->settings.core_multi_pack_index) { @@ -1247,14 +1334,15 @@ static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts return 0; } -typedef int maintenance_task_fn(struct maintenance_run_opts *opts); +typedef int maintenance_task_fn(struct maintenance_run_opts *opts, + struct gc_config *cfg); /* * An auto condition function returns 1 if the task should run * and 0 if the task should NOT run. See needs_to_gc() for an * example. */ -typedef int maintenance_auto_fn(void); +typedef int maintenance_auto_fn(struct gc_config *cfg); struct maintenance_task { const char *name; @@ -1321,7 +1409,8 @@ static int compare_tasks_by_selection(const void *a_, const void *b_) return b->selected_order - a->selected_order; } -static int maintenance_run_tasks(struct maintenance_run_opts *opts) +static int maintenance_run_tasks(struct maintenance_run_opts *opts, + struct gc_config *cfg) { int i, found_selected = 0; int result = 0; @@ -1345,6 +1434,13 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts) } free(lock_path); + /* Failure to daemonize is ok, we'll continue in foreground. */ + if (opts->detach > 0) { + trace2_region_enter("maintenance", "detach", the_repository); + daemonize(); + trace2_region_leave("maintenance", "detach", the_repository); + } + for (i = 0; !found_selected && i < TASK__COUNT; i++) found_selected = tasks[i].selected_order >= 0; @@ -1360,14 +1456,14 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts) if (opts->auto_flag && (!tasks[i].auto_condition || - !tasks[i].auto_condition())) + !tasks[i].auto_condition(cfg))) continue; if (opts->schedule && tasks[i].schedule < opts->schedule) continue; trace2_region_enter("maintenance", tasks[i].name, r); - if (tasks[i].fn(opts)) { + if (tasks[i].fn(opts, cfg)) { error(_("task '%s' failed"), tasks[i].name); result = 1; } @@ -1404,7 +1500,6 @@ static void initialize_task_config(int schedule) { int i; struct strbuf config_name = STRBUF_INIT; - gc_config(); if (schedule) initialize_maintenance_strategy(); @@ -1467,10 +1562,13 @@ static int task_option_parse(const struct option *opt UNUSED, static int maintenance_run(int argc, const char **argv, const char *prefix) { int i; - struct maintenance_run_opts opts; + struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT; + struct gc_config cfg = GC_CONFIG_INIT; struct option builtin_maintenance_run_options[] = { OPT_BOOL(0, "auto", &opts.auto_flag, N_("run tasks based on the state of the repository")), + OPT_BOOL(0, "detach", &opts.detach, + N_("perform maintenance in the background")), OPT_CALLBACK(0, "schedule", &opts.schedule, N_("frequency"), N_("run tasks based on frequency"), maintenance_opt_schedule), @@ -1481,7 +1579,7 @@ static int maintenance_run(int argc, const char **argv, const char *prefix) PARSE_OPT_NONEG, task_option_parse), OPT_END() }; - memset(&opts, 0, sizeof(opts)); + int ret; opts.quiet = !isatty(2); @@ -1496,12 +1594,16 @@ static int maintenance_run(int argc, const char **argv, const char *prefix) if (opts.auto_flag && opts.schedule) die(_("use at most one of --auto and --schedule=<frequency>")); + gc_config(&cfg); initialize_task_config(opts.schedule); if (argc != 0) usage_with_options(builtin_maintenance_run_usage, builtin_maintenance_run_options); - return maintenance_run_tasks(&opts); + + ret = maintenance_run_tasks(&opts, &cfg); + gc_config_release(&cfg); + return ret; } static char *get_maintpath(void) diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c index 66a7389f9f..7195a072ed 100644 --- a/builtin/get-tar-commit-id.c +++ b/builtin/get-tar-commit-id.c @@ -35,6 +35,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv UNUSED, const char *prefix if (header->typeflag[0] != TYPEFLAG_GLOBAL_HEADER) return 1; + errno = 0; len = strtol(content, &end, 10); if (errno == ERANGE || end == content || len < 0) return 1; diff --git a/builtin/hook.c b/builtin/hook.c index 5234693a94..cc37438fde 100644 --- a/builtin/hook.c +++ b/builtin/hook.c @@ -58,7 +58,7 @@ static int run(int argc, const char **argv, const char *prefix) hook_name = argv[0]; if (!ignore_missing) opt.error_if_missing = 1; - ret = run_hooks_opt(hook_name, &opt); + ret = run_hooks_opt(the_repository, hook_name, &opt); if (ret < 0) /* error() return */ ret = 1; return ret; diff --git a/builtin/log.c b/builtin/log.c index 4d4b60caa7..36769bab3b 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -707,6 +707,7 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c write_or_die(1, buf, size); object_context_release(&obj_context); + free(buf); return 0; } @@ -1434,6 +1435,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file, int need_8bit_cte = 0; struct pretty_print_context pp = {0}; struct commit *head = list[0]; + char *to_free = NULL; if (!cmit_fmt_is_mail(rev->commit_format)) die(_("cover letter needs email format")); @@ -1455,7 +1457,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file, } if (!branch_name) - branch_name = find_branch_name(rev); + branch_name = to_free = find_branch_name(rev); pp.fmt = CMIT_FMT_EMAIL; pp.date_mode.type = DATE_RFC2822; @@ -1466,6 +1468,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file, encoding, need_8bit_cte, cfg); fprintf(rev->diffopt.file, "%s\n", sb.buf); + free(to_free); free(pp.after_subject); strbuf_release(&sb); @@ -1825,12 +1828,14 @@ static struct commit *get_base_commit(const struct format_config *cfg, if (die_on_failure) { die(_("failed to find exact merge base")); } else { + free_commit_list(merge_base); free(rev); return NULL; } } rev[i] = merge_base->item; + free_commit_list(merge_base); } if (rev_nr % 2) @@ -2021,6 +2026,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) const char *rfc = NULL; int creation_factor = -1; const char *signature = git_version_string; + char *signature_to_free = NULL; char *signature_file_arg = NULL; struct keep_callback_data keep_callback_data = { .cfg = &cfg, @@ -2441,7 +2447,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (strbuf_read_file(&buf, signature_file, 128) < 0) die_errno(_("unable to read signature file '%s'"), signature_file); - signature = strbuf_detach(&buf, NULL); + signature = signature_to_free = strbuf_detach(&buf, NULL); } else if (cfg.signature) { signature = cfg.signature; } @@ -2546,12 +2552,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) else print_signature(signature, rev.diffopt.file); } - if (output_directory) + if (output_directory) { fclose(rev.diffopt.file); + rev.diffopt.file = NULL; + } } stop_progress(&progress); free(list); - free(branch_name); if (ignore_if_in_upstream) free_patch_ids(&ids); @@ -2563,11 +2570,14 @@ done: strbuf_release(&rdiff_title); free(description_file); free(signature_file_arg); + free(signature_to_free); + free(branch_name); free(to_free); free(rev.message_id); if (rev.ref_message_ids) string_list_clear(rev.ref_message_ids, 0); free(rev.ref_message_ids); + rev.diffopt.no_free = 0; release_revisions(&rev); format_config_release(&cfg); return 0; diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c index debf2d4f88..0a491595ca 100644 --- a/builtin/ls-remote.c +++ b/builtin/ls-remote.c @@ -19,17 +19,16 @@ static const char * const ls_remote_usage[] = { * Is there one among the list of patterns that match the tail part * of the path? */ -static int tail_match(const char **pattern, const char *path) +static int tail_match(const struct strvec *pattern, const char *path) { - const char *p; char *pathbuf; - if (!pattern) + if (!pattern->nr) return 1; /* no restriction */ pathbuf = xstrfmt("/%s", path); - while ((p = *(pattern++)) != NULL) { - if (!wildmatch(p, pathbuf, 0)) { + for (size_t i = 0; i < pattern->nr; i++) { + if (!wildmatch(pattern->v[i], pathbuf, 0)) { free(pathbuf); return 1; } @@ -47,7 +46,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) int status = 0; int show_symref_target = 0; const char *uploadpack = NULL; - const char **pattern = NULL; + struct strvec pattern = STRVEC_INIT; struct transport_ls_refs_options transport_options = TRANSPORT_LS_REFS_OPTIONS_INIT; int i; @@ -91,15 +90,25 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) PARSE_OPT_STOP_AT_NON_OPTION); dest = argv[0]; + /* + * TODO: This is buggy, but required for transport helpers. When a + * transport helper advertises a "refspec", then we'd add that to a + * list of refspecs via `refspec_append()`, which transitively depends + * on `the_hash_algo`. Thus, when the hash algorithm isn't properly set + * up, this would lead to a segfault. + * + * We really should fix this in the transport helper logic such that we + * lazily parse refspec capabilities _after_ we have learned about the + * remote's object format. Otherwise, we may end up misparsing refspecs + * depending on what object hash the remote uses. + */ + if (!the_repository->hash_algo) + repo_set_hash_algo(the_repository, GIT_HASH_SHA1); + packet_trace_identity("ls-remote"); - if (argc > 1) { - int i; - CALLOC_ARRAY(pattern, argc); - for (i = 1; i < argc; i++) { - pattern[i - 1] = xstrfmt("*/%s", argv[i]); - } - } + for (int i = 1; i < argc; i++) + strvec_pushf(&pattern, "*/%s", argv[i]); if (flags & REF_TAGS) strvec_push(&transport_options.ref_prefixes, "refs/tags/"); @@ -136,7 +145,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) struct ref_array_item *item; if (!check_ref_type(ref, flags)) continue; - if (!tail_match(pattern, ref->name)) + if (!tail_match(&pattern, ref->name)) continue; item = ref_array_push(&ref_array, ref->name, &ref->old_oid); item->symref = xstrdup_or_null(ref->symref); @@ -158,5 +167,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) if (transport_disconnect(transport)) status = 1; transport_ls_refs_options_release(&transport_options); + + strvec_clear(&pattern); return status; } diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c index 82bebea15b..e951b09805 100644 --- a/builtin/merge-recursive.c +++ b/builtin/merge-recursive.c @@ -31,7 +31,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix UNUSED) char *better1, *better2; struct commit *result; - init_merge_options(&o, the_repository); + init_basic_merge_options(&o, the_repository); if (argv[0] && ends_with(argv[0], "-subtree")) o.subtree_shift = ""; diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index dab2fdc2a6..9bca9b5f33 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -571,7 +571,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix) }; /* Init merge options */ - init_merge_options(&o.merge_options, the_repository); + init_ui_merge_options(&o.merge_options, the_repository); /* Parse arguments */ original_argc = argc - 1; /* ignoring argv[0] */ diff --git a/builtin/merge.c b/builtin/merge.c index 9fba27d85d..662a49a0e8 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -478,7 +478,7 @@ static void finish(struct commit *head_commit, } /* Run a post-merge hook */ - run_hooks_l("post-merge", squash ? "1" : "0", NULL); + run_hooks_l(the_repository, "post-merge", squash ? "1" : "0", NULL); if (new_head) apply_autostash_ref(the_repository, "MERGE_AUTOSTASH"); @@ -724,7 +724,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, return 2; } - init_merge_options(&o, the_repository); + init_ui_merge_options(&o, the_repository); if (!strcmp(strategy, "subtree")) o.subtree_shift = ""; diff --git a/builtin/mktag.c b/builtin/mktag.c index 4767f1a97e..c6b644219f 100644 --- a/builtin/mktag.c +++ b/builtin/mktag.c @@ -18,8 +18,7 @@ static int option_strict = 1; static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT; static int mktag_fsck_error_func(struct fsck_options *o UNUSED, - const struct object_id *oid UNUSED, - enum object_type object_type UNUSED, + void *fsck_report UNUSED, enum fsck_msg_type msg_type, enum fsck_msg_id msg_id UNUSED, const char *message) diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c index 9cf1a32d65..8805cbbeb3 100644 --- a/builtin/multi-pack-index.c +++ b/builtin/multi-pack-index.c @@ -129,6 +129,8 @@ static int cmd_multi_pack_index_write(int argc, const char **argv, MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX), OPT_BIT(0, "progress", &opts.flags, N_("force progress reporting"), MIDX_PROGRESS), + OPT_BIT(0, "incremental", &opts.flags, + N_("write a new incremental MIDX"), MIDX_WRITE_INCREMENTAL), OPT_BOOL(0, "stdin-packs", &opts.stdin_packs, N_("write multi-pack index containing only given indexes")), OPT_FILENAME(0, "refs-snapshot", &opts.refs_snapshot, diff --git a/builtin/name-rev.c b/builtin/name-rev.c index 70e9ec4e47..a468ef84c3 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -337,7 +337,7 @@ static int cmp_by_tag_and_age(const void *a_, const void *b_) return a->taggerdate != b->taggerdate; } -static int name_ref(const char *path, const struct object_id *oid, +static int name_ref(const char *path, const char *referent UNUSED, const struct object_id *oid, int flags UNUSED, void *cb_data) { struct object *o = parse_object(the_repository, oid); @@ -677,7 +677,9 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix) always, allow_undefined, data.name_only); } - UNLEAK(string_pool); - UNLEAK(revs); + string_list_clear(&data.ref_filters, 0); + string_list_clear(&data.exclude_filters, 0); + mem_pool_discard(&string_pool, 0); + object_array_clear(&revs); return 0; } diff --git a/builtin/notes.c b/builtin/notes.c index d9c356e354..04f9dfb7fb 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -114,7 +114,6 @@ struct note_msg { }; struct note_data { - int given; int use_editor; int stripspace; char *edit_path; @@ -193,7 +192,7 @@ static void write_commented_object(int fd, const struct object_id *object) static void prepare_note_data(const struct object_id *object, struct note_data *d, const struct object_id *old_note) { - if (d->use_editor || !d->given) { + if (d->use_editor || !d->msg_nr) { int fd; struct strbuf buf = STRBUF_INIT; @@ -201,7 +200,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data * d->edit_path = git_pathdup("NOTES_EDITMSG"); fd = xopen(d->edit_path, O_CREAT | O_TRUNC | O_WRONLY, 0600); - if (d->given) + if (d->msg_nr) write_or_die(fd, d->buf.buf, d->buf.len); else if (old_note) copy_obj_to_fd(fd, old_note); @@ -515,7 +514,6 @@ static int add(int argc, const char **argv, const char *prefix) if (d.msg_nr) concat_messages(&d); - d.given = !!d.buf.len; object_ref = argc > 1 ? argv[1] : "HEAD"; @@ -528,7 +526,7 @@ static int add(int argc, const char **argv, const char *prefix) if (note) { if (!force) { free_notes(t); - if (d.given) { + if (d.msg_nr) { free_note_data(&d); return error(_("Cannot add notes. " "Found existing notes for object %s. " @@ -690,14 +688,14 @@ static int append_edit(int argc, const char **argv, const char *prefix) usage_with_options(usage, options); } - if (d.msg_nr) + if (d.msg_nr) { concat_messages(&d); - d.given = !!d.buf.len; - - if (d.given && edit) - fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated " - "for the 'edit' subcommand.\n" - "Please use 'git notes add -f -m/-F/-c/-C' instead.\n")); + if (edit) + fprintf(stderr, _("The -m/-F/-c/-C options have been " + "deprecated for the 'edit' subcommand.\n" + "Please use 'git notes add -f -m/-F/-c/-C' " + "instead.\n")); + } object_ref = 1 < argc ? argv[1] : "HEAD"; @@ -807,7 +805,7 @@ static int merge_commit(struct notes_merge_options *o) { struct strbuf msg = STRBUF_INIT; struct object_id oid, parent_oid; - struct notes_tree *t; + struct notes_tree t = {0}; struct commit *partial; struct pretty_print_context pretty_ctx; void *local_ref_to_free; @@ -830,8 +828,7 @@ static int merge_commit(struct notes_merge_options *o) else oidclr(&parent_oid, the_repository->hash_algo); - CALLOC_ARRAY(t, 1); - init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0); + init_notes(&t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0); o->local_ref = local_ref_to_free = refs_resolve_refdup(get_main_ref_store(the_repository), @@ -839,7 +836,7 @@ static int merge_commit(struct notes_merge_options *o) if (!o->local_ref) die(_("failed to resolve NOTES_MERGE_REF")); - if (notes_merge_commit(o, t, partial, &oid)) + if (notes_merge_commit(o, &t, partial, &oid)) die(_("failed to finalize notes merge")); /* Reuse existing commit message in reflog message */ @@ -853,7 +850,7 @@ static int merge_commit(struct notes_merge_options *o) is_null_oid(&parent_oid) ? NULL : &parent_oid, 0, UPDATE_REFS_DIE_ON_ERR); - free_notes(t); + free_notes(&t); strbuf_release(&msg); ret = merge_abort(o); free(local_ref_to_free); @@ -868,7 +865,7 @@ static int git_config_get_notes_strategy(const char *key, if (git_config_get_string(key, &value)) return 1; if (parse_notes_merge_strategy(value, strategy)) - git_die_config(key, _("unknown notes merge strategy %s"), value); + git_die_config(the_repository, key, _("unknown notes merge strategy %s"), value); free(value); return 0; diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index f395488971..778be80f56 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -771,7 +771,7 @@ static enum write_one_status write_one(struct hashfile *f, return WRITE_ONE_WRITTEN; } -static int mark_tagged(const char *path UNUSED, const struct object_id *oid, +static int mark_tagged(const char *path UNUSED, const char *referent UNUSED, const struct object_id *oid, int flag UNUSED, void *cb_data UNUSED) { struct object_id peeled; @@ -1342,10 +1342,10 @@ static void write_pack_file(void) if (write_bitmap_index) { bitmap_writer_init(&bitmap_writer, - the_repository); + the_repository, &to_pack); bitmap_writer_set_checksum(&bitmap_writer, hash); bitmap_writer_build_type_index(&bitmap_writer, - &to_pack, written_list, nr_written); + written_list); } if (cruft) @@ -1367,10 +1367,10 @@ static void write_pack_file(void) bitmap_writer_select_commits(&bitmap_writer, indexed_commits, indexed_commits_nr); - if (bitmap_writer_build(&bitmap_writer, &to_pack) < 0) + if (bitmap_writer_build(&bitmap_writer) < 0) die(_("failed to write bitmap index")); bitmap_writer_finish(&bitmap_writer, - written_list, nr_written, + written_list, tmpname.buf, write_bitmap_options); bitmap_writer_free(&bitmap_writer); write_bitmap_index = 0; @@ -3129,7 +3129,7 @@ static void add_tag_chain(const struct object_id *oid) } } -static int add_ref_tag(const char *tag UNUSED, const struct object_id *oid, +static int add_ref_tag(const char *tag UNUSED, const char *referent UNUSED, const struct object_id *oid, int flag UNUSED, void *cb_data UNUSED) { struct object_id peeled; @@ -4076,6 +4076,7 @@ static void record_recent_commit(struct commit *commit, void *data UNUSED) } static int mark_bitmap_preferred_tip(const char *refname, + const char *referent UNUSED, const struct object_id *oid, int flags UNUSED, void *data UNUSED) diff --git a/builtin/patch-id.c b/builtin/patch-id.c index d790ae6354..35c1179f7e 100644 --- a/builtin/patch-id.c +++ b/builtin/patch-id.c @@ -7,10 +7,9 @@ #include "parse-options.h" #include "setup.h" -static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result) +static void flush_current_id(struct object_id *id, struct object_id *result) { - if (patchlen) - printf("%s %s\n", oid_to_hex(result), oid_to_hex(id)); + printf("%s %s\n", oid_to_hex(result), oid_to_hex(id)); } static int remove_space(char *line) @@ -60,9 +59,27 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after) return 1; } +/* + * flag bits to control get_one_patchid()'s behaviour. + * + * STABLE/VERBATIM are given from the command line option as + * --stable/--verbatim. FIND_HEADER conveys the internal state + * maintained by the caller to allow the function to avoid mistaking + * lines of log message before seeing the "diff" part as the beginning + * of the next patch. + */ +enum { + GOPID_STABLE = (1<<0), /* --stable */ + GOPID_VERBATIM = (1<<1), /* --verbatim */ + GOPID_FIND_HEADER = (1<<2), /* stop at the beginning of patch message */ +}; + static int get_one_patchid(struct object_id *next_oid, struct object_id *result, - struct strbuf *line_buf, int stable, int verbatim) + struct strbuf *line_buf, unsigned flags) { + int stable = flags & GOPID_STABLE; + int verbatim = flags & GOPID_VERBATIM; + int find_header = flags & GOPID_FIND_HEADER; int patchlen = 0, found_next = 0; int before = -1, after = -1; int diff_is_binary = 0; @@ -77,24 +94,40 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result, const char *p = line; int len; - /* Possibly skip over the prefix added by "log" or "format-patch" */ - if (!skip_prefix(line, "commit ", &p) && - !skip_prefix(line, "From ", &p) && - starts_with(line, "\\ ") && 12 < strlen(line)) { - if (verbatim) - the_hash_algo->update_fn(&ctx, line, strlen(line)); - continue; - } - - if (!get_oid_hex(p, next_oid)) { - found_next = 1; - break; + /* + * The caller hasn't seen us find a patch header and + * return to it, or we have started processing patch + * and may encounter the beginning of the next patch. + */ + if (find_header) { + /* + * If we see a line that begins with "<object name>", + * "commit <object name>" or "From <object name>", it is + * the beginning of a patch. Return to the caller, as + * we are done with the one we have been processing. + */ + if (skip_prefix(line, "commit ", &p)) + ; + else if (skip_prefix(line, "From ", &p)) + ; + if (!get_oid_hex(p, next_oid)) { + if (verbatim) + the_hash_algo->update_fn(&ctx, line, strlen(line)); + found_next = 1; + break; + } } /* Ignore commit comments */ if (!patchlen && !starts_with(line, "diff ")) continue; + /* + * We are past the commit log message. Prepare to + * stop at the beginning of the next patch header. + */ + find_header = 1; + /* Parsing diff header? */ if (before == -1) { if (starts_with(line, "GIT binary patch") || @@ -127,6 +160,16 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result, break; } + /* + * A hunk about an incomplete line may have this + * marker at the end, which should just be ignored. + */ + if (starts_with(line, "\\ ") && 12 < strlen(line)) { + if (verbatim) + the_hash_algo->update_fn(&ctx, line, strlen(line)); + continue; + } + if (diff_is_binary) { if (starts_with(line, "diff ")) { diff_is_binary = 0; @@ -173,17 +216,20 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result, return patchlen; } -static void generate_id_list(int stable, int verbatim) +static void generate_id_list(unsigned flags) { struct object_id oid, n, result; int patchlen; struct strbuf line_buf = STRBUF_INIT; oidclr(&oid, the_repository->hash_algo); + flags |= GOPID_FIND_HEADER; while (!feof(stdin)) { - patchlen = get_one_patchid(&n, &result, &line_buf, stable, verbatim); - flush_current_id(patchlen, &oid, &result); + patchlen = get_one_patchid(&n, &result, &line_buf, flags); + if (patchlen) + flush_current_id(&oid, &result); oidcpy(&oid, &n); + flags &= ~GOPID_FIND_HEADER; } strbuf_release(&line_buf); } @@ -219,6 +265,7 @@ int cmd_patch_id(int argc, const char **argv, const char *prefix) /* if nothing is set, default to unstable */ struct patch_id_opts config = {0, 0}; int opts = 0; + unsigned flags = 0; struct option builtin_patch_id_options[] = { OPT_CMDMODE(0, "unstable", &opts, N_("use the unstable patch-id algorithm"), 1), @@ -250,7 +297,11 @@ int cmd_patch_id(int argc, const char **argv, const char *prefix) if (!the_hash_algo) repo_set_hash_algo(the_repository, GIT_HASH_SHA1); - generate_id_list(opts ? opts > 1 : config.stable, - opts ? opts == 3 : config.verbatim); + if (opts ? opts > 1 : config.stable) + flags |= GOPID_STABLE; + if (opts ? opts == 3 : config.verbatim) + flags |= GOPID_VERBATIM; + generate_id_list(flags); + return 0; } diff --git a/builtin/rebase.c b/builtin/rebase.c index e3a8e74cfc..a2c96c080e 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -186,6 +186,7 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts) replay.committer_date_is_author_date = opts->committer_date_is_author_date; replay.ignore_date = opts->ignore_date; + free(replay.gpg_sign); replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt); replay.reflog_action = xstrdup(opts->reflog_action); if (opts->strategy) @@ -1774,7 +1775,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) /* If a hook exists, give it a chance to interrupt*/ if (!ok_to_skip_pre_rebase && - run_hooks_l("pre-rebase", options.upstream_arg, + run_hooks_l(the_repository, "pre-rebase", options.upstream_arg, argc ? argv[0] : NULL, NULL)) die(_("The pre-rebase hook refused to rebase.")); diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 339524ae2a..3f35140e48 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -300,7 +300,7 @@ static void show_ref(const char *path, const struct object_id *oid) } } -static int show_ref_cb(const char *path_full, const struct object_id *oid, +static int show_ref_cb(const char *path_full, const char *referent UNUSED, const struct object_id *oid, int flag UNUSED, void *data) { struct oidset *seen = data; @@ -792,7 +792,7 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, struct child_process proc = CHILD_PROCESS_INIT; struct async muxer; int code; - const char *hook_path = find_hook(hook_name); + const char *hook_path = find_hook(the_repository, hook_name); if (!hook_path) return 0; @@ -922,7 +922,7 @@ static int run_update_hook(struct command *cmd) { struct child_process proc = CHILD_PROCESS_INIT; int code; - const char *hook_path = find_hook("update"); + const char *hook_path = find_hook(the_repository, "update"); if (!hook_path) return 0; @@ -1098,7 +1098,7 @@ static int run_proc_receive_hook(struct command *commands, int hook_use_push_options = 0; int version = 0; int code; - const char *hook_path = find_hook("proc-receive"); + const char *hook_path = find_hook(the_repository, "proc-receive"); if (!hook_path) { rp_error("cannot find hook 'proc-receive'"); @@ -1409,7 +1409,7 @@ static const char *push_to_checkout(unsigned char *hash, strvec_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree)); strvec_pushv(&opt.env, env->v); strvec_push(&opt.args, hash_to_hex(hash)); - if (run_hooks_opt(push_to_checkout_hook, &opt)) + if (run_hooks_opt(the_repository, push_to_checkout_hook, &opt)) return "push-to-checkout hook declined"; else return NULL; @@ -1618,7 +1618,7 @@ static void run_update_post_hook(struct command *commands) struct child_process proc = CHILD_PROCESS_INIT; const char *hook; - hook = find_hook("post-update"); + hook = find_hook(the_repository, "post-update"); if (!hook) return; diff --git a/builtin/refs.c b/builtin/refs.c index 46dcd150d4..131f98be98 100644 --- a/builtin/refs.c +++ b/builtin/refs.c @@ -1,4 +1,6 @@ #include "builtin.h" +#include "config.h" +#include "fsck.h" #include "parse-options.h" #include "refs.h" #include "repository.h" @@ -7,6 +9,9 @@ #define REFS_MIGRATE_USAGE \ N_("git refs migrate --ref-format=<format> [--dry-run]") +#define REFS_VERIFY_USAGE \ + N_("git refs verify [--strict] [--verbose]") + static int cmd_refs_migrate(int argc, const char **argv, const char *prefix) { const char * const migrate_usage[] = { @@ -58,15 +63,44 @@ out: return err; } +static int cmd_refs_verify(int argc, const char **argv, const char *prefix) +{ + struct fsck_options fsck_refs_options = FSCK_REFS_OPTIONS_DEFAULT; + const char * const verify_usage[] = { + REFS_VERIFY_USAGE, + NULL, + }; + struct option options[] = { + OPT_BOOL(0, "verbose", &fsck_refs_options.verbose, N_("be verbose")), + OPT_BOOL(0, "strict", &fsck_refs_options.strict, N_("enable strict checking")), + OPT_END(), + }; + int ret; + + argc = parse_options(argc, argv, prefix, options, verify_usage, 0); + if (argc) + usage(_("'git refs verify' takes no arguments")); + + git_config(git_fsck_config, &fsck_refs_options); + prepare_repo_settings(the_repository); + + ret = refs_fsck(get_main_ref_store(the_repository), &fsck_refs_options); + + fsck_options_clear(&fsck_refs_options); + return ret; +} + int cmd_refs(int argc, const char **argv, const char *prefix) { const char * const refs_usage[] = { REFS_MIGRATE_USAGE, + REFS_VERIFY_USAGE, NULL, }; parse_opt_subcommand_fn *fn = NULL; struct option opts[] = { OPT_SUBCOMMAND("migrate", &fn, cmd_refs_migrate), + OPT_SUBCOMMAND("verify", &fn, cmd_refs_verify), OPT_END(), }; diff --git a/builtin/remote.c b/builtin/remote.c index 08292498bd..d1f9292ed2 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -258,7 +258,7 @@ struct branch_info { char *push_remote_name; }; -static struct string_list branch_list = STRING_LIST_INIT_NODUP; +static struct string_list branch_list = STRING_LIST_INIT_DUP; static const char *abbrev_ref(const char *name, const char *prefix) { @@ -292,8 +292,8 @@ static int config_read_branches(const char *key, const char *value, type = PUSH_REMOTE; else return 0; - name = xmemdupz(key, key_len); + name = xmemdupz(key, key_len); item = string_list_insert(&branch_list, name); if (!item->util) @@ -337,6 +337,7 @@ static int config_read_branches(const char *key, const char *value, BUG("unexpected type=%d", type); } + free(name); return 0; } @@ -543,6 +544,7 @@ struct branches_for_remote { }; static int add_branch_for_removal(const char *refname, + const char *referent UNUSED, const struct object_id *oid UNUSED, int flags UNUSED, void *cb_data) { @@ -554,13 +556,16 @@ static int add_branch_for_removal(const char *refname, refspec.dst = (char *)refname; if (remote_find_tracking(branches->remote, &refspec)) return 0; + free(refspec.src); /* don't delete a branch if another remote also uses it */ for (kr = branches->keep->list; kr; kr = kr->next) { memset(&refspec, 0, sizeof(refspec)); refspec.dst = (char *)refname; - if (!remote_find_tracking(kr->remote, &refspec)) + if (!remote_find_tracking(kr->remote, &refspec)) { + free(refspec.src); return 0; + } } /* don't delete non-remote-tracking refs */ @@ -585,7 +590,7 @@ struct rename_info { uint32_t symrefs_nr; }; -static int read_remote_branches(const char *refname, +static int read_remote_branches(const char *refname, const char *referent UNUSED, const struct object_id *oid UNUSED, int flags UNUSED, void *cb_data) { @@ -667,7 +672,11 @@ static int config_read_push_default(const char *key, const char *value, static void handle_push_default(const char* old_name, const char* new_name) { struct push_default_info push_default = { - old_name, CONFIG_SCOPE_UNKNOWN, STRBUF_INIT, -1 }; + .old_name = old_name, + .scope = CONFIG_SCOPE_UNKNOWN, + .origin = STRBUF_INIT, + .linenr = -1, + }; git_config(config_read_push_default, &push_default); if (push_default.scope >= CONFIG_SCOPE_COMMAND) ; /* pass */ @@ -687,6 +696,8 @@ static void handle_push_default(const char* old_name, const char* new_name) push_default.origin.buf, push_default.linenr, old_name); } + + strbuf_release(&push_default.origin); } @@ -736,7 +747,7 @@ static int mv(int argc, const char **argv, const char *prefix) strbuf_addf(&buf, "remote.%s", rename.old_name); strbuf_addf(&buf2, "remote.%s", rename.new_name); - if (git_config_rename_section(buf.buf, buf2.buf) < 1) + if (repo_config_rename_section(the_repository, buf.buf, buf2.buf) < 1) return error(_("Could not rename config section '%s' to '%s'"), buf.buf, buf2.buf); @@ -784,7 +795,7 @@ static int mv(int argc, const char **argv, const char *prefix) } if (!refspec_updated) - return 0; + goto out; /* * First remove symrefs, then rename the rest, finally create @@ -850,10 +861,15 @@ static int mv(int argc, const char **argv, const char *prefix) display_progress(progress, ++refs_renamed_nr); } stop_progress(&progress); - string_list_clear(&remote_branches, 1); handle_push_default(rename.old_name, rename.new_name); +out: + string_list_clear(&remote_branches, 1); + strbuf_release(&old_remote_context); + strbuf_release(&buf); + strbuf_release(&buf2); + strbuf_release(&buf3); return 0; } @@ -944,12 +960,21 @@ static int rm(int argc, const char **argv, const char *prefix) if (!result) { strbuf_addf(&buf, "remote.%s", remote->name); - if (git_config_rename_section(buf.buf, NULL) < 1) - return error(_("Could not remove config section '%s'"), buf.buf); + if (repo_config_rename_section(the_repository, buf.buf, NULL) < 1) { + result = error(_("Could not remove config section '%s'"), buf.buf); + goto out; + } handle_push_default(remote->name, NULL); } +out: + for (struct known_remote *r = known_remotes.list; r;) { + struct known_remote *next = r->next; + free(r); + r = next; + } + strbuf_release(&buf); return result; } @@ -971,6 +996,7 @@ static void free_remote_ref_states(struct ref_states *states) } static int append_ref_to_tracked_list(const char *refname, + const char *referent UNUSED, const struct object_id *oid UNUSED, int flags, void *cb_data) { @@ -982,8 +1008,10 @@ static int append_ref_to_tracked_list(const char *refname, memset(&refspec, 0, sizeof(refspec)); refspec.dst = (char *)refname; - if (!remote_find_tracking(states->remote, &refspec)) + if (!remote_find_tracking(states->remote, &refspec)) { string_list_append(&states->tracked, abbrev_branch(refspec.src)); + free(refspec.src); + } return 0; } diff --git a/builtin/repack.c b/builtin/repack.c index f0317fa94a..62cfa50c50 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -667,6 +667,7 @@ struct midx_snapshot_ref_data { }; static int midx_snapshot_ref_one(const char *refname UNUSED, + const char *referent UNUSED, const struct object_id *oid, int flag UNUSED, void *_data) { @@ -1217,10 +1218,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix) if (!write_midx && (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository())) write_bitmaps = 0; - } else if (write_bitmaps && - git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0) && - git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP, 0)) { - write_bitmaps = 0; } if (pack_kept_objects < 0) pack_kept_objects = write_bitmaps > 0 && !write_midx; @@ -1520,8 +1517,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix) if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0)) { unsigned flags = 0; - if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP, 0)) - flags |= MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX; + if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL, 0)) + flags |= MIDX_WRITE_INCREMENTAL; write_midx_file(get_object_directory(), NULL, NULL, flags); } diff --git a/builtin/replace.c b/builtin/replace.c index 1ef833c07f..34cc4672bc 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -49,6 +49,7 @@ struct show_data { }; static int show_reference(const char *refname, + const char *referent UNUSED, const struct object_id *oid, int flag UNUSED, void *cb_data) { diff --git a/builtin/replay.c b/builtin/replay.c index 0448326636..138198ce9c 100644 --- a/builtin/replay.c +++ b/builtin/replay.c @@ -151,7 +151,7 @@ static void get_ref_information(struct rev_cmdline_info *cmd_info, static void determine_replay_mode(struct rev_cmdline_info *cmd_info, const char *onto_name, - const char **advance_name, + char **advance_name, struct commit **onto, struct strset **update_refs) { @@ -174,6 +174,7 @@ static void determine_replay_mode(struct rev_cmdline_info *cmd_info, *onto = peel_committish(*advance_name); if (repo_dwim_ref(the_repository, *advance_name, strlen(*advance_name), &oid, &fullname, 0) == 1) { + free(*advance_name); *advance_name = fullname; } else { die(_("argument to --advance must be a reference")); @@ -197,6 +198,7 @@ static void determine_replay_mode(struct rev_cmdline_info *cmd_info, if (negative_refs_complete) { struct hashmap_iter iter; struct strmap_entry *entry; + const char *last_key = NULL; if (rinfo.negative_refexprs == 0) die(_("all positive revisions given must be references")); @@ -208,8 +210,11 @@ static void determine_replay_mode(struct rev_cmdline_info *cmd_info, /* Only one entry, but we have to loop to get it */ strset_for_each_entry(&rinfo.negative_refs, &iter, entry) { - *advance_name = entry->key; + last_key = entry->key; } + + free(*advance_name); + *advance_name = xstrdup_or_null(last_key); } else { /* positive_refs_complete */ if (rinfo.negative_refexprs > 1) die(_("cannot implicitly determine correct base for --onto")); @@ -271,7 +276,8 @@ static struct commit *pick_regular_commit(struct commit *pickme, int cmd_replay(int argc, const char **argv, const char *prefix) { - const char *advance_name = NULL; + const char *advance_name_opt = NULL; + char *advance_name = NULL; struct commit *onto = NULL; const char *onto_name = NULL; int contained = 0; @@ -292,7 +298,7 @@ int cmd_replay(int argc, const char **argv, const char *prefix) NULL }; struct option replay_options[] = { - OPT_STRING(0, "advance", &advance_name, + OPT_STRING(0, "advance", &advance_name_opt, N_("branch"), N_("make replay advance given branch")), OPT_STRING(0, "onto", &onto_name, @@ -306,14 +312,15 @@ int cmd_replay(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, replay_options, replay_usage, PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT); - if (!onto_name && !advance_name) { + if (!onto_name && !advance_name_opt) { error(_("option --onto or --advance is mandatory")); usage_with_options(replay_usage, replay_options); } - if (advance_name && contained) + if (advance_name_opt && contained) die(_("options '%s' and '%s' cannot be used together"), "--advance", "--contained"); + advance_name = xstrdup_or_null(advance_name_opt); repo_init_revisions(the_repository, &revs, prefix); @@ -377,7 +384,7 @@ int cmd_replay(int argc, const char **argv, const char *prefix) goto cleanup; } - init_merge_options(&merge_opt, the_repository); + init_basic_merge_options(&merge_opt, the_repository); memset(&result, 0, sizeof(result)); merge_opt.show_rename_progress = 0; last_commit = onto; @@ -441,6 +448,7 @@ int cmd_replay(int argc, const char **argv, const char *prefix) cleanup: release_revisions(&revs); + free(advance_name); /* Return */ if (ret < 0) diff --git a/builtin/rerere.c b/builtin/rerere.c index b2efc6f640..81b65ffa39 100644 --- a/builtin/rerere.c +++ b/builtin/rerere.c @@ -73,11 +73,17 @@ int cmd_rerere(int argc, const char **argv, const char *prefix) if (!strcmp(argv[0], "forget")) { struct pathspec pathspec; + int ret; + if (argc < 2) warning(_("'git rerere forget' without paths is deprecated")); parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD, prefix, argv + 1); - return rerere_forget(the_repository, &pathspec); + + ret = rerere_forget(the_repository, &pathspec); + + clear_pathspec(&pathspec); + return ret; } if (!strcmp(argv[0], "clear")) { diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 2e64f5bda7..4285dc34a7 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -211,7 +211,7 @@ static int show_default(void) return 0; } -static int show_reference(const char *refname, const struct object_id *oid, +static int show_reference(const char *refname, const char *referent UNUSED, const struct object_id *oid, int flag UNUSED, void *cb_data UNUSED) { if (ref_excluded(&ref_excludes, refname)) @@ -220,7 +220,7 @@ static int show_reference(const char *refname, const struct object_id *oid, return 0; } -static int anti_reference(const char *refname, const struct object_id *oid, +static int anti_reference(const char *refname, const char *referent UNUSED, const struct object_id *oid, int flag UNUSED, void *cb_data UNUSED) { show_rev(REVERSED, oid, refname); @@ -553,7 +553,10 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) strbuf_release(&sb); strvec_clear(&longnames); strvec_clear(&usage); - free((char *) opts->help); + for (size_t i = 0; i < opts_nr; i++) { + free((char *) opts[i].help); + free((char *) opts[i].argh); + } free(opts); return 0; } diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 5bde7c68c2..b529608c92 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -514,4 +514,5 @@ void shortlog_output(struct shortlog *log) string_list_clear(&log->list, 1); clear_mailmap(&log->mailmap); string_list_clear(&log->format, 0); + string_list_clear(&log->trailers, 0); } diff --git a/builtin/show-branch.c b/builtin/show-branch.c index d72f4cb98d..29237f653d 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -410,7 +410,7 @@ static int append_ref(const char *refname, const struct object_id *oid, return 0; } -static int append_head_ref(const char *refname, const struct object_id *oid, +static int append_head_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid, int flag UNUSED, void *cb_data UNUSED) { struct object_id tmp; @@ -425,7 +425,7 @@ static int append_head_ref(const char *refname, const struct object_id *oid, return append_ref(refname + ofs, oid, 0); } -static int append_remote_ref(const char *refname, const struct object_id *oid, +static int append_remote_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid, int flag UNUSED, void *cb_data UNUSED) { struct object_id tmp; @@ -451,7 +451,7 @@ static int append_tag_ref(const char *refname, const struct object_id *oid, static const char *match_ref_pattern = NULL; static int match_ref_slash = 0; -static int append_matching_ref(const char *refname, const struct object_id *oid, +static int append_matching_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid, int flag, void *cb_data) { /* we want to allow pattern hold/<asterisk> to show all @@ -468,7 +468,7 @@ static int append_matching_ref(const char *refname, const struct object_id *oid, if (wildmatch(match_ref_pattern, tail, 0)) return 0; if (starts_with(refname, "refs/heads/")) - return append_head_ref(refname, oid, flag, cb_data); + return append_head_ref(refname, NULL, oid, flag, cb_data); if (starts_with(refname, "refs/tags/")) return append_tag_ref(refname, oid, flag, cb_data); return append_ref(refname, oid, 0); @@ -502,14 +502,14 @@ static int rev_is_head(const char *head, const char *name) return !strcmp(head, name); } -static int show_merge_base(struct commit_list *seen, int num_rev) +static int show_merge_base(const struct commit_list *seen, int num_rev) { int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1); int all_revs = all_mask & ~((1u << REV_SHIFT) - 1); int exit_status = 1; - while (seen) { - struct commit *commit = pop_commit(&seen); + for (const struct commit_list *s = seen; s; s = s->next) { + struct commit *commit = s->item; int flags = commit->object.flags & all_mask; if (!(flags & UNINTERESTING) && ((flags & all_revs) == all_revs)) { @@ -635,7 +635,7 @@ static int parse_reflog_param(const struct option *opt, const char *arg, int cmd_show_branch(int ac, const char **av, const char *prefix) { struct commit *rev[MAX_REVS], *commit; - char *reflog_msg[MAX_REVS]; + char *reflog_msg[MAX_REVS] = {0}; struct commit_list *list = NULL, *seen = NULL; unsigned int rev_mask[MAX_REVS]; int num_rev, i, extra = 0; @@ -692,6 +692,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) parse_reflog_param), OPT_END() }; + const char **args_copy = NULL; + int ret; init_commit_name_slab(&name_slab); @@ -699,8 +701,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) /* If nothing is specified, try the default first */ if (ac == 1 && default_args.nr) { + DUP_ARRAY(args_copy, default_args.v, default_args.nr); ac = default_args.nr; - av = default_args.v; + av = args_copy; } ac = parse_options(ac, av, prefix, builtin_show_branch_options, @@ -780,7 +783,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) } for (i = 0; i < reflog; i++) { - char *logmsg; + char *logmsg = NULL; char *nth_desc; const char *msg; char *end; @@ -790,6 +793,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) if (read_ref_at(get_main_ref_store(the_repository), ref, flags, 0, base + i, &oid, &logmsg, ×tamp, &tz, NULL)) { + free(logmsg); reflog = i; break; } @@ -842,7 +846,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) if (!ref_name_cnt) { fprintf(stderr, "No revs to be shown.\n"); - exit(0); + ret = 0; + goto out; } for (num_rev = 0; ref_name[num_rev]; num_rev++) { @@ -879,11 +884,15 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) commit_list_sort_by_date(&seen); - if (merge_base) - return show_merge_base(seen, num_rev); + if (merge_base) { + ret = show_merge_base(seen, num_rev); + goto out; + } - if (independent) - return show_independent(rev, num_rev, rev_mask); + if (independent) { + ret = show_independent(rev, num_rev, rev_mask); + goto out; + } /* Show list; --more=-1 means list-only */ if (1 < num_rev || extra < 0) { @@ -919,8 +928,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) putchar('\n'); } } - if (extra < 0) - exit(0); + if (extra < 0) { + ret = 0; + goto out; + } /* Sort topologically */ sort_in_topological_order(&seen, sort_order); @@ -932,8 +943,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) all_mask = ((1u << (REV_SHIFT + num_rev)) - 1); all_revs = all_mask & ~((1u << REV_SHIFT) - 1); - while (seen) { - struct commit *commit = pop_commit(&seen); + for (struct commit_list *l = seen; l; l = l->next) { + struct commit *commit = l->item; int this_flag = commit->object.flags; int is_merge_point = ((this_flag & all_revs) == all_revs); @@ -973,6 +984,15 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) if (shown_merge_point && --extra < 0) break; } + + ret = 0; + +out: + for (size_t i = 0; i < ARRAY_SIZE(reflog_msg); i++) + free(reflog_msg[i]); + free_commit_list(seen); + free_commit_list(list); + free(args_copy); free(head); - return 0; + return ret; } diff --git a/builtin/show-ref.c b/builtin/show-ref.c index 839a5c29f3..f5899ce9ff 100644 --- a/builtin/show-ref.c +++ b/builtin/show-ref.c @@ -63,7 +63,7 @@ struct show_ref_data { int show_head; }; -static int show_ref(const char *refname, const struct object_id *oid, +static int show_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid, int flag UNUSED, void *cbdata) { struct show_ref_data *data = cbdata; @@ -97,6 +97,7 @@ match: } static int add_existing(const char *refname, + const char *referent UNUSED, const struct object_id *oid UNUSED, int flag UNUSED, void *cbdata) { @@ -293,8 +294,8 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix) struct show_one_options show_one_opts = {0}; int verify = 0, exists = 0; const struct option show_ref_options[] = { - OPT_BOOL(0, "tags", &patterns_opts.tags_only, N_("only show tags (can be combined with branches)")), - OPT_BOOL(0, "branches", &patterns_opts.branches_only, N_("only show branches (can be combined with tags)")), + OPT_BOOL(0, "tags", &patterns_opts.tags_only, N_("only show tags (can be combined with --branches)")), + OPT_BOOL(0, "branches", &patterns_opts.branches_only, N_("only show branches (can be combined with --tags)")), OPT_HIDDEN_BOOL(0, "heads", &patterns_opts.branches_only, N_("deprecated synonym for --branches")), OPT_BOOL(0, "exists", &exists, N_("check for reference existence without resolving")), diff --git a/builtin/stash.c b/builtin/stash.c index 46b981c4dd..fcfd97972a 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -574,7 +574,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info, } } - init_merge_options(&o, the_repository); + init_ui_merge_options(&o, the_repository); o.branch1 = "Updated upstream"; o.branch2 = "Stashed changes"; @@ -1521,6 +1521,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q struct strbuf patch = STRBUF_INIT; struct strbuf stash_msg_buf = STRBUF_INIT; struct strbuf untracked_files = STRBUF_INIT; + struct strbuf out = STRBUF_INIT; if (patch_mode && keep_index == -1) keep_index = 1; @@ -1626,7 +1627,6 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q struct child_process cp_add = CHILD_PROCESS_INIT; struct child_process cp_diff = CHILD_PROCESS_INIT; struct child_process cp_apply = CHILD_PROCESS_INIT; - struct strbuf out = STRBUF_INIT; cp_add.git_cmd = 1; strvec_push(&cp_add.args, "add"); @@ -1671,7 +1671,28 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q } } - if (keep_index == 1 && !is_null_oid(&info.i_tree)) { + /* + * When keeping staged entries, we need to reset the working + * directory to match the state of our index. This can be + * skipped when the index is the empty tree, because there is + * nothing to reset in that case: + * + * - When the index has any file, regardless of whether + * staged or not, the tree cannot be empty by definition + * and thus we enter the condition. + * + * - When the index has no files, the only thing we need to + * care about is untracked files when `--include-untracked` + * is given. But as we already execute git-clean(1) further + * up to delete such untracked files we don't have to do + * anything here, either. + * + * We thus skip calling git-checkout(1) in this case, also + * because running it on an empty tree will cause it to fail + * due to the pathspec not matching anything. + */ + if (keep_index == 1 && !is_null_oid(&info.i_tree) && + !is_empty_tree_oid(&info.i_tree, the_repository->hash_algo)) { struct child_process cp = CHILD_PROCESS_INIT; cp.git_cmd = 1; @@ -1718,6 +1739,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q done: strbuf_release(&patch); + strbuf_release(&out); free_stash_info(&info); strbuf_release(&stash_msg_buf); strbuf_release(&untracked_files); @@ -1869,6 +1891,8 @@ int cmd_stash(int argc, const char **argv, const char *prefix) OPT_SUBCOMMAND_F("save", &fn, save_stash, PARSE_OPT_NOCOMPLETE), OPT_END() }; + const char **args_copy; + int ret; git_config(git_stash_config, NULL); @@ -1892,5 +1916,16 @@ int cmd_stash(int argc, const char **argv, const char *prefix) /* Assume 'stash push' */ strvec_push(&args, "push"); strvec_pushv(&args, argv); - return !!push_stash(args.nr, args.v, prefix, 1); + + /* + * `push_stash()` ends up modifying the array, which causes memory + * leaks if we didn't copy the array here. + */ + DUP_ARRAY(args_copy, args.v, args.nr); + + ret = !!push_stash(args.nr, args_copy, prefix, 1); + + strvec_clear(&args); + free(args_copy); + return ret; } diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index f1218a1995..85fb23dee8 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -608,6 +608,7 @@ static void print_status(unsigned int flags, char state, const char *path, } static int handle_submodule_head_ref(const char *refname UNUSED, + const char *referent UNUSED, const struct object_id *oid, int flags UNUSED, void *cb_data) @@ -1455,7 +1456,7 @@ static void deinit_submodule(const char *path, const char *prefix, * remove the whole section so we have a clean state when * the user later decides to init this submodule again */ - git_config_rename_section_in_file(NULL, sub_key, NULL); + repo_config_rename_section_in_file(the_repository, NULL, sub_key, NULL); if (!(flags & OPT_QUIET)) printf(_("Submodule '%s' (%s) unregistered for path '%s'\n"), sub->name, sub->url, displaypath); @@ -1530,8 +1531,9 @@ struct module_clone_data { const char *path; const char *name; const char *url; - const char *depth; + int depth; struct list_objects_filter_options *filter_options; + enum ref_storage_format ref_storage_format; unsigned int quiet: 1; unsigned int progress: 1; unsigned int dissociate: 1; @@ -1540,6 +1542,7 @@ struct module_clone_data { }; #define MODULE_CLONE_DATA_INIT { \ .single_branch = -1, \ + .ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \ } struct submodule_alternate_setup { @@ -1729,8 +1732,8 @@ static int clone_submodule(const struct module_clone_data *clone_data, strvec_push(&cp.args, "--quiet"); if (clone_data->progress) strvec_push(&cp.args, "--progress"); - if (clone_data->depth && *(clone_data->depth)) - strvec_pushl(&cp.args, "--depth", clone_data->depth, NULL); + if (clone_data->depth > 0) + strvec_pushf(&cp.args, "--depth=%d", clone_data->depth); if (reference->nr) { struct string_list_item *item; @@ -1738,6 +1741,9 @@ static int clone_submodule(const struct module_clone_data *clone_data, strvec_pushl(&cp.args, "--reference", item->string, NULL); } + if (clone_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN) + strvec_pushf(&cp.args, "--ref-format=%s", + ref_storage_format_to_name(clone_data->ref_storage_format)); if (clone_data->dissociate) strvec_push(&cp.args, "--dissociate"); if (sm_gitdir && *sm_gitdir) @@ -1832,6 +1838,7 @@ static int module_clone(int argc, const char **argv, const char *prefix) struct string_list reference = STRING_LIST_INIT_NODUP; struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT; + const char *ref_storage_format = NULL; struct option module_clone_options[] = { OPT_STRING(0, "prefix", &clone_data.prefix, @@ -1849,10 +1856,11 @@ static int module_clone(int argc, const char **argv, const char *prefix) OPT_STRING_LIST(0, "reference", &reference, N_("repo"), N_("reference repository")), + OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"), + N_("specify the reference format to use")), OPT_BOOL(0, "dissociate", &dissociate, N_("use --reference only while cloning")), - OPT_STRING(0, "depth", &clone_data.depth, - N_("string"), + OPT_INTEGER(0, "depth", &clone_data.depth, N_("depth for shallow clones")), OPT__QUIET(&quiet, "suppress output for cloning a submodule"), OPT_BOOL(0, "progress", &progress, @@ -1875,6 +1883,11 @@ static int module_clone(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, module_clone_options, git_submodule_helper_usage, 0); + if (ref_storage_format) { + clone_data.ref_storage_format = ref_storage_format_by_name(ref_storage_format); + if (clone_data.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN) + die(_("unknown ref storage format '%s'"), ref_storage_format); + } clone_data.dissociate = !!dissociate; clone_data.quiet = !!quiet; clone_data.progress = !!progress; @@ -1974,6 +1987,7 @@ struct update_data { struct submodule_update_strategy update_strategy; struct list_objects_filter_options *filter_options; struct module_list list; + enum ref_storage_format ref_storage_format; int depth; int max_jobs; int single_branch; @@ -1997,6 +2011,7 @@ struct update_data { #define UPDATE_DATA_INIT { \ .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \ .list = MODULE_LIST_INIT, \ + .ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \ .recommend_shallow = -1, \ .references = STRING_LIST_INIT_DUP, \ .single_branch = -1, \ @@ -2132,6 +2147,9 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, expand_list_objects_filter_spec(suc->update_data->filter_options)); if (suc->update_data->require_init) strvec_push(&child->args, "--require-init"); + if (suc->update_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN) + strvec_pushf(&child->args, "--ref-format=%s", + ref_storage_format_to_name(suc->update_data->ref_storage_format)); strvec_pushl(&child->args, "--path", sub->path, NULL); strvec_pushl(&child->args, "--name", sub->name, NULL); strvec_pushl(&child->args, "--url", url, NULL); @@ -2269,6 +2287,7 @@ static int is_tip_reachable(const char *path, const struct object_id *oid) struct child_process cp = CHILD_PROCESS_INIT; struct strbuf rev = STRBUF_INIT; char *hex = oid_to_hex(oid); + int reachable; cp.git_cmd = 1; cp.dir = path; @@ -2278,9 +2297,12 @@ static int is_tip_reachable(const char *path, const struct object_id *oid) prepare_submodule_repo_env(&cp.env); if (capture_command(&cp, &rev, GIT_MAX_HEXSZ + 1) || rev.len) - return 0; + reachable = 0; + else + reachable = 1; - return 1; + strbuf_release(&rev); + return reachable; } static int fetch_in_submodule(const char *module_path, int depth, int quiet, @@ -2562,6 +2584,9 @@ static void update_data_to_args(const struct update_data *update_data, for_each_string_list_item(item, &update_data->references) strvec_pushl(args, "--reference", item->string, NULL); } + if (update_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN) + strvec_pushf(args, "--ref-format=%s", + ref_storage_format_to_name(update_data->ref_storage_format)); if (update_data->filter_options && update_data->filter_options->choice) strvec_pushf(args, "--filter=%s", expand_list_objects_filter_spec( @@ -2737,6 +2762,7 @@ static int module_update(int argc, const char **argv, const char *prefix) struct update_data opt = UPDATE_DATA_INIT; struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT; + const char *ref_storage_format = NULL; int ret; struct option module_update_options[] = { OPT__SUPER_PREFIX(&opt.super_prefix), @@ -2760,6 +2786,8 @@ static int module_update(int argc, const char **argv, const char *prefix) SM_UPDATE_REBASE), OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"), N_("reference repository")), + OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"), + N_("specify the reference format to use")), OPT_BOOL(0, "dissociate", &opt.dissociate, N_("use --reference only while cloning")), OPT_INTEGER(0, "depth", &opt.depth, @@ -2803,6 +2831,12 @@ static int module_update(int argc, const char **argv, const char *prefix) module_update_options); } + if (ref_storage_format) { + opt.ref_storage_format = ref_storage_format_by_name(ref_storage_format); + if (opt.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN) + die(_("unknown ref storage format '%s'"), ref_storage_format); + } + opt.filter_options = &filter_options; opt.prefix = prefix; @@ -3098,13 +3132,17 @@ struct add_data { const char *sm_name; const char *repo; const char *realrepo; + enum ref_storage_format ref_storage_format; int depth; unsigned int force: 1; unsigned int quiet: 1; unsigned int progress: 1; unsigned int dissociate: 1; }; -#define ADD_DATA_INIT { .depth = -1 } +#define ADD_DATA_INIT { \ + .depth = -1, \ + .ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \ +} static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path) { @@ -3198,9 +3236,10 @@ static int add_submodule(const struct add_data *add_data) string_list_append(&reference, p)->util = p; } + clone_data.ref_storage_format = add_data->ref_storage_format; clone_data.dissociate = add_data->dissociate; if (add_data->depth >= 0) - clone_data.depth = xstrfmt("%d", add_data->depth); + clone_data.depth = add_data->depth; if (clone_submodule(&clone_data, &reference)) goto cleanup; @@ -3223,6 +3262,7 @@ static int add_submodule(const struct add_data *add_data) die(_("unable to checkout submodule '%s'"), add_data->sm_path); } ret = 0; + cleanup: string_list_clear(&reference, 1); return ret; @@ -3362,6 +3402,7 @@ static int module_add(int argc, const char **argv, const char *prefix) { int force = 0, quiet = 0, progress = 0, dissociate = 0; struct add_data add_data = ADD_DATA_INIT; + const char *ref_storage_format = NULL; char *to_free = NULL; struct option options[] = { OPT_STRING('b', "branch", &add_data.branch, N_("branch"), @@ -3372,6 +3413,8 @@ static int module_add(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "progress", &progress, N_("force cloning progress")), OPT_STRING(0, "reference", &add_data.reference_path, N_("repository"), N_("reference repository")), + OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"), + N_("specify the reference format to use")), OPT_BOOL(0, "dissociate", &dissociate, N_("borrow the objects from reference repositories")), OPT_STRING(0, "name", &add_data.sm_name, N_("name"), N_("sets the submodule's name to the given string " @@ -3398,6 +3441,12 @@ static int module_add(int argc, const char **argv, const char *prefix) if (argc == 0 || argc > 2) usage_with_options(usage, options); + if (ref_storage_format) { + add_data.ref_storage_format = ref_storage_format_by_name(ref_storage_format); + if (add_data.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN) + die(_("unknown ref storage format '%s'"), ref_storage_format); + } + add_data.repo = argv[0]; if (argc == 1) add_data.sm_path = git_url_basename(add_data.repo, 0, 0); diff --git a/builtin/update-index.c b/builtin/update-index.c index d343416ae2..35a1f957ad 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -1156,7 +1156,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) end_odb_transaction(); if (split_index > 0) { - if (git_config_get_split_index() == 0) + if (repo_config_get_split_index(the_repository) == 0) warning(_("core.splitIndex is set to false; " "remove or change it, if you really want to " "enable split index")); @@ -1165,7 +1165,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) else add_split_index(the_repository->index); } else if (!split_index) { - if (git_config_get_split_index() == 1) + if (repo_config_get_split_index(the_repository) == 1) warning(_("core.splitIndex is set to true; " "remove or change it, if you really want to " "disable split index")); diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 6a6a2ff55d..8f31da9a4b 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -274,7 +274,7 @@ static void parse_cmd_update(struct ref_transaction *transaction, } static void parse_cmd_symref_update(struct ref_transaction *transaction, - const char *next, const char *end) + const char *next, const char *end UNUSED) { char *refname, *new_target, *old_arg; char *old_target = NULL; @@ -360,7 +360,7 @@ static void parse_cmd_create(struct ref_transaction *transaction, static void parse_cmd_symref_create(struct ref_transaction *transaction, - const char *next, const char *end) + const char *next, const char *end UNUSED) { struct strbuf err = STRBUF_INIT; char *refname, *new_target; @@ -423,7 +423,7 @@ static void parse_cmd_delete(struct ref_transaction *transaction, static void parse_cmd_symref_delete(struct ref_transaction *transaction, - const char *next, const char *end) + const char *next, const char *end UNUSED) { struct strbuf err = STRBUF_INIT; char *refname, *old_target; @@ -479,7 +479,7 @@ static void parse_cmd_verify(struct ref_transaction *transaction, } static void parse_cmd_symref_verify(struct ref_transaction *transaction, - const char *next, const char *end) + const char *next, const char *end UNUSED) { struct strbuf err = STRBUF_INIT; struct object_id old_oid; diff --git a/builtin/worktree.c b/builtin/worktree.c index 1d51e54fcd..41e7f6a327 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -573,7 +573,7 @@ done: NULL); opt.dir = path; - ret = run_hooks_opt("post-checkout", &opt); + ret = run_hooks_opt(the_repository, "post-checkout", &opt); } strvec_clear(&child_env); @@ -626,6 +626,7 @@ static void print_preparing_worktree_line(int detach, * Returns 0 on failure and non-zero on success. */ static int first_valid_ref(const char *refname UNUSED, + const char *referent UNUSED, const struct object_id *oid UNUSED, int flags UNUSED, void *cb_data UNUSED) @@ -769,7 +770,7 @@ static int add(int ac, const char **av, const char *prefix) char *branch_to_free = NULL; char *new_branch_to_free = NULL; const char *new_branch = NULL; - const char *opt_track = NULL; + char *opt_track = NULL; const char *lock_reason = NULL; int keep_locked = 0; int used_new_branch_options; @@ -846,7 +847,7 @@ static int add(int ac, const char **av, const char *prefix) if (opts.orphan && !new_branch) { int n; const char *s = worktree_basename(path, &n); - new_branch = xstrndup(s, n); + new_branch = new_branch_to_free = xstrndup(s, n); } else if (opts.orphan) { ; /* no-op */ } else if (opts.detach) { @@ -875,7 +876,7 @@ static int add(int ac, const char **av, const char *prefix) remote = unique_tracking_name(branch, &oid, NULL); if (remote) { new_branch = branch; - branch = remote; + branch = new_branch_to_free = remote; } } @@ -923,6 +924,7 @@ static int add(int ac, const char **av, const char *prefix) ret = add_worktree(path, branch, &opts); free(path); + free(opt_track); free(branch_to_free); free(new_branch_to_free); return ret; @@ -1146,14 +1148,14 @@ static void validate_no_submodules(const struct worktree *wt) struct strbuf path = STRBUF_INIT; int i, found_submodules = 0; - if (is_directory(worktree_git_path(wt, "modules"))) { + if (is_directory(worktree_git_path(the_repository, wt, "modules"))) { /* * There could be false positives, e.g. the "modules" * directory exists but is empty. But it's a rare case and * this simpler check is probably good enough for now. */ found_submodules = 1; - } else if (read_index_from(&istate, worktree_git_path(wt, "index"), + } else if (read_index_from(&istate, worktree_git_path(the_repository, wt, "index"), get_worktree_git_dir(wt)) > 0) { for (i = 0; i < istate.cache_nr; i++) { struct cache_entry *ce = istate.cache[i]; |
