aboutsummaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2026-03-19 09:54:56 -0700
committerJunio C Hamano <gitster@pobox.com>2026-03-19 09:54:56 -0700
commitaccd0e107bb36cbcdb158f8bb19d5bae589294a9 (patch)
tree9c127dab3844830d92aaf884a0f1037d11d5a3c3 /builtin
parenta7a079c2c4bc7b269229a6ea6c147b6b2d5b2684 (diff)
parente4f9d6b0ab2e1903765258991a6265599d0007ce (diff)
downloadgit-accd0e107bb36cbcdb158f8bb19d5bae589294a9.tar.xz
Merge branch 'lc/rebase-trailer'
"git rebase" learns "--trailer" command to drive the interpret-trailers machinery. * lc/rebase-trailer: rebase: support --trailer commit, tag: parse --trailer with OPT_STRVEC trailer: append trailers without fork/exec trailer: libify a couple of functions interpret-trailers: refactor create_in_place_tempfile() interpret-trailers: factor trailer rewriting
Diffstat (limited to 'builtin')
-rw-r--r--builtin/commit.c6
-rw-r--r--builtin/interpret-trailers.c87
-rw-r--r--builtin/rebase.c19
-rw-r--r--builtin/tag.c7
4 files changed, 45 insertions, 74 deletions
diff --git a/builtin/commit.c b/builtin/commit.c
index 7b23c1f883..02a04f68be 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1720,7 +1720,8 @@ int cmd_commit(int argc,
OPT_STRING(0, "fixup", &fixup_message, N_("[(amend|reword):]commit"), N_("use autosquash formatted message to fixup or amend/reword specified commit")),
OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash specified commit")),
OPT_BOOL(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")),
- OPT_PASSTHRU_ARGV(0, "trailer", &trailer_args, N_("trailer"), N_("add custom trailer(s)"), PARSE_OPT_NONEG),
+ OPT_STRVEC(0, "trailer", &trailer_args, N_("trailer"),
+ N_("add custom trailer(s)")),
OPT_BOOL('s', "signoff", &signoff, N_("add a Signed-off-by trailer")),
OPT_FILENAME('t', "template", &template_file, N_("use specified template file")),
OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
@@ -1820,6 +1821,9 @@ int cmd_commit(int argc,
argc = parse_and_validate_options(argc, argv, builtin_commit_options,
builtin_commit_usage,
prefix, current_head, &s);
+ if (trailer_args.nr)
+ trailer_config_init();
+
if (verbose == -1)
verbose = (config_commit_verbose < 0) ? 0 : config_commit_verbose;
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index 41b0750e5a..acaf42b2d9 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -93,37 +93,6 @@ static int parse_opt_parse(const struct option *opt, const char *arg,
return 0;
}
-static struct tempfile *trailers_tempfile;
-
-static FILE *create_in_place_tempfile(const char *file)
-{
- struct stat st;
- struct strbuf filename_template = STRBUF_INIT;
- const char *tail;
- FILE *outfile;
-
- if (stat(file, &st))
- die_errno(_("could not stat %s"), file);
- if (!S_ISREG(st.st_mode))
- die(_("file %s is not a regular file"), file);
- if (!(st.st_mode & S_IWUSR))
- die(_("file %s is not writable by user"), file);
-
- /* Create temporary file in the same directory as the original */
- tail = strrchr(file, '/');
- if (tail)
- strbuf_add(&filename_template, file, tail - file + 1);
- strbuf_addstr(&filename_template, "git-interpret-trailers-XXXXXX");
-
- trailers_tempfile = xmks_tempfile_m(filename_template.buf, st.st_mode);
- strbuf_release(&filename_template);
- outfile = fdopen_tempfile(trailers_tempfile, "w");
- if (!outfile)
- die_errno(_("could not open temporary file"));
-
- return outfile;
-}
-
static void read_input_file(struct strbuf *sb, const char *file)
{
if (file) {
@@ -140,55 +109,31 @@ static void interpret_trailers(const struct process_trailer_options *opts,
struct list_head *new_trailer_head,
const char *file)
{
- LIST_HEAD(head);
- struct strbuf sb = STRBUF_INIT;
- struct strbuf trailer_block_sb = STRBUF_INIT;
- struct trailer_block *trailer_block;
- FILE *outfile = stdout;
+ struct strbuf input = STRBUF_INIT;
+ struct strbuf out = STRBUF_INIT;
+ struct tempfile *tempfile = NULL;
+ int fd = 1;
trailer_config_init();
- read_input_file(&sb, file);
+ read_input_file(&input, file);
- if (opts->in_place)
- outfile = create_in_place_tempfile(file);
-
- trailer_block = parse_trailers(opts, sb.buf, &head);
-
- /* Print the lines before the trailer block */
- if (!opts->only_trailers)
- fwrite(sb.buf, 1, trailer_block_start(trailer_block), outfile);
-
- if (!opts->only_trailers && !blank_line_before_trailer_block(trailer_block))
- fprintf(outfile, "\n");
-
-
- if (!opts->only_input) {
- LIST_HEAD(config_head);
- LIST_HEAD(arg_head);
- parse_trailers_from_config(&config_head);
- parse_trailers_from_command_line_args(&arg_head, new_trailer_head);
- list_splice(&config_head, &arg_head);
- process_trailers_lists(&head, &arg_head);
+ if (opts->in_place) {
+ tempfile = trailer_create_in_place_tempfile(file);
+ if (!tempfile)
+ die(NULL);
+ fd = tempfile->fd;
}
+ process_trailers(opts, new_trailer_head, &input, &out);
- /* Print trailer block. */
- format_trailers(opts, &head, &trailer_block_sb);
- free_trailers(&head);
- fwrite(trailer_block_sb.buf, 1, trailer_block_sb.len, outfile);
- strbuf_release(&trailer_block_sb);
-
- /* Print the lines after the trailer block as is. */
- if (!opts->only_trailers)
- fwrite(sb.buf + trailer_block_end(trailer_block), 1,
- sb.len - trailer_block_end(trailer_block), outfile);
- trailer_block_release(trailer_block);
-
+ if (write_in_full(fd, out.buf, out.len) < 0)
+ die_errno(_("could not write to temporary file '%s'"), file);
if (opts->in_place)
- if (rename_tempfile(&trailers_tempfile, file))
+ if (rename_tempfile(&tempfile, file))
die_errno(_("could not rename temporary file to %s"), file);
- strbuf_release(&sb);
+ strbuf_release(&input);
+ strbuf_release(&out);
}
int cmd_interpret_trailers(int argc,
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 8c1316db38..a1c7d78196 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -36,6 +36,7 @@
#include "reset.h"
#include "trace2.h"
#include "hook.h"
+#include "trailer.h"
static char const * const builtin_rebase_usage[] = {
N_("git rebase [-i] [options] [--exec <cmd>] "
@@ -113,6 +114,7 @@ struct rebase_options {
enum action action;
char *reflog_action;
int signoff;
+ struct strvec trailer_args;
int allow_rerere_autoupdate;
int keep_empty;
int autosquash;
@@ -143,6 +145,7 @@ struct rebase_options {
.flags = REBASE_NO_QUIET, \
.git_am_opts = STRVEC_INIT, \
.exec = STRING_LIST_INIT_NODUP, \
+ .trailer_args = STRVEC_INIT, \
.git_format_patch_opt = STRBUF_INIT, \
.fork_point = -1, \
.reapply_cherry_picks = -1, \
@@ -166,6 +169,7 @@ static void rebase_options_release(struct rebase_options *opts)
free(opts->strategy);
string_list_clear(&opts->strategy_opts, 0);
strbuf_release(&opts->git_format_patch_opt);
+ strvec_clear(&opts->trailer_args);
}
static struct replay_opts get_replay_opts(const struct rebase_options *opts)
@@ -177,6 +181,10 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
sequencer_init_config(&replay);
replay.signoff = opts->signoff;
+
+ for (size_t i = 0; i < opts->trailer_args.nr; i++)
+ strvec_push(&replay.trailer_args, opts->trailer_args.v[i]);
+
replay.allow_ff = !(opts->flags & REBASE_FORCE);
if (opts->allow_rerere_autoupdate)
replay.allow_rerere_auto = opts->allow_rerere_autoupdate;
@@ -1134,6 +1142,8 @@ int cmd_rebase(int argc,
.flags = PARSE_OPT_NOARG,
.defval = REBASE_DIFFSTAT,
},
+ OPT_STRVEC(0, "trailer", &options.trailer_args, N_("trailer"),
+ N_("add custom trailer(s)")),
OPT_BOOL(0, "signoff", &options.signoff,
N_("add a Signed-off-by trailer to each commit")),
OPT_BOOL(0, "committer-date-is-author-date",
@@ -1287,6 +1297,12 @@ int cmd_rebase(int argc,
builtin_rebase_options,
builtin_rebase_usage, 0);
+ if (options.trailer_args.nr) {
+ if (validate_trailer_args(&options.trailer_args))
+ die(NULL);
+ options.flags |= REBASE_FORCE;
+ }
+
if (preserve_merges_selected)
die(_("--preserve-merges was replaced by --rebase-merges\n"
"Note: Your `pull.rebase` configuration may also be set to 'preserve',\n"
@@ -1544,6 +1560,9 @@ int cmd_rebase(int argc,
if (options.root && !options.onto_name)
imply_merge(&options, "--root without --onto");
+ if (options.trailer_args.nr)
+ imply_merge(&options, "--trailer");
+
if (isatty(2) && options.flags & REBASE_NO_QUIET)
strbuf_addstr(&options.git_format_patch_opt, " --progress");
diff --git a/builtin/tag.c b/builtin/tag.c
index aeb04c487f..e0f05f94fd 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -499,8 +499,8 @@ int cmd_tag(int argc,
OPT_CALLBACK_F('m', "message", &msg, N_("message"),
N_("tag message"), PARSE_OPT_NONEG, parse_msg_arg),
OPT_FILENAME('F', "file", &msgfile, N_("read message from file")),
- OPT_PASSTHRU_ARGV(0, "trailer", &trailer_args, N_("trailer"),
- N_("add custom trailer(s)"), PARSE_OPT_NONEG),
+ OPT_STRVEC(0, "trailer", &trailer_args, N_("trailer"),
+ N_("add custom trailer(s)")),
OPT_BOOL('e', "edit", &edit_flag, N_("force edit of tag message")),
OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")),
OPT_CLEANUP(&cleanup_arg),
@@ -568,6 +568,9 @@ int cmd_tag(int argc,
if (cmdmode == 'l')
setup_auto_pager("tag", 1);
+ if (trailer_args.nr)
+ trailer_config_init();
+
if (opt.sign == -1)
opt.sign = cmdmode ? 0 : config_sign_tag > 0;