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

[PATCH v3 0/2] fast-import: start controlling how commit signatures are handled

From
Christian Couder <christian.couder@gmail.com>
Date
Sep 17, 2025, 18:14 UTC
Message-ID
<20250917181427.3193500-1-christian.couder@gmail.com>
In-Reply-To
<20250912124042.2523683-1-christian.couder@gmail.com>

Tools like `git-filter-repo` should be able to control how commit signatures are handled when regenerating repository content after it has been filtered (see https://github.com/newren/git-filter-repo/issues/139). For this purpose, they need a way for `git fast-import` to control how commit signatures are handled.

This small patch series starts to implement such a way by adding a new `--signed-commits=<mode>` option to `git fast-import`.

For now this new option behaves in a very similar way as the option with the same name that already exists in `git fast-export`. Especially it supports exactly the same <mode>s and the same aliases for these modes. For example "ignore" is a synonym for "verbatim".

In the future I want to implement new <mode>s like "strip-if-invalid", "re-sign", "re-sign-if-invalid" that might be a bit more complex for this option. But for now I prefer to start with the simple modes to validate the general design of the new option.

In the future I also plan to add a similar `--signed-tags=<mode>` so that the import of tags can also be controlled. But I prefer to validate the general design of a single new option first.

In particular, I am interested in feedback about the following:
  - Should we keep "ignore" as a synonym for "verbatim" and "warn" as
    a synonym for "warn-verbatim"? My opinion is that they might be
    confusing, so we might want to remove them for `git fast-import`
    even if we keep them for `git fast-export`. The parsing code might
    be a bit more complex if we do that though, so for now I have kept
    the synonyms.
  - Are we still fine with most <mode>s having a "warn-*" variant
    (like the "warn-strip" variant of "strip" for example)? Or should
    we have a separate `--verbose` or maybe `--signed-commits-verbose`
    option dedicated to switching warnings on/off? I think it's good
    to decide about this before the number of <mode>s increases a lot
    with new <mode>s like "strip-if-invalid", "re-sign",
    "re-sign-if-invalid" and possibly others.

Changes since v2: =================

Thanks to Junio and Patrick for reviewing previous versions.
In patch 2/2:
  - The commit message has been improved to explain why new functions
    are added and how the 'strip' and 'warn-strip' modes are handled.
  - The code responsible for consuming a signature has been refactored
    into two new functions: import_one_signature() and
    discard_one_signature() functions. This makes it easier to follow
    the logic and add new modes in the future.
  - The SIGN_ABORT case is not handled separately from the other cases
    anymore.
  - Code comments have been added to the
    `switch (signed_commit_mode) { ... }` that handles the different
    cases, and a `default: ...` case that calls BUG() has been added
    to it.

CI tests: =========

They have all passed. See:
https://github.com/chriscool/git/actions/runs/17804251337

Range-diff vs V2: =================

1:  87149ae92d = 1:  87149ae92d gpg-interface: refactor 'enum sign_mode' parsing
2:  e34f015aea ! 2:  cf6ce66e1d fast-import: add '--signed-commits=<mode>' option
    @@ Commit message
         For now the supported <mode>s are the same as those supported by
         `git fast-export`.
     
    +    The code responsible for consuming a signature is refactored into
    +    the import_one_signature() and discard_one_signature() functions,
    +    which makes it easier to follow the logic and add new modes in the
    +    future.
    +
    +    In the 'strip' and 'warn-strip' modes, we deliberately use
    +    discard_one_signature() to discard the signature without parsing it.
    +    This ensures that even malformed signatures, which would cause the
    +    parser to fail, can be successfully stripped from a commit.
    +
         Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
     
      ## Documentation/git-fast-import.adoc ##
    @@ builtin/fast-import.c: static int global_argc;
      /* Memory pools */
      static struct mem_pool fi_mem_pool = {
      	.block_alloc = 2*1024*1024 - sizeof(struct mp_block),
    +@@ builtin/fast-import.c: static void parse_one_signature(struct signature_data *sig, const char *v)
    + 	parse_data(&sig->data, 0, NULL);
    + }
    + 
    ++static void discard_one_signature(void)
    ++{
    ++	struct strbuf data = STRBUF_INIT;
    ++
    ++	read_next_command();
    ++	parse_data(&data, 0, NULL);
    ++	strbuf_release(&data);
    ++}
    ++
    + static void add_gpgsig_to_commit(struct strbuf *commit_data,
    + 				 const char *header,
    + 				 struct signature_data *sig)
    +@@ builtin/fast-import.c: static void store_signature(struct signature_data *stored_sig,
    + 	}
    + }
    + 
    ++static void import_one_signature(struct signature_data *sig_sha1,
    ++				 struct signature_data *sig_sha256,
    ++				 const char *v)
    ++{
    ++	struct signature_data sig = { NULL, NULL, STRBUF_INIT };
    ++
    ++	parse_one_signature(&sig, v);
    ++
    ++	if (!strcmp(sig.hash_algo, "sha1"))
    ++		store_signature(sig_sha1, &sig, "SHA-1");
    ++	else if (!strcmp(sig.hash_algo, "sha256"))
    ++		store_signature(sig_sha256, &sig, "SHA-256");
    ++	else
    ++		die(_("parse_one_signature() returned unknown hash algo"));
    ++}
    ++
    + static void parse_new_commit(const char *arg)
    + {
    + 	static struct strbuf msg = STRBUF_INIT;
     @@ builtin/fast-import.c: static void parse_new_commit(const char *arg)
      	if (!committer)
      		die("Expected committer but didn't get one");
      
     -	/* Process signatures (up to 2: one "sha1" and one "sha256") */
      	while (skip_prefix(command_buf.buf, "gpgsig ", &v)) {
    - 		struct signature_data sig = { NULL, NULL, STRBUF_INIT };
    - 
    +-		struct signature_data sig = { NULL, NULL, STRBUF_INIT };
    +-
     -		parse_one_signature(&sig, v);
    -+		if (signed_commit_mode == SIGN_ABORT)
    -+			die(_("encountered signed commit; use "
    -+			      "--signed-commits=<mode> to handle it"));
    ++		switch (signed_commit_mode) {
    ++
    ++		/* First, modes that don't need the signature to be parsed */
    ++		case SIGN_ABORT:
    ++			die("encountered signed commit; use "
    ++			    "--signed-commits=<mode> to handle it");
    ++		case SIGN_WARN_STRIP:
    ++			warning(_("stripping a commit signature"));
    ++			/* fallthru */
    ++		case SIGN_STRIP:
    ++			discard_one_signature();
    ++			break;
      
     -		if (!strcmp(sig.hash_algo, "sha1"))
     -			store_signature(&sig_sha1, &sig, "SHA-1");
    @@ builtin/fast-import.c: static void parse_new_commit(const char *arg)
     -			store_signature(&sig_sha256, &sig, "SHA-256");
     -		else
     -			BUG("parse_one_signature() returned unknown hash algo");
    -+		parse_one_signature(&sig, v);
    - 
    -+		switch (signed_commit_mode) {
    -+		case SIGN_ABORT:
    -+			BUG("SIGN_ABORT should be handled before calling parse_one_signature()");
    -+			break;
    ++		/* Second, modes that parse the signature */
     +		case SIGN_WARN_VERBATIM:
     +			warning(_("importing a commit signature verbatim"));
     +			/* fallthru */
     +		case SIGN_VERBATIM:
    -+			if (!strcmp(sig.hash_algo, "sha1"))
    -+				store_signature(&sig_sha1, &sig, "SHA-1");
    -+			else if (!strcmp(sig.hash_algo, "sha256"))
    -+				store_signature(&sig_sha256, &sig, "SHA-256");
    -+			else
    -+				die(_("parse_one_signature() returned unknown hash algo"));
    -+			break;
    -+		case SIGN_WARN_STRIP:
    -+			warning(_("stripping a commit signature"));
    -+			/* fallthru */
    -+		case SIGN_STRIP:
    -+			/* Just discard signature data */
    -+			strbuf_release(&sig.data);
    -+			free(sig.hash_algo);
    ++			import_one_signature(&sig_sha1, &sig_sha256, v);
     +			break;
    + 
    ++		/* Third, BUG */
    ++		default:
    ++			BUG("invalid signed_commit_mode value %d", signed_commit_mode);
     +		}
      		read_next_command();
      	}
Christian Couder (2):
  gpg-interface: refactor 'enum sign_mode' parsing
  fast-import: add '--signed-commits=<mode>' option
 Documentation/git-fast-import.adoc |   5 ++
 builtin/fast-export.c              |  19 ++----
 builtin/fast-import.c              |  63 ++++++++++++++---
 gpg-interface.c                    |  17 +++++
 gpg-interface.h                    |  15 ++++
 t/meson.build                      |   1 +
 t/t9305-fast-import-signatures.sh  | 106 +++++++++++++++++++++++++++++
 7 files changed, 202 insertions(+), 24 deletions(-)
 create mode 100755 t/t9305-fast-import-signatures.sh
-- 
2.51.0.195.ge34f015aea.dirty
Previous: Christian CouderNext: Christian Couder
Message 9 of 11 in “fast-import: start controlling how commit signatures are handled”
  1. 0/2 fast-import: start controlling how commit signatures are handledChristian Couder, Sep 12, 2025
  2. 1/2 gpg-interface: refactor 'enum sign_mode' parsingChristian Couder, Sep 12, 2025
  3. 2/2 fast-import: add '--signed-commits=<mode>' optionChristian Couder, Sep 12, 2025
  4. Christian CouderSep 12, 2025
  5. Patrick SteinhardtSep 15, 2025
  6. Christian CouderSep 15, 2025
  7. Patrick SteinhardtSep 15, 2025
  8. Christian CouderSep 17, 2025
  9. 0/2 fast-import: start controlling how commit signatures are handledChristian Couder, Sep 17, 2025
  10. 1/2 gpg-interface: refactor 'enum sign_mode' parsingChristian Couder, Sep 17, 2025
  11. 2/2 fast-import: add '--signed-commits=<mode>' optionChristian Couder, Sep 17, 2025

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.