All of lore.kernel.org
 help / color / mirror / Atom feed
From: Phillip Wood <phillip.wood123@gmail.com>
To: Li Chen <me@linux.beauty>, phillipwood <phillip.wood@dunelm.org.uk>
Cc: git <git@vger.kernel.org>, Junio C Hamano <gitster@pobox.com>,
	Kristoffer Haugsbakk <kristofferhaugsbakk@fastmail.com>
Subject: Re: [PATCH v7 0/5] rebase: support --trailer
Date: Fri, 6 Mar 2026 14:55:48 +0000	[thread overview]
Message-ID: <8a37a357-5a3b-4ca1-9949-6b2f28d3f208@gmail.com> (raw)
In-Reply-To: <19cbe42b2cd.bb6e3883730656.6495265672263159010@linux.beauty>

Hi Li

On 05/03/2026 13:49, Li Chen wrote:
>   >
>   > This all looks pretty good. The main thing I think we want to change is
>   > sharing the code that creates the temporary file in patch 3. I've push a
>   > version that does that and fixes my other small comments to
>   > https://github.com/phillipwood/git/commits/refs/heads/rebase-trailers-v8
>   > The range diff is below. If you're happy I can post that as a hopefully
>   > final v8. Of course if you want to work on it yourself you're very
>   > welcome to do that.
> 
> These changes all look good to me! Thank you very much for your patience and work! Please help
> post this as v8.

I've just posted v8, thanks for all your work on these patches

Phillip

