git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 10/20] builtin/log: stop using globals for format config

From
Patrick Steinhardt <ps@pks.im>
Date
May 23, 2024, 12:25 UTC
Message-ID
<d8cd9a05f8cb93bac31dcfe04517b841bb5e0197.1716465556.git.ps@pks.im>
In-Reply-To
<cover.1716465556.git.ps@pks.im>

This commit does the exact same as the preceding commit, only for the format configuration instead of the log configuration.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/log.c | 467 ++++++++++++++++++++++++++++----------------------
 1 file changed, 265 insertions(+), 202 deletions(-)
diff --git a/builtin/log.c b/builtin/log.c
index f5da29ee2a..890bf0c425 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -945,36 +945,6 @@ int cmd_log(int argc, const char **argv, const char *prefix)
 
 /* format-patch */
 
-static const char *fmt_patch_suffix = ".patch";
-static int numbered = 0;
-static int auto_number = 1;
-
-static char *default_attach = NULL;
-
-static struct string_list extra_hdr = STRING_LIST_INIT_NODUP;
-static struct string_list extra_to = STRING_LIST_INIT_NODUP;
-static struct string_list extra_cc = STRING_LIST_INIT_NODUP;
-
-static void add_header(const char *value)
-{
-	struct string_list_item *item;
-	int len = strlen(value);
-	while (len && value[len - 1] == '\n')
-		len--;
-
-	if (!strncasecmp(value, "to: ", 4)) {
-		item = string_list_append(&extra_to, value + 4);
-		len -= 4;
-	} else if (!strncasecmp(value, "cc: ", 4)) {
-		item = string_list_append(&extra_cc, value + 4);
-		len -= 4;
-	} else {
-		item = string_list_append(&extra_hdr, value);
-	}
-
-	item->string[len] = '\0';
-}
-
 enum cover_setting {
 	COVER_UNSET,
 	COVER_OFF,
@@ -1001,17 +971,61 @@ enum auto_base_setting {
 	AUTO_BASE_WHEN_ABLE
 };
 
-static enum thread_level thread;
-static int do_signoff;
-static enum auto_base_setting auto_base;
-static char *from;
-static const char *signature = git_version_string;
-static char *signature_file;
-static enum cover_setting config_cover_letter;
-static const char *config_output_directory;
-static enum cover_from_description cover_from_description_mode = COVER_FROM_MESSAGE;
-static int show_notes;
-static struct display_notes_opt notes_opt;
+struct format_config {
+	struct log_config log;
+	enum thread_level thread;
+	int do_signoff;
+	enum auto_base_setting auto_base;
+	char *base_commit;
+	char *from;
+	char *signature;
+	char *signature_file;
+	enum cover_setting config_cover_letter;
+	char *config_output_directory;
+	enum cover_from_description cover_from_description_mode;
+	int show_notes;
+	struct display_notes_opt notes_opt;
+	int numbered_cmdline_opt;
+	int numbered;
+	int auto_number;
+	char *default_attach;
+	struct string_list extra_hdr;
+	struct string_list extra_to;
+	struct string_list extra_cc;
+	int keep_subject;
+	int subject_prefix;
+	struct strbuf sprefix;
+	char *fmt_patch_suffix;
+};
+
+static void format_config_init(struct format_config *cfg)
+{
+	memset(cfg, 0, sizeof(*cfg));
+	log_config_init(&cfg->log);
+	cfg->cover_from_description_mode = COVER_FROM_MESSAGE;
+	cfg->auto_number = 1;
+	string_list_init_dup(&cfg->extra_hdr);
+	string_list_init_dup(&cfg->extra_to);
+	string_list_init_dup(&cfg->extra_cc);
+	strbuf_init(&cfg->sprefix, 0);
+	cfg->fmt_patch_suffix = xstrdup(".patch");
+}
+
+static void format_config_release(struct format_config *cfg)
+{
+	log_config_release(&cfg->log);
+	free(cfg->base_commit);
+	free(cfg->from);
+	free(cfg->signature);
+	free(cfg->signature_file);
+	free(cfg->config_output_directory);
+	free(cfg->default_attach);
+	string_list_clear(&cfg->extra_hdr, 0);
+	string_list_clear(&cfg->extra_to, 0);
+	string_list_clear(&cfg->extra_cc, 0);
+	strbuf_release(&cfg->sprefix);
+	free(cfg->fmt_patch_suffix);
+}
 
 static enum cover_from_description parse_cover_from_description(const char *arg)
 {
@@ -1029,27 +1043,51 @@ static enum cover_from_description parse_cover_from_description(const char *arg)
 		die(_("%s: invalid cover from description mode"), arg);
 }
 
+static void add_header(struct format_config *cfg, const char *value)
+{
+	struct string_list_item *item;
+	int len = strlen(value);
+	while (len && value[len - 1] == '\n')
+		len--;
+
+	if (!strncasecmp(value, "to: ", 4)) {
+		item = string_list_append(&cfg->extra_to, value + 4);
+		len -= 4;
+	} else if (!strncasecmp(value, "cc: ", 4)) {
+		item = string_list_append(&cfg->extra_cc, value + 4);
+		len -= 4;
+	} else {
+		item = string_list_append(&cfg->extra_hdr, value);
+	}
+
+	item->string[len] = '\0';
+}
+
 static int git_format_config(const char *var, const char *value,
 			     const struct config_context *ctx, void *cb)
 {
+	struct format_config *cfg = cb;
+
 	if (!strcmp(var, "format.headers")) {
 		if (!value)
 			die(_("format.headers without value"));
-		add_header(value);
+		add_header(cfg, value);
 		return 0;
 	}
-	if (!strcmp(var, "format.suffix"))
-		return git_config_string(&fmt_patch_suffix, var, value);
+	if (!strcmp(var, "format.suffix")) {
+		FREE_AND_NULL(cfg->fmt_patch_suffix);
+		return git_config_string((const char **) &cfg->fmt_patch_suffix, var, value);
+	}
 	if (!strcmp(var, "format.to")) {
 		if (!value)
 			return config_error_nonbool(var);
-		string_list_append(&extra_to, value);
+		string_list_append(&cfg->extra_to, value);
 		return 0;
 	}
 	if (!strcmp(var, "format.cc")) {
 		if (!value)
 			return config_error_nonbool(var);
-		string_list_append(&extra_cc, value);
+		string_list_append(&cfg->extra_cc, value);
 		return 0;
 	}
 	if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff") ||
@@ -1058,69 +1096,76 @@ static int git_format_config(const char *var, const char *value,
 	}
 	if (!strcmp(var, "format.numbered")) {
 		if (value && !strcasecmp(value, "auto")) {
-			auto_number = 1;
+			cfg->auto_number = 1;
 			return 0;
 		}
-		numbered = git_config_bool(var, value);
-		auto_number = auto_number && numbered;
+		cfg->numbered = git_config_bool(var, value);
+		cfg->auto_number = cfg->auto_number && cfg->numbered;
 		return 0;
 	}
 	if (!strcmp(var, "format.attach")) {
-		if (value && *value)
-			default_attach = xstrdup(value);
-		else if (value && !*value)
-			FREE_AND_NULL(default_attach);
-		else
-			default_attach = xstrdup(git_version_string);
+		if (value && *value) {
+			FREE_AND_NULL(cfg->default_attach);
+			cfg->default_attach = xstrdup(value);
+		} else if (value && !*value) {
+			FREE_AND_NULL(cfg->default_attach);
+		} else {
+			FREE_AND_NULL(cfg->default_attach);
+			cfg->default_attach = xstrdup(git_version_string);
+		}
 		return 0;
 	}
 	if (!strcmp(var, "format.thread")) {
 		if (value && !strcasecmp(value, "deep")) {
-			thread = THREAD_DEEP;
+			cfg->thread = THREAD_DEEP;
 			return 0;
 		}
 		if (value && !strcasecmp(value, "shallow")) {
-			thread = THREAD_SHALLOW;
+			cfg->thread = THREAD_SHALLOW;
 			return 0;
 		}
-		thread = git_config_bool(var, value) ? THREAD_SHALLOW : THREAD_UNSET;
+		cfg->thread = git_config_bool(var, value) ? THREAD_SHALLOW : THREAD_UNSET;
 		return 0;
 	}
 	if (!strcmp(var, "format.signoff")) {
-		do_signoff = git_config_bool(var, value);
+		cfg->do_signoff = git_config_bool(var, value);
 		return 0;
 	}
-	if (!strcmp(var, "format.signature"))
-		return git_config_string(&signature, var, value);
-	if (!strcmp(var, "format.signaturefile"))
-		return git_config_pathname(&signature_file, var, value);
+	if (!strcmp(var, "format.signature")) {
+		FREE_AND_NULL(cfg->signature);
+		return git_config_string((const char **) &cfg->signature, var, value);
+	}
+	if (!strcmp(var, "format.signaturefile")) {
+		FREE_AND_NULL(cfg->signature_file);
+		return git_config_pathname(&cfg->signature_file, var, value);
+	}
 	if (!strcmp(var, "format.coverletter")) {
 		if (value && !strcasecmp(value, "auto")) {
-			config_cover_letter = COVER_AUTO;
+			cfg->config_cover_letter = COVER_AUTO;
 			return 0;
 		}
-		config_cover_letter = git_config_bool(var, value) ? COVER_ON : COVER_OFF;
+		cfg->config_cover_letter = git_config_bool(var, value) ? COVER_ON : COVER_OFF;
 		return 0;
 	}
-	if (!strcmp(var, "format.outputdirectory"))
-		return git_config_string(&config_output_directory, var, value);
+	if (!strcmp(var, "format.outputdirectory")) {
+		FREE_AND_NULL(cfg->config_output_directory);
+		return git_config_string((const char **) &cfg->config_output_directory, var, value);
+	}
 	if (!strcmp(var, "format.useautobase")) {
 		if (value && !strcasecmp(value, "whenAble")) {
-			auto_base = AUTO_BASE_WHEN_ABLE;
+			cfg->auto_base = AUTO_BASE_WHEN_ABLE;
 			return 0;
 		}
-		auto_base = git_config_bool(var, value) ? AUTO_BASE_ALWAYS : AUTO_BASE_NEVER;
+		cfg->auto_base = git_config_bool(var, value) ? AUTO_BASE_ALWAYS : AUTO_BASE_NEVER;
 		return 0;
 	}
 	if (!strcmp(var, "format.from")) {
 		int b = git_parse_maybe_bool(value);
-		free(from);
+		FREE_AND_NULL(cfg->from);
 		if (b < 0)
-			from = xstrdup(value);
+			cfg->from = xstrdup(value);
 		else if (b)
-			from = xstrdup(git_committer_info(IDENT_NO_DATE));
-		else
-			from = NULL;
+			cfg->from = xstrdup(git_committer_info(IDENT_NO_DATE));
 		return 0;
 	}
 	if (!strcmp(var, "format.forceinbodyfrom")) {
@@ -1130,15 +1175,15 @@ static int git_format_config(const char *var, const char *value,
 	if (!strcmp(var, "format.notes")) {
 		int b = git_parse_maybe_bool(value);
 		if (b < 0)
-			enable_ref_display_notes(&notes_opt, &show_notes, value);
+			enable_ref_display_notes(&cfg->notes_opt, &cfg->show_notes, value);
 		else if (b)
-			enable_default_display_notes(&notes_opt, &show_notes);
+			enable_default_display_notes(&cfg->notes_opt, &cfg->show_notes);
 		else
-			disable_display_notes(&notes_opt, &show_notes);
+			disable_display_notes(&cfg->notes_opt, &cfg->show_notes);
 		return 0;
 	}
 	if (!strcmp(var, "format.coverfromdescription")) {
-		cover_from_description_mode = parse_cover_from_description(value);
+		cfg->cover_from_description_mode = parse_cover_from_description(value);
 		return 0;
 	}
 	if (!strcmp(var, "format.mboxrd")) {
@@ -1159,7 +1204,7 @@ static int git_format_config(const char *var, const char *value,
 	if (!strcmp(var, "diff.noprefix"))
 		return 0;
 
-	return git_log_config(var, value, ctx, cb);
+	return git_log_config(var, value, ctx, &cfg->log);
 }
 
 static const char *output_directory = NULL;
@@ -1247,7 +1292,7 @@ static void gen_message_id(struct rev_info *info, char *base)
 	info->message_id = strbuf_detach(&buf, NULL);
 }
 
-static void print_signature(FILE *file)
+static void print_signature(const char *signature, FILE *file)
 {
 	if (!signature || !*signature)
 		return;
@@ -1317,14 +1362,15 @@ static void prepare_cover_text(struct pretty_print_context *pp,
 			       const char *branch_name,
 			       struct strbuf *sb,
 			       const char *encoding,
-			       int need_8bit_cte)
+			       int need_8bit_cte,
+			       const struct format_config *cfg)
 {
 	const char *subject = "*** SUBJECT HERE ***";
 	const char *body = "*** BLURB HERE ***";
 	struct strbuf description_sb = STRBUF_INIT;
 	struct strbuf subject_sb = STRBUF_INIT;
 
-	if (cover_from_description_mode == COVER_FROM_NONE)
+	if (cfg->cover_from_description_mode == COVER_FROM_NONE)
 		goto do_pp;
 
 	if (description_file && *description_file)
@@ -1334,13 +1380,13 @@ static void prepare_cover_text(struct pretty_print_context *pp,
 	if (!description_sb.len)
 		goto do_pp;
 
-	if (cover_from_description_mode == COVER_FROM_SUBJECT ||
-			cover_from_description_mode == COVER_FROM_AUTO)
+	if (cfg->cover_from_description_mode == COVER_FROM_SUBJECT ||
+	    cfg->cover_from_description_mode == COVER_FROM_AUTO)
 		body = format_subject(&subject_sb, description_sb.buf, " ");
 
-	if (cover_from_description_mode == COVER_FROM_MESSAGE ||
-			(cover_from_description_mode == COVER_FROM_AUTO &&
-			 subject_sb.len > COVER_FROM_AUTO_MAX_SUBJECT_LEN))
+	if (cfg->cover_from_description_mode == COVER_FROM_MESSAGE ||
+	    (cfg->cover_from_description_mode == COVER_FROM_AUTO &&
+	     subject_sb.len > COVER_FROM_AUTO_MAX_SUBJECT_LEN))
 		body = description_sb.buf;
 	else
 		subject = subject_sb.buf;
@@ -1377,7 +1423,8 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
 			      int nr, struct commit **list,
 			      const char *description_file,
 			      const char *branch_name,
-			      int quiet)
+			      int quiet,
+			      const struct format_config *cfg)
 {
 	const char *committer;
 	struct shortlog log;
@@ -1416,7 +1463,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
 	pp.encode_email_headers = rev->encode_email_headers;
 	pp_user_info(&pp, NULL, &sb, committer, encoding);
 	prepare_cover_text(&pp, description_file, branch_name, &sb,
-			   encoding, need_8bit_cte);
+			   encoding, need_8bit_cte, cfg);
 	fprintf(rev->diffopt.file, "%s\n", sb.buf);
 
 	free(pp.after_subject);
@@ -1517,29 +1564,30 @@ static const char * const builtin_format_patch_usage[] = {
 	NULL
 };
 
-static int keep_subject = 0;
+struct keep_callback_data {
+	struct format_config *cfg;
+	struct rev_info *revs;
+};
 
 static int keep_callback(const struct option *opt, const char *arg, int unset)
 {
+	struct keep_callback_data *data = opt->value;
 	BUG_ON_OPT_NEG(unset);
 	BUG_ON_OPT_ARG(arg);
-	((struct rev_info *)opt->value)->total = -1;
-	keep_subject = 1;
+	data->revs->total = -1;
+	data->cfg->keep_subject = 1;
 	return 0;
 }
 
-static int subject_prefix = 0;
-
 static int subject_prefix_callback(const struct option *opt, const char *arg,
 			    int unset)
 {
-	struct strbuf *sprefix;
+	struct format_config *cfg = opt->value;
 
 	BUG_ON_OPT_NEG(unset);
-	sprefix = opt->value;
-	subject_prefix = 1;
-	strbuf_reset(sprefix);
-	strbuf_addstr(sprefix, arg);
+	cfg->subject_prefix = 1;
+	strbuf_reset(&cfg->sprefix);
+	strbuf_addstr(&cfg->sprefix, arg);
 	return 0;
 }
 
@@ -1556,15 +1604,14 @@ static int rfc_callback(const struct option *opt, const char *arg,
 	return 0;
 }
 
-static int numbered_cmdline_opt = 0;
-
 static int numbered_callback(const struct option *opt, const char *arg,
 			     int unset)
 {
+	struct format_config *cfg = opt->value;
 	BUG_ON_OPT_ARG(arg);
-	*(int *)opt->value = numbered_cmdline_opt = unset ? 0 : 1;
+	cfg->numbered = cfg->numbered_cmdline_opt = unset ? 0 : 1;
 	if (unset)
-		auto_number =  0;
+		cfg->auto_number =  0;
 	return 0;
 }
 
@@ -1588,13 +1635,14 @@ static int output_directory_callback(const struct option *opt, const char *arg,
 
 static int thread_callback(const struct option *opt, const char *arg, int unset)
 {
-	enum thread_level *thread = (enum thread_level *)opt->value;
+	struct format_config *cfg = opt->value;
+
 	if (unset)
-		*thread = THREAD_UNSET;
+		cfg->thread = THREAD_UNSET;
 	else if (!arg || !strcmp(arg, "shallow"))
-		*thread = THREAD_SHALLOW;
+		cfg->thread = THREAD_SHALLOW;
 	else if (!strcmp(arg, "deep"))
-		*thread = THREAD_DEEP;
+		cfg->thread = THREAD_DEEP;
 	/*
 	 * Please update _git_formatpatch() in git-completion.bash
 	 * when you add new options.
@@ -1630,15 +1678,17 @@ static int inline_callback(const struct option *opt, const char *arg, int unset)
 	return 0;
 }
 
-static int header_callback(const struct option *opt UNUSED, const char *arg,
+static int header_callback(const struct option *opt, const char *arg,
 			   int unset)
 {
+	struct format_config *cfg = opt->value;
+
 	if (unset) {
-		string_list_clear(&extra_hdr, 0);
-		string_list_clear(&extra_to, 0);
-		string_list_clear(&extra_cc, 0);
+		string_list_clear(&cfg->extra_hdr, 0);
+		string_list_clear(&cfg->extra_to, 0);
+		string_list_clear(&cfg->extra_cc, 0);
 	} else {
-		add_header(arg);
+		add_header(cfg, arg);
 	}
 	return 0;
 }
@@ -1660,17 +1710,17 @@ static int from_callback(const struct option *opt, const char *arg, int unset)
 
 static int base_callback(const struct option *opt, const char *arg, int unset)
 {
-	const char **base_commit = opt->value;
+	struct format_config *cfg = opt->value;
 
 	if (unset) {
-		auto_base = AUTO_BASE_NEVER;
-		*base_commit = NULL;
+		cfg->auto_base = AUTO_BASE_NEVER;
+		FREE_AND_NULL(cfg->base_commit);
 	} else if (!strcmp(arg, "auto")) {
-		auto_base = AUTO_BASE_ALWAYS;
-		*base_commit = NULL;
+		cfg->auto_base = AUTO_BASE_ALWAYS;
+		FREE_AND_NULL(cfg->base_commit);
 	} else {
-		auto_base = AUTO_BASE_NEVER;
-		*base_commit = arg;
+		cfg->auto_base = AUTO_BASE_NEVER;
+		cfg->base_commit = xstrdup(arg);
 	}
 	return 0;
 }
@@ -1681,7 +1731,7 @@ struct base_tree_info {
 	struct object_id *patch_id;
 };
 
-static struct commit *get_base_commit(const char *base_commit,
+static struct commit *get_base_commit(const struct format_config *cfg,
 				      struct commit **list,
 				      int total)
 {
@@ -1689,9 +1739,9 @@ static struct commit *get_base_commit(const char *base_commit,
 	struct commit **rev;
 	int i = 0, rev_nr = 0, auto_select, die_on_failure, ret;
 
-	switch (auto_base) {
+	switch (cfg->auto_base) {
 	case AUTO_BASE_NEVER:
-		if (base_commit) {
+		if (cfg->base_commit) {
 			auto_select = 0;
 			die_on_failure = 1;
 		} else {
@@ -1701,11 +1751,11 @@ static struct commit *get_base_commit(const char *base_commit,
 		break;
 	case AUTO_BASE_ALWAYS:
 	case AUTO_BASE_WHEN_ABLE:
-		if (base_commit) {
+		if (cfg->base_commit) {
 			BUG("requested automatic base selection but a commit was provided");
 		} else {
 			auto_select = 1;
-			die_on_failure = auto_base == AUTO_BASE_ALWAYS;
+			die_on_failure = cfg->auto_base == AUTO_BASE_ALWAYS;
 		}
 		break;
 	default:
@@ -1713,9 +1763,9 @@ static struct commit *get_base_commit(const char *base_commit,
 	}
 
 	if (!auto_select) {
-		base = lookup_commit_reference_by_name(base_commit);
+		base = lookup_commit_reference_by_name(cfg->base_commit);
 		if (!base)
-			die(_("unknown commit %s"), base_commit);
+			die(_("unknown commit %s"), cfg->base_commit);
 	} else {
 		struct branch *curr_branch = branch_get(NULL);
 		const char *upstream = branch_get_upstream(curr_branch, NULL);
@@ -1933,7 +1983,7 @@ static void infer_range_diff_ranges(struct strbuf *r1,
 
 int cmd_format_patch(int argc, const char **argv, const char *prefix)
 {
-	struct log_config cfg;
+	struct format_config cfg;
 	struct commit *commit;
 	struct commit **list = NULL;
 	struct rev_info rev;
@@ -1958,7 +2008,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	char *cover_from_description_arg = NULL;
 	char *description_file = NULL;
 	char *branch_name = NULL;
-	char *base_commit = NULL;
 	struct base_tree_info bases;
 	struct commit *base;
 	int show_progress = 0;
@@ -1969,18 +2018,24 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	struct strbuf rdiff1 = STRBUF_INIT;
 	struct strbuf rdiff2 = STRBUF_INIT;
 	struct strbuf rdiff_title = STRBUF_INIT;
-	struct strbuf sprefix = STRBUF_INIT;
 	const char *rfc = NULL;
 	int creation_factor = -1;
+	const char *signature = git_version_string;
+	const char *signature_file_arg = NULL;
+	struct keep_callback_data keep_callback_data = {
+		.cfg = &cfg,
+		.revs = &rev,
+	};
+	const char *fmt_patch_suffix = NULL;
 
 	const struct option builtin_format_patch_options[] = {
-		OPT_CALLBACK_F('n', "numbered", &numbered, NULL,
+		OPT_CALLBACK_F('n', "numbered", &cfg, NULL,
 			    N_("use [PATCH n/m] even with a single patch"),
 			    PARSE_OPT_NOARG, numbered_callback),
-		OPT_CALLBACK_F('N', "no-numbered", &numbered, NULL,
+		OPT_CALLBACK_F('N', "no-numbered", &cfg, NULL,
 			    N_("use [PATCH] even with multiple patches"),
 			    PARSE_OPT_NOARG | PARSE_OPT_NONEG, no_numbered_callback),
-		OPT_BOOL('s', "signoff", &do_signoff, N_("add a Signed-off-by trailer")),
+		OPT_BOOL('s', "signoff", &cfg.do_signoff, N_("add a Signed-off-by trailer")),
 		OPT_BOOL(0, "stdout", &use_stdout,
 			    N_("print patches to standard out")),
 		OPT_BOOL(0, "cover-letter", &cover_letter,
@@ -1993,7 +2048,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 			    N_("start numbering patches at <n> instead of 1")),
 		OPT_STRING('v', "reroll-count", &reroll_count, N_("reroll-count"),
 			    N_("mark the series as Nth re-roll")),
-		OPT_INTEGER(0, "filename-max-length", &cfg.fmt_patch_name_max,
+		OPT_INTEGER(0, "filename-max-length", &cfg.log.fmt_patch_name_max,
 			    N_("max length of output filename")),
 		OPT_CALLBACK_F(0, "rfc", &rfc, N_("rfc"),
 			       N_("add <rfc> (default 'RFC') before 'PATCH'"),
@@ -2003,13 +2058,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 			    N_("generate parts of a cover letter based on a branch's description")),
 		OPT_FILENAME(0, "description-file", &description_file,
 			     N_("use branch description from file")),
-		OPT_CALLBACK_F(0, "subject-prefix", &sprefix, N_("prefix"),
+		OPT_CALLBACK_F(0, "subject-prefix", &cfg, N_("prefix"),
 			    N_("use [<prefix>] instead of [PATCH]"),
 			    PARSE_OPT_NONEG, subject_prefix_callback),
 		OPT_CALLBACK_F('o', "output-directory", &output_directory,
 			    N_("dir"), N_("store resulting files in <dir>"),
 			    PARSE_OPT_NONEG, output_directory_callback),
-		OPT_CALLBACK_F('k', "keep-subject", &rev, NULL,
+		OPT_CALLBACK_F('k', "keep-subject", &keep_callback_data, NULL,
 			    N_("don't strip/add [PATCH]"),
 			    PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback),
 		OPT_BOOL(0, "no-binary", &no_binary_diff,
@@ -2022,11 +2077,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 			      N_("show patch format instead of default (patch + stat)"),
 			      1, PARSE_OPT_NONEG),
 		OPT_GROUP(N_("Messaging")),
-		OPT_CALLBACK(0, "add-header", NULL, N_("header"),
+		OPT_CALLBACK(0, "add-header", &cfg, N_("header"),
 			    N_("add email header"), header_callback),
-		OPT_STRING_LIST(0, "to", &extra_to, N_("email"), N_("add To: header")),
-		OPT_STRING_LIST(0, "cc", &extra_cc, N_("email"), N_("add Cc: header")),
-		OPT_CALLBACK_F(0, "from", &from, N_("ident"),
+		OPT_STRING_LIST(0, "to", &cfg.extra_to, N_("email"), N_("add To: header")),
+		OPT_STRING_LIST(0, "cc", &cfg.extra_cc, N_("email"), N_("add Cc: header")),
+		OPT_CALLBACK_F(0, "from", &cfg.from, N_("ident"),
 			    N_("set From address to <ident> (or committer ident if absent)"),
 			    PARSE_OPT_OPTARG, from_callback),
 		OPT_STRING(0, "in-reply-to", &in_reply_to, N_("message-id"),
@@ -2038,15 +2093,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 			    N_("inline the patch"),
 			    PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
 			    inline_callback),
-		OPT_CALLBACK_F(0, "thread", &thread, N_("style"),
+		OPT_CALLBACK_F(0, "thread", &cfg, N_("style"),
 			    N_("enable message threading, styles: shallow, deep"),
 			    PARSE_OPT_OPTARG, thread_callback),
 		OPT_STRING(0, "signature", &signature, N_("signature"),
 			    N_("add a signature")),
-		OPT_CALLBACK_F(0, "base", &base_commit, N_("base-commit"),
+		OPT_CALLBACK_F(0, "base", &cfg, N_("base-commit"),
 			       N_("add prerequisite tree info to the patch series"),
 			       0, base_callback),
-		OPT_FILENAME(0, "signature-file", &signature_file,
+		OPT_FILENAME(0, "signature-file", &signature_file_arg,
 				N_("add a signature from a file")),
 		OPT__QUIET(&quiet, N_("don't print the patch filenames")),
 		OPT_BOOL(0, "progress", &show_progress,
@@ -2063,21 +2118,17 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 		OPT_END()
 	};
 
-	extra_hdr.strdup_strings = 1;
-	extra_to.strdup_strings = 1;
-	extra_cc.strdup_strings = 1;
-
-	log_config_init(&cfg);
+	format_config_init(&cfg);
 	init_diff_ui_defaults();
-	init_display_notes(&notes_opt);
+	init_display_notes(&cfg.notes_opt);
 	git_config(git_format_config, &cfg);
 	repo_init_revisions(the_repository, &rev, prefix);
 	git_config(grep_config, &rev.grep_filter);
 
-	rev.show_notes = show_notes;
-	memcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));
+	rev.show_notes = cfg.show_notes;
+	memcpy(&rev.notes_opt, &cfg.notes_opt, sizeof(cfg.notes_opt));
 	rev.commit_format = CMIT_FMT_EMAIL;
-	rev.encode_email_headers = cfg.default_encode_email_headers;
+	rev.encode_email_headers = cfg.log.default_encode_email_headers;
 	rev.expand_tabs_in_log_default = 0;
 	rev.verbose_header = 1;
 	rev.diff = 1;
@@ -2088,12 +2139,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	s_r_opt.def = "HEAD";
 	s_r_opt.revarg_opt = REVARG_COMMITTISH;
 
-	strbuf_addstr(&sprefix, cfg.fmt_patch_subject_prefix);
+	strbuf_addstr(&cfg.sprefix, cfg.log.fmt_patch_subject_prefix);
 	if (format_no_prefix)
 		diff_set_noprefix(&rev.diffopt);
 
-	if (default_attach) {
-		rev.mime_boundary = default_attach;
+	if (cfg.default_attach) {
+		rev.mime_boundary = cfg.default_attach;
 		rev.no_inline = 1;
 	}
 
@@ -2109,60 +2160,63 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 
 	rev.force_in_body_from = force_in_body_from;
 
+	if (!fmt_patch_suffix)
+		fmt_patch_suffix = cfg.fmt_patch_suffix;
+
 	/* Make sure "0000-$sub.patch" gives non-negative length for $sub */
-	if (cfg.fmt_patch_name_max <= strlen("0000-") + strlen(fmt_patch_suffix))
-		cfg.fmt_patch_name_max = strlen("0000-") + strlen(fmt_patch_suffix);
+	if (cfg.log.fmt_patch_name_max <= strlen("0000-") + strlen(fmt_patch_suffix))
+		cfg.log.fmt_patch_name_max = strlen("0000-") + strlen(fmt_patch_suffix);
 
 	if (cover_from_description_arg)
-		cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
+		cfg.cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
 
 	if (rfc && rfc[0]) {
-		subject_prefix = 1;
+		cfg.subject_prefix = 1;
 		if (rfc[0] == '-')
-			strbuf_addf(&sprefix, " %s", rfc + 1);
+			strbuf_addf(&cfg.sprefix, " %s", rfc + 1);
 		else
-			strbuf_insertf(&sprefix, 0, "%s ", rfc);
+			strbuf_insertf(&cfg.sprefix, 0, "%s ", rfc);
 	}
 
 	if (reroll_count) {
-		strbuf_addf(&sprefix, " v%s", reroll_count);
+		strbuf_addf(&cfg.sprefix, " v%s", reroll_count);
 		rev.reroll_count = reroll_count;
 	}
 
-	rev.subject_prefix = sprefix.buf;
+	rev.subject_prefix = cfg.sprefix.buf;
 
-	for (i = 0; i < extra_hdr.nr; i++) {
-		strbuf_addstr(&buf, extra_hdr.items[i].string);
+	for (i = 0; i < cfg.extra_hdr.nr; i++) {
+		strbuf_addstr(&buf, cfg.extra_hdr.items[i].string);
 		strbuf_addch(&buf, '\n');
 	}
 
-	if (extra_to.nr)
+	if (cfg.extra_to.nr)
 		strbuf_addstr(&buf, "To: ");
-	for (i = 0; i < extra_to.nr; i++) {
+	for (i = 0; i < cfg.extra_to.nr; i++) {
 		if (i)
 			strbuf_addstr(&buf, "    ");
-		strbuf_addstr(&buf, extra_to.items[i].string);
-		if (i + 1 < extra_to.nr)
+		strbuf_addstr(&buf, cfg.extra_to.items[i].string);
+		if (i + 1 < cfg.extra_to.nr)
 			strbuf_addch(&buf, ',');
 		strbuf_addch(&buf, '\n');
 	}
 
-	if (extra_cc.nr)
+	if (cfg.extra_cc.nr)
 		strbuf_addstr(&buf, "Cc: ");
-	for (i = 0; i < extra_cc.nr; i++) {
+	for (i = 0; i < cfg.extra_cc.nr; i++) {
 		if (i)
 			strbuf_addstr(&buf, "    ");
-		strbuf_addstr(&buf, extra_cc.items[i].string);
-		if (i + 1 < extra_cc.nr)
+		strbuf_addstr(&buf, cfg.extra_cc.items[i].string);
+		if (i + 1 < cfg.extra_cc.nr)
 			strbuf_addch(&buf, ',');
 		strbuf_addch(&buf, '\n');
 	}
 
 	rev.extra_headers = to_free = strbuf_detach(&buf, NULL);
 
-	if (from) {
-		if (split_ident_line(&rev.from_ident, from, strlen(from)))
-			die(_("invalid ident line: %s"), from);
+	if (cfg.from) {
+		if (split_ident_line(&rev.from_ident, cfg.from, strlen(cfg.from)))
+			die(_("invalid ident line: %s"), cfg.from);
 	}
 
 	if (start_number < 0)
@@ -2173,14 +2227,14 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	 * and it would conflict with --keep-subject (-k) from the
 	 * command line, reset "numbered".
 	 */
-	if (numbered && keep_subject && !numbered_cmdline_opt)
-		numbered = 0;
+	if (cfg.numbered && cfg.keep_subject && !cfg.numbered_cmdline_opt)
+		cfg.numbered = 0;
 
-	if (numbered && keep_subject)
+	if (cfg.numbered && cfg.keep_subject)
 		die(_("options '%s' and '%s' cannot be used together"), "-n", "-k");
-	if (keep_subject && subject_prefix)
+	if (cfg.keep_subject && cfg.subject_prefix)
 		die(_("options '%s' and '%s' cannot be used together"), "--subject-prefix/--rfc", "-k");
-	rev.preserve_subject = keep_subject;
+	rev.preserve_subject = cfg.keep_subject;
 
 	argc = setup_revisions(argc, argv, &rev, &s_r_opt);
 	if (argc > 1)
@@ -2207,7 +2261,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	rev.always_show_header = 1;
 
 	rev.zero_commit = zero_commit;
-	rev.patch_name_max = cfg.fmt_patch_name_max;
+	rev.patch_name_max = cfg.log.fmt_patch_name_max;
 
 	if (!rev.diffopt.flags.text && !no_binary_diff)
 		rev.diffopt.flags.binary = 1;
@@ -2228,7 +2282,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 		int saved;
 
 		if (!output_directory)
-			output_directory = config_output_directory;
+			output_directory = cfg.config_output_directory;
 		output_directory = set_outdir(prefix, output_directory);
 
 		if (rev.diffopt.use_color != GIT_COLOR_ALWAYS)
@@ -2326,14 +2380,14 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 		goto done;
 	total = nr;
 	if (cover_letter == -1) {
-		if (config_cover_letter == COVER_AUTO)
+		if (cfg.config_cover_letter == COVER_AUTO)
 			cover_letter = (total > 1);
 		else
-			cover_letter = (config_cover_letter == COVER_ON);
+			cover_letter = (cfg.config_cover_letter == COVER_ON);
 	}
-	if (!keep_subject && auto_number && (total > 1 || cover_letter))
-		numbered = 1;
-	if (numbered)
+	if (!cfg.keep_subject && cfg.auto_number && (total > 1 || cover_letter))
+		cfg.numbered = 1;
+	if (cfg.numbered)
 		rev.total = total + start_number - 1;
 
 	if (idiff_prev.nr) {
@@ -2365,27 +2419,40 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 					     _("Range-diff against v%d:"));
 	}
 
+	/*
+	 * The order of precedence is:
+	 *
+	 *   1. The `--signature` and `--no-signature` options.
+	 *   2. The `--signature-file` option.
+	 *   3. The `format.signature` config.
+	 *   4. The `format.signatureFile` config.
+	 *   5. Default `git_version_string`.
+	 */
 	if (!signature) {
 		; /* --no-signature inhibits all signatures */
 	} else if (signature && signature != git_version_string) {
 		; /* non-default signature already set */
-	} else if (signature_file) {
+	} else if (signature_file_arg || (cfg.signature_file && !cfg.signature)) {
 		struct strbuf buf = STRBUF_INIT;
+		const char *signature_file = signature_file_arg ?
+			signature_file_arg : cfg.signature_file;
 
 		if (strbuf_read_file(&buf, signature_file, 128) < 0)
 			die_errno(_("unable to read signature file '%s'"), signature_file);
 		signature = strbuf_detach(&buf, NULL);
+	} else if (cfg.signature) {
+		signature = cfg.signature;
 	}
 
 	memset(&bases, 0, sizeof(bases));
-	base = get_base_commit(base_commit, list, nr);
+	base = get_base_commit(&cfg, list, nr);
 	if (base) {
 		reset_revision_walk();
 		clear_object_flags(UNINTERESTING);
 		prepare_bases(&bases, base, list, nr);
 	}
 
-	if (in_reply_to || thread || cover_letter) {
+	if (in_reply_to || cfg.thread || cover_letter) {
 		rev.ref_message_ids = xmalloc(sizeof(*rev.ref_message_ids));
 		string_list_init_dup(rev.ref_message_ids);
 	}
@@ -2396,19 +2463,19 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	rev.numbered_files = just_numbers;
 	rev.patch_suffix = fmt_patch_suffix;
 	if (cover_letter) {
-		if (thread)
+		if (cfg.thread)
 			gen_message_id(&rev, "cover");
 		make_cover_letter(&rev, !!output_directory,
-				  origin, nr, list, description_file, branch_name, quiet);
+				  origin, nr, list, description_file, branch_name, quiet, &cfg);
 		print_bases(&bases, rev.diffopt.file);
-		print_signature(rev.diffopt.file);
+		print_signature(signature, rev.diffopt.file);
 		total++;
 		start_number--;
 		/* interdiff/range-diff in cover-letter; omit from patches */
 		rev.idiff_oid1 = NULL;
 		rev.rdiff1 = NULL;
 	}
-	rev.add_signoff = do_signoff;
+	rev.add_signoff = cfg.do_signoff;
 
 	if (show_progress)
 		progress = start_delayed_progress(_("Generating patches"), total);
@@ -2418,7 +2485,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 		commit = list[nr];
 		rev.nr = total - nr + (start_number - 1);
 		/* Make the second and subsequent mails replies to the first */
-		if (thread) {
+		if (cfg.thread) {
 			/* Have we already had a message ID? */
 			if (rev.message_id) {
 				/*
@@ -2442,7 +2509,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 				 * letter is a reply to the
 				 * --in-reply-to, if specified.
 				 */
-				if (thread == THREAD_SHALLOW
+				if (cfg.thread == THREAD_SHALLOW
 				    && rev.ref_message_ids->nr > 0
 				    && (!cover_letter || rev.nr > 1))
 					free(rev.message_id);
@@ -2475,7 +2542,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 				       mime_boundary_leader,
 				       rev.mime_boundary);
 			else
-				print_signature(rev.diffopt.file);
+				print_signature(signature, rev.diffopt.file);
 		}
 		if (output_directory)
 			fclose(rev.diffopt.file);
@@ -2483,9 +2550,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	stop_progress(&progress);
 	free(list);
 	free(branch_name);
-	string_list_clear(&extra_to, 0);
-	string_list_clear(&extra_cc, 0);
-	string_list_clear(&extra_hdr, 0);
 	if (ignore_if_in_upstream)
 		free_patch_ids(&ids);
 
@@ -2495,14 +2559,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	strbuf_release(&rdiff1);
 	strbuf_release(&rdiff2);
 	strbuf_release(&rdiff_title);
-	strbuf_release(&sprefix);
 	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);
 	release_revisions(&rev);
-	log_config_release(&cfg);
+	format_config_release(&cfg);
 	return 0;
 }
 
-- 
2.45.1.216.g4365c6fcf9.dirty
Previous: Patrick SteinhardtNext: Patrick Steinhardt
Message 19 of 115 in “Various memory leak fixes”
  1. 00/20 Various memory leak fixesPatrick Steinhardt, May 23, 2024
  2. 01/20 t: mark a bunch of tests as leak-freePatrick Steinhardt, May 23, 2024
  3. Junio C HamanoMay 23, 2024
  4. Patrick SteinhardtMay 24, 2024
  5. Junio C HamanoMay 24, 2024
  6. Junio C HamanoMay 24, 2024
  7. Karthik NayakMay 24, 2024
  8. 02/20 transport-helper: fix leaking helper namePatrick Steinhardt, May 23, 2024
  9. Junio C HamanoMay 23, 2024
  10. Karthik NayakMay 24, 2024
  11. 03/20 strbuf: fix leak when `appendwholeline()` fails with EOFPatrick Steinhardt, May 23, 2024
  12. 04/20 checkout: clarify memory ownership in `unique_tracking_name()`Patrick Steinhardt, May 23, 2024
  13. 05/20 http: refactor code to clarify memory ownershipPatrick Steinhardt, May 23, 2024
  14. 06/20 config: clarify memory ownership in `git_config_pathname()`Patrick Steinhardt, May 23, 2024
  15. 07/20 diff: refactor code to clarify memory ownership of prefixesPatrick Steinhardt, May 23, 2024
  16. Eric SunshineMay 23, 2024
  17. 08/20 convert: refactor code to clarify ownership of check_roundtrip_encodingPatrick Steinhardt, May 23, 2024
  18. 09/20 builtin/log: stop using globals for log configPatrick Steinhardt, May 23, 2024
  19. 10/20 builtin/log: stop using globals for format configPatrick Steinhardt, May 23, 2024
  20. 11/20 config: clarify memory ownership in `git_config_string()`Patrick Steinhardt, May 23, 2024
  21. 12/20 config: plug various memory leaksPatrick Steinhardt, May 23, 2024
  22. Junio C HamanoMay 23, 2024
  23. Patrick SteinhardtMay 24, 2024
  24. Patrick SteinhardtMay 24, 2024
  25. Junio C HamanoMay 24, 2024
  26. Junio C HamanoMay 24, 2024
  27. 13/20 builtin/credential: clear credential before exitPatrick Steinhardt, May 23, 2024
  28. 14/20 commit-reach: fix memory leak in `ahead_behind()`Patrick Steinhardt, May 23, 2024
  29. 15/20 submodule: fix leaking memory for submodule entriesPatrick Steinhardt, May 23, 2024
  30. 16/20 strvec: add functions to replace and remove stringsPatrick Steinhardt, May 23, 2024
  31. Eric SunshineMay 23, 2024
  32. Patrick SteinhardtMay 24, 2024
  33. 17/20 builtin/mv: refactor `add_slash()` to always return allocated stringsPatrick Steinhardt, May 23, 2024
  34. 18/20 builtin/mv duplicate string list memoryPatrick Steinhardt, May 23, 2024
  35. 19/20 builtin/mv: refactor to use `struct strvec`Patrick Steinhardt, May 23, 2024
  36. 20/20 builtin/mv: fix leaks for submodule gitfile pathsPatrick Steinhardt, May 23, 2024
  37. Junio C HamanoMay 23, 2024
  38. Patrick SteinhardtMay 24, 2024
  39. 00/21 Various memory leak fixesPatrick Steinhardt, May 24, 2024
  40. 01/21 ci: add missing dependency for TTY prereqPatrick Steinhardt, May 24, 2024
  41. Junio C HamanoMay 24, 2024
  42. 02/21 t: mark a bunch of tests as leak-freePatrick Steinhardt, May 24, 2024
  43. 03/21 transport-helper: fix leaking helper namePatrick Steinhardt, May 24, 2024
  44. 04/21 strbuf: fix leak when `appendwholeline()` fails with EOFPatrick Steinhardt, May 24, 2024
  45. Jeff KingMay 25, 2024
  46. Patrick SteinhardtMay 27, 2024
  47. Jeff KingMay 29, 2024
  48. Patrick SteinhardtMay 29, 2024
  49. Jeff KingMay 30, 2024
  50. 05/21 checkout: clarify memory ownership in `unique_tracking_name()`Patrick Steinhardt, May 24, 2024
  51. 06/21 http: refactor code to clarify memory ownershipPatrick Steinhardt, May 24, 2024
  52. 07/21 config: clarify memory ownership in `git_config_pathname()`Patrick Steinhardt, May 24, 2024
  53. 08/21 diff: refactor code to clarify memory ownership of prefixesPatrick Steinhardt, May 24, 2024
  54. 09/21 convert: refactor code to clarify ownership of check_roundtrip_encodingPatrick Steinhardt, May 24, 2024
  55. 10/21 builtin/log: stop using globals for log configPatrick Steinhardt, May 24, 2024
  56. 11/21 builtin/log: stop using globals for format configPatrick Steinhardt, May 24, 2024
  57. 12/21 config: clarify memory ownership in `git_config_string()`Patrick Steinhardt, May 24, 2024
  58. 13/21 config: plug various memory leaksPatrick Steinhardt, May 24, 2024
  59. Patrick SteinhardtMay 24, 2024
  60. Jeff KingMay 25, 2024
  61. Patrick SteinhardtMay 27, 2024
  62. Jeff KingMay 29, 2024
  63. 14/21 builtin/credential: clear credential before exitPatrick Steinhardt, May 24, 2024
  64. 15/21 commit-reach: fix memory leak in `ahead_behind()`Patrick Steinhardt, May 24, 2024
  65. 16/21 submodule: fix leaking memory for submodule entriesPatrick Steinhardt, May 24, 2024
  66. 17/21 strvec: add functions to replace and remove stringsPatrick Steinhardt, May 24, 2024
  67. 18/21 builtin/mv: refactor `add_slash()` to always return allocated stringsPatrick Steinhardt, May 24, 2024
  68. 19/21 builtin/mv duplicate string list memoryPatrick Steinhardt, May 24, 2024
  69. 20/21 builtin/mv: refactor to use `struct strvec`Patrick Steinhardt, May 24, 2024
  70. 21/21 builtin/mv: fix leaks for submodule gitfile pathsPatrick Steinhardt, May 24, 2024
  71. Junio C HamanoMay 25, 2024
  72. Patrick SteinhardtMay 27, 2024
  73. Junio C HamanoMay 27, 2024
  74. Junio C HamanoMay 27, 2024
  75. Patrick SteinhardtMay 28, 2024
  76. Karthik NayakMay 29, 2024
  77. 00/21 Various memory leak fixesPatrick Steinhardt, May 27, 2024
  78. 01/21 ci: add missing dependency for TTY prereqPatrick Steinhardt, May 27, 2024
  79. 02/21 t: mark a bunch of tests as leak-freePatrick Steinhardt, May 27, 2024
  80. 03/21 transport-helper: fix leaking helper namePatrick Steinhardt, May 27, 2024
  81. 04/21 strbuf: fix leak when `appendwholeline()` fails with EOFPatrick Steinhardt, May 27, 2024
  82. 05/21 checkout: clarify memory ownership in `unique_tracking_name()`Patrick Steinhardt, May 27, 2024
  83. 06/21 http: refactor code to clarify memory ownershipPatrick Steinhardt, May 27, 2024
  84. 07/21 config: clarify memory ownership in `git_config_pathname()`Patrick Steinhardt, May 27, 2024
  85. 08/21 diff: refactor code to clarify memory ownership of prefixesPatrick Steinhardt, May 27, 2024
  86. 09/21 convert: refactor code to clarify ownership of check_roundtrip_encodingPatrick Steinhardt, May 27, 2024
  87. 10/21 builtin/log: stop using globals for log configPatrick Steinhardt, May 27, 2024
  88. 11/21 builtin/log: stop using globals for format configPatrick Steinhardt, May 27, 2024
  89. 12/21 config: clarify memory ownership in `git_config_string()`Patrick Steinhardt, May 27, 2024
  90. 13/21 config: plug various memory leaksPatrick Steinhardt, May 27, 2024
  91. 14/21 builtin/credential: clear credential before exitPatrick Steinhardt, May 27, 2024
  92. 15/21 commit-reach: fix memory leak in `ahead_behind()`Patrick Steinhardt, May 27, 2024
  93. 16/21 submodule: fix leaking memory for submodule entriesPatrick Steinhardt, May 27, 2024
  94. 17/21 strvec: add functions to replace and remove stringsPatrick Steinhardt, May 27, 2024
  95. 18/21 builtin/mv: refactor `add_slash()` to always return allocated stringsPatrick Steinhardt, May 27, 2024
  96. 19/21 builtin/mv duplicate string list memoryPatrick Steinhardt, May 27, 2024
  97. 20/21 builtin/mv: refactor to use `struct strvec`Patrick Steinhardt, May 27, 2024
  98. 21/21 builtin/mv: fix leaks for submodule gitfile pathsPatrick Steinhardt, May 27, 2024
  99. Junio C HamanoMay 27, 2024
  100. 0/5 add-ons for ps/leakfixesJeff King, May 30, 2024
  101. 1/5 t-strvec: use va_end() to match va_start()Jeff King, May 30, 2024
  102. 2/5 t-strvec: mark variable-arg helper with LAST_ARG_MUST_BE_NULLJeff King, May 30, 2024
  103. 3/5 mv: move src_dir cleanup to end of cmd_mv()Jeff King, May 30, 2024
  104. Patrick SteinhardtMay 30, 2024
  105. Jeff KingMay 30, 2024
  106. Patrick SteinhardtMay 30, 2024
  107. Jeff KingMay 30, 2024
  108. Patrick SteinhardtMay 30, 2024
  109. Jeff KingMay 30, 2024
  110. 4/5 mv: factor out empty src_dir removalJeff King, May 30, 2024
  111. 5/5 mv: replace src_dir with a strvecJeff King, May 30, 2024
  112. Junio C HamanoMay 30, 2024
  113. Jeff KingMay 31, 2024
  114. Junio C HamanoMay 31, 2024
  115. Patrick SteinhardtMay 30, 2024

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.