> Regards,
> Li
> 
>   >
>   > 1:  b2685e34c22 ! 1:  0d08b361995 interpret-trailers: factor trailer rewriting
>   >      @@ Commit message
>   >           This separation makes it easier to move the helper into trailer.c in the
>   >           next commit.
>   >
>   >      +    Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
>   >           Signed-off-by: Li Chen <me@linux.beauty>
>   >
>   >        ## builtin/interpret-trailers.c ##
>   >       @@ builtin/interpret-trailers.c: static void read_input_file(struct strbuf *sb, const char *file)
>   > -:  ----------- > 2:  5a4d03ab375 interpret-trailers: refactor create_in_place_tempfile()
>   > 2:  1bac3025045 ! 3:  ab7e232a95d trailer: move process_trailers to trailer.h
>   >      @@ Metadata
>   >       Author: Li Chen <me@linux.beauty>
>   >
>   >        ## Commit message ##
>   >      -    trailer: move process_trailers to trailer.h
>   >      -
>   >      -    Move process_trailers() from builtin/interpret-trailers.c into trailer.c
>   >      -    and expose it via trailer.h.
>   >      -
>   >      -    This lets other call sites reuse the same trailer rewriting logic.
>   >      +    trailer: libify a couple of functions
>   >      +
>   >      +    Move create_in_place_tempfile() and process_trailers() from
>   >      +    builtin/interpret-trailers.c into trailer.c and expose it via trailer.h.
>   >      +
>   >      +    This reverts most of ae0ec2e0e0b (trailer: move interpret_trailers()
>   >      +    to interpret-trailers.c, 2024-03-01) and lets other call sites reuse
>   >      +    the same trailer rewriting logic.
>   >
>   >           Signed-off-by: Li Chen <me@linux.beauty>
>   >      +    Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
>   >
>   >        ## builtin/interpret-trailers.c ##
>   >      +@@ builtin/interpret-trailers.c: static int parse_opt_parse(const struct option *opt, const char *arg,
>   >      +     return 0;
>   >      + }
>   >      +
>   >      +-
>   >      +-static struct tempfile *create_in_place_tempfile(const char *file)
>   >      +-{
>   >      +-    struct tempfile *tempfile = NULL;
>   >      +-    struct stat st;
>   >      +-    struct strbuf filename_template = STRBUF_INIT;
>   >      +-    const char *tail;
>   >      +-
>   >      +-    if (stat(file, &st)) {
>   >      +-        error_errno(_("could not stat %s"), file);
>   >      +-        return NULL;
>   >      +-    }
>   >      +-    if (!S_ISREG(st.st_mode)) {
>   >      +-        error(_("file %s is not a regular file"), file);
>   >      +-        return NULL;
>   >      +-    }
>   >      +-    if (!(st.st_mode & S_IWUSR)) {
>   >      +-        error(_("file %s is not writable by user"), file);
>   >      +-        return NULL;
>   >      +-    }
>   >      +-    /* Create temporary file in the same directory as the original */
>   >      +-    tail = find_last_dir_sep(file);
>   >      +-    if (tail)
>   >      +-        strbuf_add(&filename_template, file, tail - file + 1);
>   >      +-    strbuf_addstr(&filename_template, "git-interpret-trailers-XXXXXX");
>   >      +-
>   >      +-    tempfile = mks_tempfile_m(filename_template.buf, st.st_mode);
>   >      +-
>   >      +-    strbuf_release(&filename_template);
>   >      +-
>   >      +-    return tempfile;
>   >      +-}
>   >      +-
>   >      + static void read_input_file(struct strbuf *sb, const char *file)
>   >      + {
>   >      +     if (file) {
>   >       @@ builtin/interpret-trailers.c: static void read_input_file(struct strbuf *sb, const char *file)
>   >            strbuf_complete_line(sb);
>   >        }
>   >      @@ builtin/interpret-trailers.c: static void read_input_file(struct strbuf *sb, con
>   >        static void interpret_trailers(const struct process_trailer_options *opts,
>   >                           struct list_head *new_trailer_head,
>   >                           const char *file)
>   >      +@@ builtin/interpret-trailers.c: static void interpret_trailers(const struct process_trailer_options *opts,
>   >      +     read_input_file(&input, file);
>   >      +
>   >      +     if (opts->in_place) {
>   >      +-        tempfile = create_in_place_tempfile(file);
>   >      ++        tempfile = trailer_create_in_place_tempfile(file);
>   >      +         if (!tempfile)
>   >      +             die(NULL);
>   >      +         fd = tempfile->fd;
>   >
>   >        ## trailer.c ##
>   >      +@@
>   >      + #include "commit.h"
>   >      + #include "trailer.h"
>   >      + #include "list.h"
>   >      ++#include "tempfile.h"
>   >      ++
>   >      + /*
>   >      +  * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
>   >      +  */
>   >      +@@ trailer.c: void trailer_iterator_release(struct trailer_iterator *iter)
>   >      +     strbuf_release(&iter->key);
>   >      + }
>   >      +
>   >      ++struct tempfile *trailer_create_in_place_tempfile(const char *file)
>   >      ++{
>   >      ++    struct tempfile *tempfile = NULL;
>   >      ++    struct stat st;
>   >      ++    struct strbuf filename_template = STRBUF_INIT;
>   >      ++    const char *tail;
>   >      ++
>   >      ++    if (stat(file, &st)) {
>   >      ++        error_errno(_("could not stat %s"), file);
>   >      ++        return NULL;
>   >      ++    }
>   >      ++    if (!S_ISREG(st.st_mode)) {
>   >      ++        error(_("file %s is not a regular file"), file);
>   >      ++        return NULL;
>   >      ++    }
>   >      ++    if (!(st.st_mode & S_IWUSR)) {
>   >      ++        error(_("file %s is not writable by user"), file);
>   >      ++        return NULL;
>   >      ++    }
>   >      ++    /* Create temporary file in the same directory as the original */
>   >      ++    tail = find_last_dir_sep(file);
>   >      ++    if (tail)
>   >      ++        strbuf_add(&filename_template, file, tail - file + 1);
>   >      ++    strbuf_addstr(&filename_template, "git-interpret-trailers-XXXXXX");
>   >      ++
>   >      ++    tempfile = mks_tempfile_m(filename_template.buf, st.st_mode);
>   >      ++
>   >      ++    strbuf_release(&filename_template);
>   >      ++
>   >      ++    return tempfile;
>   >      ++}
>   >      ++
>   >      + int amend_file_with_trailers(const char *path, const struct strvec *trailer_args)
>   >      + {
>   >      +     struct child_process run_trailer = CHILD_PROCESS_INIT;
>   >       @@ trailer.c: int amend_file_with_trailers(const char *path, const struct strvec *trailer_args
>   >            strvec_pushv(&run_trailer.args, trailer_args->v);
>   >            return run_command(&run_trailer);
>   >      @@ trailer.h: void trailer_iterator_release(struct trailer_iterator *iter);
>   >         */
>   >        int amend_file_with_trailers(const char *path, const struct strvec *trailer_args);
>   >
>   >      ++/*
>   >      ++ * Create a tempfile ""git-interpret-trailers-XXXXXX" in the same
>   >      ++ * directory as file.
>   >      ++ */
>   >      ++struct tempfile *trailer_create_in_place_tempfile(const char *file);
>   >      ++
>   >      ++/*
>   >      ++ * Rewrite the contents of input by processing its trailer block according to
>   >      ++ * opts and (optionally) appending trailers from new_trailer_head.
>   >      ++ *
>   >      ++ * The rewritten message is appended to out (callers should strbuf_reset()
>   >      ++ * first if needed).
>   >      ++ */
>   >       +void process_trailers(const struct process_trailer_options *opts,
>   >       +              struct list_head *new_trailer_head,
>   >       +              struct strbuf *input, struct strbuf *out);
>   > 3:  3114f0dbb57 ! 4:  1f24917eb64 trailer: append trailers without fork/exec
>   >      @@ Commit message
>   >
>   >           Update amend_file_with_trailers() to use the in-process helper and
>   >           rewrite the target file via tempfile+rename, preserving the previous
>   >      -    in-place semantics.
>   >      +    in-place semantics. As the trailers are no longer added in a separate
>   >      +    process and trailer_config_init() die()s on missing config values it
>   >      +    is called early on in cmd_commit() and cmd_tag() so that they die()
>   >      +    early before writing the message file. The trailer arguments are now
>   >      +    also sanity checked.
>   >
>   >           Keep existing callers unchanged by continuing to accept argv-style
>   >           --trailer=<trailer> entries and stripping the prefix before feeding the
>   >           in-process implementation.
>   >
>   >           Signed-off-by: Li Chen <me@linux.beauty>
>   >      +    Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
>   >      -
>   >      - ## builtin/interpret-trailers.c ##
>   >      -@@ builtin/interpret-trailers.c: static void interpret_trailers(const struct process_trailer_options *opts,
>   >      -     struct strbuf out = STRBUF_INIT;
>   >      -     FILE *outfile = stdout;
>   >      -
>   >      --    trailer_config_init();
>   >      --
>   >      -     read_input_file(&input, file);
>   >      -
>   >      -     if (opts->in_place)
>   >      -@@ builtin/interpret-trailers.c: int cmd_interpret_trailers(int argc,
>   >      -             git_interpret_trailers_usage,
>   >      -             options);
>   >      -
>   >      -+    trailer_config_init();
>   >      -+
>   >      -     if (argc) {
>   >      -         int i;
>   >      -         for (i = 0; i < argc; i++)
>   >      +    Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
>   >      +
>   >      + ## builtin/commit.c ##
>   >      +@@ builtin/commit.c: 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;
>   >      +
>   >      +
>   >      + ## builtin/tag.c ##
>   >      +@@ builtin/tag.c: 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;
>   >      +
>   >
>   >        ## trailer.c ##
>   >       @@
>   >        #include "string-list.h"
>   >        #include "run-command.h"
>   >        #include "commit.h"
>   >       +#include "strvec.h"
>   >      -+#include "tempfile.h"
>   >        #include "trailer.h"
>   >        #include "list.h"
>   >      -+
>   >      - /*
>   >      -  * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
>   >      -  */
>   >      + #include "tempfile.h"
>   >       @@ trailer.c: void parse_trailers_from_command_line_args(struct list_head *arg_head,
>   >            free(cl_separators);
>   >        }
>   >
>   >      -+void validate_trailer_args(const struct strvec *cli_args)
>   >      ++int validate_trailer_args(const struct strvec *cli_args)
>   >       +{
>   >       +    char *cl_separators;
>   >      ++    int ret = 0;
>   >       +
>   >       +    trailer_config_init();
>   >       +
>   >      @@ trailer.c: void parse_trailers_from_command_line_args(struct list_head *arg_head
>   >       +        const char *txt = cli_args->v[i];
>   >       +        ssize_t separator_pos;
>   >       +
>   >      -+        if (!*txt)
>   >      -+            die(_("empty --trailer argument"));
>   >      -+
>   >      ++        if (!*txt) {
>   >      ++            ret = error(_("empty --trailer argument"));
>   >      ++            goto out;
>   >      ++        }
>   >       +        separator_pos = find_separator(txt, cl_separators);
>   >      -+        if (separator_pos == 0)
>   >      -+            die(_("invalid trailer '%s': missing key before separator"),
>   >      -+                txt);
>   >      ++        if (separator_pos == 0) {
>   >      ++            ret = error(_("invalid trailer '%s': missing key before separator"),
>   >      ++                    txt);
>   >      ++            goto out;
>   >      ++        }
>   >       +    }
>   >      -+
>   >      ++out:
>   >       +    free(cl_separators);
>   >      ++    return ret;
>   >       +}
>   >       +
>   >        static const char *next_line(const char *str)
>   >        {
>   >            const char *nl = strchrnul(str, '\n');
>   >      -@@ trailer.c: void trailer_iterator_release(struct trailer_iterator *iter)
>   >      -     strbuf_release(&iter->key);
>   >      +@@ trailer.c: struct tempfile *trailer_create_in_place_tempfile(const char *file)
>   >      +     return tempfile;
>   >        }
>   >
>   >       -int amend_file_with_trailers(const char *path, const struct strvec *trailer_args)
>   >      @@ trailer.c: void trailer_iterator_release(struct trailer_iterator *iter)
>   >       -             path, NULL);
>   >       -    strvec_pushv(&run_trailer.args, trailer_args->v);
>   >       -    return run_command(&run_trailer);
>   >      -+static void new_trailer_items_clear(struct list_head *items)
>   >      -+{
>   >      -+    while (!list_empty(items)) {
>   >      -+        struct new_trailer_item *item =
>   >      -+            list_first_entry(items, struct new_trailer_item, list);
>   >      -+        list_del(&item->list);
>   >      -+        free(item);
>   >      -+    }
>   >      -+}
>   >      -+
>   >      -+void amend_strbuf_with_trailers(struct strbuf *buf,
>   >      ++int amend_strbuf_with_trailers(struct strbuf *buf,
>   >       +                const struct strvec *trailer_args)
>   >       +{
>   >       +    struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
>   >       +    LIST_HEAD(new_trailer_head);
>   >       +    struct strbuf out = STRBUF_INIT;
>   >       +    size_t i;
>   >      ++    int ret = 0;
>   >       +
>   >       +    opts.no_divider = 1;
>   >       +
>   >       +    for (i = 0; i < trailer_args->nr; i++) {
>   >       +        const char *text = trailer_args->v[i];
>   >       +        struct new_trailer_item *item;
>   >       +
>   >      -+        if (!*text)
>   >      -+            die(_("empty --trailer argument"));
>   >      ++        if (!*text) {
>   >      ++            ret = error(_("empty --trailer argument"));
>   >      ++            goto out;
>   >      ++        }
>   >       +        item = xcalloc(1, sizeof(*item));
>   >      -+        item->text = text;
>   >      ++        item->text = xstrdup(text);
>   >       +        list_add_tail(&item->list, &new_trailer_head);
>   >       +    }
>   >       +
>   >      -+    trailer_config_init();
>   >       +    process_trailers(&opts, &new_trailer_head, buf, &out);
>   >       +
>   >       +    strbuf_swap(buf, &out);
>   >      ++out:
>   >       +    strbuf_release(&out);
>   >      ++    free_trailers(&new_trailer_head);
>   >       +
>   >      -+    new_trailer_items_clear(&new_trailer_head);
>   >      ++    return ret;
>   >       +}
>   >       +
>   >       +static int write_file_in_place(const char *path, const struct strbuf *buf)
>   >       +{
>   >      -+    struct stat st;
>   >      -+    struct strbuf filename_template = STRBUF_INIT;
>   >      -+    const char *tail;
>   >      -+    struct tempfile *tempfile;
>   >      -+    FILE *outfile;
>   >      -+
>   >      -+    if (stat(path, &st))
>   >      -+        return error_errno(_("could not stat %s"), path);
>   >      -+    if (!S_ISREG(st.st_mode))
>   >      -+        return error(_("file %s is not a regular file"), path);
>   >      -+    if (!(st.st_mode & S_IWUSR))
>   >      -+        return error(_("file %s is not writable by user"), path);
>   >      -+
>   >      -+    /* Create temporary file in the same directory as the original */
>   >      -+    tail = strrchr(path, '/');
>   >      -+    if (tail)
>   >      -+        strbuf_add(&filename_template, path, tail - path + 1);
>   >      -+    strbuf_addstr(&filename_template, "git-interpret-trailers-XXXXXX");
>   >      -+
>   >      -+    tempfile = mks_tempfile_sm(filename_template.buf, 0, st.st_mode);
>   >      -+    strbuf_release(&filename_template);
>   >      ++    struct tempfile *tempfile = trailer_create_in_place_tempfile(path);
>   >       +    if (!tempfile)
>   >      -+        return error_errno(_("could not create temporary file"));
>   >      -+
>   >      -+    outfile = fdopen_tempfile(tempfile, "w");
>   >      -+    if (!outfile) {
>   >      -+        int saved_errno = errno;
>   >      -+        delete_tempfile(&tempfile);
>   >      -+        errno = saved_errno;
>   >      -+        return error_errno(_("could not open temporary file"));
>   >      -+    }
>   >      -+
>   >      -+    if (buf->len && fwrite(buf->buf, 1, buf->len, outfile) < buf->len) {
>   >      -+        int saved_errno = errno;
>   >      -+        delete_tempfile(&tempfile);
>   >      -+        errno = saved_errno;
>   >      ++        return -1;
>   >      ++
>   >      ++    if (write_in_full(tempfile->fd, buf->buf, buf->len) < 0)
>   >       +        return error_errno(_("could not write to temporary file"));
>   >      -+    }
>   >       +
>   >       +    if (rename_tempfile(&tempfile, path))
>   >       +        return error_errno(_("could not rename temporary file to %s"), path);
>   >      @@ trailer.c: void trailer_iterator_release(struct trailer_iterator *iter)
>   >       +         * in-process implementation.
>   >       +         */
>   >       +        skip_prefix(txt, "--trailer=", &txt);
>   >      -+        if (!*txt)
>   >      -+            die(_("empty --trailer argument"));
>   >      ++        if (!*txt) {
>   >      ++            ret = error(_("empty --trailer argument"));
>   >      ++            goto out;
>   >      ++        }
>   >       +        strvec_push(&stripped_trailer_args, txt);
>   >       +    }
>   >       +
>   >      ++    if (validate_trailer_args(&stripped_trailer_args)) {
>   >      ++        ret = -1;
>   >      ++        goto out;
>   >      ++    }
>   >       +    if (strbuf_read_file(&buf, path, 0) < 0)
>   >       +        ret = error_errno(_("could not read '%s'"), path);
>   >       +    else
>   >       +        amend_strbuf_with_trailers(&buf, &stripped_trailer_args);
>   >       +
>   >       +    if (!ret)
>   >       +        ret = write_file_in_place(path, &buf);
>   >      -+
>   >      ++out:
>   >       +    strvec_clear(&stripped_trailer_args);
>   >       +    strbuf_release(&buf);
>   >       +    return ret;
>   >      @@ trailer.h: void parse_trailers_from_config(struct list_head *config_head);
>   >        void parse_trailers_from_command_line_args(struct list_head *arg_head,
>   >                               struct list_head *new_trailer_head);
>   >
>   >      -+void validate_trailer_args(const struct strvec *cli_args);
>   >      ++int validate_trailer_args(const struct strvec *cli_args);
>   >       +
>   >        void process_trailers_lists(struct list_head *head,
>   >                        struct list_head *arg_head);
>   >      @@ trailer.h: int trailer_iterator_advance(struct trailer_iterator *iter);
>   >       + * Each element of trailer_args should be in the same format as the value
>   >       + * accepted by --trailer=<trailer> (i.e., without the --trailer= prefix).
>   >       + */
>   >      -+void amend_strbuf_with_trailers(struct strbuf *buf,
>   >      ++int amend_strbuf_with_trailers(struct strbuf *buf,
>   >       +                const struct strvec *trailer_args);
>   >       +
>   >       +/*
>   >      @@ trailer.h: int trailer_iterator_advance(struct trailer_iterator *iter);
>   >         */
>   >        int amend_file_with_trailers(const char *path, const struct strvec *trailer_args);
>   >
>   >      -+/*
>   >      -+ * Rewrite the contents of input by processing its trailer block according to
>   >      -+ * opts and (optionally) appending trailers from new_trailer_head.
>   >      -+ *
>   >      -+ * The rewritten message is appended to out (callers should strbuf_reset()
>   >      -+ * first if needed).
>   >      -+ */
>   >      - void process_trailers(const struct process_trailer_options *opts,
>   >      -               struct list_head *new_trailer_head,
>   >      -               struct strbuf *input, struct strbuf *out);
>   > 4:  147595a9317 ! 5:  3c1fa9e8579 commit, tag: parse --trailer with OPT_STRVEC
>   >      @@ Commit message
>   >           amend_file_with_trailers().
>   >
>   >           Signed-off-by: Li Chen <me@linux.beauty>
>   >
>   >        ## builtin/commit.c ##
>   >       @@ builtin/commit.c: int cmd_commit(int argc,
>   >      @@ trailer.c: int amend_file_with_trailers(const char *path,
>   >       -         * in-process implementation.
>   >       -         */
>   >       -        skip_prefix(txt, "--trailer=", &txt);
>   >      --        if (!*txt)
>   >      --            die(_("empty --trailer argument"));
>   >      +-        if (!*txt) {
>   >      +-            ret = error(_("empty --trailer argument"));
>   >      +-            goto out;
>   >      +-        }
>   >       -        strvec_push(&stripped_trailer_args, txt);
>   >       -    }
>   >       -
>   >      +-    if (validate_trailer_args(&stripped_trailer_args)) {
>   >      ++    if (validate_trailer_args(trailer_args)) {
>   >      +         ret = -1;
>   >      +         goto out;
>   >      +     }
>   >            if (strbuf_read_file(&buf, path, 0) < 0)
>   >                ret = error_errno(_("could not read '%s'"), path);
>   >            else
>   >      @@ trailer.c: int amend_file_with_trailers(const char *path,
>   >
>   >            if (!ret)
>   >                ret = write_file_in_place(path, &buf);
>   >      -
>   >      + out:
>   >       -    strvec_clear(&stripped_trailer_args);
>   >            strbuf_release(&buf);
>   >            return ret;
>   >        }
>   >
>   >        ## trailer.h ##
>   >      -@@ trailer.h: void amend_strbuf_with_trailers(struct strbuf *buf,
>   >      +@@ trailer.h: int amend_strbuf_with_trailers(struct strbuf *buf,
>   >        /*
>   >         * Augment a file by appending trailers specified in trailer_args.
>   >         *
>   > 5:  864cf5f8eb6 ! 6:  99654d80547 rebase: support --trailer
>   >      @@ Commit message
>   >           non-interactive and interactive rebases.
>   >
>   >           Signed-off-by: Li Chen <me@linux.beauty>
>   >      +    Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
>   >
>   >        ## Documentation/git-rebase.adoc ##
>   >       @@ Documentation/git-rebase.adoc: See also INCOMPATIBLE OPTIONS below.
>   >      @@ Documentation/git-rebase.adoc: See also INCOMPATIBLE OPTIONS below.
>   >       +--trailer=<trailer>::
>   >       +    Append the given trailer to every rebased commit message, processed
>   >       +    via linkgit:git-interpret-trailers[1]. This option implies
>   >      -+    `--force-rebase` so that fast-forwarded commits are also rewritten.
>   >      ++    `--force-rebase`.
>   >       ++
>   >       +See also INCOMPATIBLE OPTIONS below.
>   >       +
>   >        -i::
>   >        --interactive::
>   >            Make a list of the commits which are about to be rebased.  Let the
>   >      +@@ Documentation/git-rebase.adoc: are incompatible with the following options:
>   >      +  * --[no-]reapply-cherry-picks when used without --keep-base
>   >      +  * --update-refs
>   >      +  * --root when used without --onto
>   >      ++ * --trailer
>   >      +
>   >      + In addition, the following pairs of options are incompatible:
>   >      +
>   >
>   >        ## builtin/rebase.c ##
>   >       @@
>   >      @@ builtin/rebase.c: int cmd_rebase(int argc,
>   >                         builtin_rebase_usage, 0);
>   >
>   >       +    if (options.trailer_args.nr) {
>   >      -+        validate_trailer_args(&options.trailer_args);
>   >      ++        if (validate_trailer_args(&options.trailer_args))
>   >      ++            die(NULL);
>   >       +        options.flags |= REBASE_FORCE;
>   >       +    }
>   >       +
>   >      @@ sequencer.c: void replay_opts_release(struct replay_opts *opts)
>   >            free(opts->ctx);
>   >        }
>   >       @@ sequencer.c: static int append_squash_message(struct strbuf *buf, const char *body,
>   >      +     if (is_fixup_flag(command, flag) && !seen_squash(ctx)) {
>   >      +         /*
>   >      +          * We're replacing the commit message so we need to
>   >      +-         * append the Signed-off-by: trailer if the user
>   >      +-         * requested '--signoff'.
>   >      ++         * append any trailers if the user requested
>   >      ++         * '--signoff' or '--trailer'.
>   >      +          */
>   >                if (opts->signoff)
>   >                    append_signoff(buf, 0, 0);
>   >
>   >      @@ sequencer.c: static int do_pick_commit(struct repository *r,
>   >            if (is_rebase_i(opts) && write_author_script(msg.message) < 0)
>   >                res = -1;
>   >            else if (!opts->strategy ||
>   >      +@@ sequencer.c: static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)
>   >      +     parse_strategy_opts(opts, buf->buf);
>   >      + }
>   >      +
>   >      ++static int read_trailers(struct replay_opts *opts, struct strbuf *buf)
>   >      ++{
>   >      ++    ssize_t len;
>   >      ++
>   >      ++    strbuf_reset(buf);
>   >      ++    len = strbuf_read_file(buf, rebase_path_trailer(), 0);
>   >      ++    if (len > 0) {
>   >      ++        char *p = buf->buf, *nl;
>   >      ++
>   >      ++        trailer_config_init();
>   >      ++
>   >      ++        while ((nl = strchr(p, '\n'))) {
>   >      ++            *nl = '\0';
>   >      ++            if (!*p)
>   >      ++                return error(_("trailers file contains empty line"));
>   >      ++            strvec_push(&opts->trailer_args, p);
>   >      ++            p = nl + 1;
>   >      ++        }
>   >      ++    } else if (!len) {
>   >      ++        return error(_("trailers file is empty"));
>   >      ++    } else if (errno != ENOENT) {
>   >      ++        return error(_("cannot read trailers files"));
>   >      ++    }
>   >      ++
>   >      ++    return 0;
>   >      ++}
>   >      ++
>   >      + static int read_populate_opts(struct replay_opts *opts)
>   >      + {
>   >      +     struct replay_ctx *ctx = opts->ctx;
>   >       @@ sequencer.c: static int read_populate_opts(struct replay_opts *opts)
>   >      +             opts->keep_redundant_commits = 1;
>   >
>   >                read_strategy_opts(opts, &buf);
>   >      ++
>   >      ++        if (read_trailers(opts, &buf)) {
>   >      ++            ret = -1;
>   >      ++            goto done_rebase_i;
>   >      ++        }
>   >                strbuf_reset(&buf);
>   >      -+        if (strbuf_read_file(&buf, rebase_path_trailer(), 0) >= 0) {
>   >      -+            char *p = buf.buf, *nl;
>   >      -+
>   >      -+            while ((nl = strchr(p, '\n'))) {
>   >      -+                *nl = '\0';
>   >      -+                if (!*p)
>   >      -+                    BUG("rebase-merge/trailer has an empty line");
>   >      -+                strvec_push(&opts->trailer_args, p);
>   >      -+                p = nl + 1;
>   >      -+            }
>   >      -+            strbuf_reset(&buf);
>   >      -+        }
>   >
>   >                if (read_oneliner(&ctx->current_fixups,
>   >      -                   rebase_path_current_fixups(),
>   >       @@ sequencer.c: int write_basic_state(struct replay_opts *opts, const char *head_name,
>   >                write_file(rebase_path_reschedule_failed_exec(), "%s", "");
>   >            else
>   >
>   >
> 


  reply	other threads:[~2026-03-06 14:55 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-24  7:05 [PATCH v7 0/5] rebase: support --trailer Li Chen
2026-02-24  7:05 ` [PATCH v7 1/5] interpret-trailers: factor trailer rewriting Li Chen
2026-03-02 14:56   ` Phillip Wood
2026-03-02 15:00     ` Li Chen
2026-02-24  7:05 ` [PATCH v7 2/5] trailer: move process_trailers to trailer.h Li Chen
2026-03-02 14:56   ` phillip.wood123
2026-02-24  7:05 ` [PATCH v7 3/5] trailer: append trailers without fork/exec Li Chen
2026-03-02 14:56   ` Phillip Wood
2026-02-24  7:05 ` [PATCH v7 4/5] commit, tag: parse --trailer with OPT_STRVEC Li Chen
2026-03-02 14:56   ` Phillip Wood
2026-02-24  7:05 ` [PATCH v7 5/5] rebase: support --trailer Li Chen
2026-03-03 15:05   ` Phillip Wood
2026-03-03 20:36     ` Kristoffer Haugsbakk
2026-03-03 21:18       ` Junio C Hamano
2026-03-04 15:53         ` Phillip Wood
2026-03-04 17:22           ` Junio C Hamano
2026-02-26 16:52 ` [PATCH v7 0/5] " Junio C Hamano
2026-02-26 18:15   ` Phillip Wood
2026-02-26 21:12 ` Kristoffer Haugsbakk
2026-03-04 14:29 ` Phillip Wood
2026-03-05 13:49   ` Li Chen
2026-03-06 14:55     ` Phillip Wood [this message]
2026-03-06 14:53 ` [PATCH v8 0/6] " Phillip Wood
2026-03-06 14:53   ` [PATCH v8 1/6] interpret-trailers: factor trailer rewriting Phillip Wood
2026-03-06 21:04     ` Junio C Hamano
2026-03-09 10:36       ` Phillip Wood
2026-03-06 14:53   ` [PATCH v8 2/6] interpret-trailers: refactor create_in_place_tempfile() Phillip Wood
2026-03-06 21:05     ` Junio C Hamano
2026-03-06 14:53   ` [PATCH v8 3/6] trailer: libify a couple of functions Phillip Wood
2026-03-06 14:53   ` [PATCH v8 4/6] trailer: append trailers without fork/exec Phillip Wood
2026-03-06 14:53   ` [PATCH v8 5/6] commit, tag: parse --trailer with OPT_STRVEC Phillip Wood
2026-03-06 14:53   ` [PATCH v8 6/6] rebase: support --trailer Phillip Wood

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8a37a357-5a3b-4ca1-9949-6b2f28d3f208@gmail.com \
    --to=phillip.wood123@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=kristofferhaugsbakk@fastmail.com \
    --cc=me@linux.beauty \
    --cc=phillip.wood@dunelm.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.