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

Re: [PATCH v2 2/2] fast-import: add '--signed-commits=<mode>' option

From
Christian Couder <christian.couder@gmail.com>
Date
Sep 12, 2025, 12:45 UTC
Message-ID
<CAP8UFD3guuRXR6DEEBLaO3AqzSfs_woj6WcrCxJ3krdObokD3A@mail.gmail.com>
In-Reply-To
<20250912124042.2523683-3-christian.couder@gmail.com>

Sorry I forgot to use the --in-reply-to='20250910080839.2142651-1-christian.couder@gmail.com' option when sending this series. It is related to:

https://lore.kernel.org/git/20250910080839.2142651-1-christian.couder@gmail.com/

On Fri, Sep 12, 2025 at 2:40 PM Christian Couder <christian.couder@gmail.com> wrote:

Show 235 quoted lines
>
> A '--signed-commits=<mode>' option is already available when using
> `git fast-export` to decide what should be done at export time about
> commit signatures. At import time though, there is no option, or
> other way, in `git fast-import` to decide about commit signatures.
>
> To remediate that, let's add a '--signed-commits=<mode>' option to
> `git fast-import` too.
>
> For now the supported <mode>s are the same as those supported by
> `git fast-export`.
>
> Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
> ---
>  Documentation/git-fast-import.adoc |   5 ++
>  builtin/fast-import.c              |  41 ++++++++---
>  t/meson.build                      |   1 +
>  t/t9305-fast-import-signatures.sh  | 106 +++++++++++++++++++++++++++++
>  4 files changed, 145 insertions(+), 8 deletions(-)
>  create mode 100755 t/t9305-fast-import-signatures.sh
>
> diff --git a/Documentation/git-fast-import.adoc b/Documentation/git-fast-import.adoc
> index 3144ffcdb6..90f242d058 100644
> --- a/Documentation/git-fast-import.adoc
> +++ b/Documentation/git-fast-import.adoc
> @@ -66,6 +66,11 @@ OPTIONS
>         remote-helpers that use the `import` capability, as they are
>         already trusted to run their own code.
>
> +--signed-commits=(verbatim|warn-verbatim|warn-strip|strip|abort)::
> +       Specify how to handle signed commits.  Behaves in the same way
> +       as the same option in linkgit:git-fast-export[1], except that
> +       default is 'verbatim' (instead of 'abort').
> +
>  Options for Frontends
>  ~~~~~~~~~~~~~~~~~~~~~
>
> diff --git a/builtin/fast-import.c b/builtin/fast-import.c
> index 2c35f9345d..890f05de4d 100644
> --- a/builtin/fast-import.c
> +++ b/builtin/fast-import.c
> @@ -188,6 +188,8 @@ static int global_argc;
>  static const char **global_argv;
>  static const char *global_prefix;
>
> +static enum sign_mode signed_commit_mode = SIGN_VERBATIM;
> +
>  /* Memory pools */
>  static struct mem_pool fi_mem_pool = {
>         .block_alloc = 2*1024*1024 - sizeof(struct mp_block),
> @@ -2817,19 +2819,39 @@ 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 };
>
> -               parse_one_signature(&sig, v);
> +               if (signed_commit_mode == SIGN_ABORT)
> +                       die(_("encountered signed commit; use "
> +                             "--signed-commits=<mode> to handle it"));
>
> -               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
> -                       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;
> +               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);
> +                       break;
> +               }
>                 read_next_command();
>         }
>
> @@ -3501,6 +3523,9 @@ static int parse_one_option(const char *option)
>                 option_active_branches(option);
>         } else if (skip_prefix(option, "export-pack-edges=", &option)) {
>                 option_export_pack_edges(option);
> +       } else if (skip_prefix(option, "signed-commits=", &option)) {
> +               if (parse_sign_mode(option, &signed_commit_mode))
> +                       usagef(_("unknown --signed-commits mode '%s'"), option);
>         } else if (!strcmp(option, "quiet")) {
>                 show_stats = 0;
>                 quiet = 1;
> diff --git a/t/meson.build b/t/meson.build
> index 82af229be3..08ad6938e2 100644
> --- a/t/meson.build
> +++ b/t/meson.build
> @@ -1032,6 +1032,7 @@ integration_tests = [
>    't9302-fast-import-unpack-limit.sh',
>    't9303-fast-import-compression.sh',
>    't9304-fast-import-marks.sh',
> +  't9305-fast-import-signatures.sh',
>    't9350-fast-export.sh',
>    't9351-fast-export-anonymize.sh',
>    't9400-git-cvsserver-server.sh',
> diff --git a/t/t9305-fast-import-signatures.sh b/t/t9305-fast-import-signatures.sh
> new file mode 100755
> index 0000000000..c2b4271658
> --- /dev/null
> +++ b/t/t9305-fast-import-signatures.sh
> @@ -0,0 +1,106 @@
> +#!/bin/sh
> +
> +test_description='git fast-import --signed-commits=<mode>'
> +
> +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
> +
> +. ./test-lib.sh
> +. "$TEST_DIRECTORY/lib-gpg.sh"
> +
> +test_expect_success 'set up unsigned initial commit and import repo' '
> +       test_commit first &&
> +       git init new
> +'
> +
> +test_expect_success GPG 'set up OpenPGP signed commit' '
> +       git checkout -b openpgp-signing main &&
> +       echo "Content for OpenPGP signing." >file-sign &&
> +       git add file-sign &&
> +       git commit -S -m "OpenPGP signed commit" &&
> +       OPENPGP_SIGNING=$(git rev-parse --verify openpgp-signing)
> +'
> +
> +test_expect_success GPG 'import OpenPGP signature with --signed-commits=verbatim' '
> +       git fast-export --signed-commits=verbatim openpgp-signing >output &&
> +       git -C new fast-import --quiet --signed-commits=verbatim <output >log 2>&1 &&
> +       IMPORTED=$(git -C new rev-parse --verify refs/heads/openpgp-signing) &&
> +       test $OPENPGP_SIGNING = $IMPORTED &&
> +       test_must_be_empty log
> +'
> +
> +test_expect_success GPGSM 'set up X.509 signed commit' '
> +       git checkout -b x509-signing main &&
> +       test_config gpg.format x509 &&
> +       test_config user.signingkey $GIT_COMMITTER_EMAIL &&
> +       echo "Content for X.509 signing." >file-sign &&
> +       git add file-sign &&
> +       git commit -S -m "X.509 signed commit" &&
> +       X509_SIGNING=$(git rev-parse HEAD)
> +'
> +
> +test_expect_success GPGSM 'import X.509 signature fails with --signed-commits=abort' '
> +       git fast-export --signed-commits=verbatim x509-signing >output &&
> +       test_must_fail git -C new fast-import --quiet --signed-commits=abort <output
> +'
> +
> +test_expect_success GPGSM 'import X.509 signature with --signed-commits=warn-verbatim' '
> +       git -C new fast-import --quiet --signed-commits=warn-verbatim <output >log 2>&1 &&
> +       IMPORTED=$(git -C new rev-parse --verify refs/heads/x509-signing) &&
> +       test $X509_SIGNING = $IMPORTED &&
> +       test_grep "importing a commit signature" log
> +'
> +
> +test_expect_success GPGSSH 'set up SSH signed commit' '
> +       git checkout -b ssh-signing main &&
> +       test_config gpg.format ssh &&
> +       test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" &&
> +       echo "Content for SSH signing." >file-sign &&
> +       git add file-sign &&
> +       git commit -S -m "SSH signed commit" &&
> +       SSH_SIGNING=$(git rev-parse HEAD)
> +'
> +
> +test_expect_success GPGSSH 'strip SSH signature with --signed-commits=strip' '
> +       git fast-export --signed-commits=verbatim ssh-signing >output &&
> +       git -C new fast-import --quiet --signed-commits=strip <output >log 2>&1 &&
> +       IMPORTED=$(git -C new rev-parse --verify refs/heads/ssh-signing) &&
> +       test $SSH_SIGNING != $IMPORTED &&
> +       git -C new cat-file commit "$IMPORTED" >actual &&
> +       test_grep ! -E "^gpgsig" actual &&
> +       test_must_be_empty log
> +'
> +
> +test_expect_success GPG 'setup a commit with dual OpenPGP signatures on its SHA-1 and SHA-256 formats' '
> +       # Create a signed SHA-256 commit
> +       git init --object-format=sha256 explicit-sha256 &&
> +       git -C explicit-sha256 config extensions.compatObjectFormat sha1 &&
> +       git -C explicit-sha256 checkout -b dual-signed &&
> +       test_commit -C explicit-sha256 A &&
> +       echo B >explicit-sha256/B &&
> +       git -C explicit-sha256 add B &&
> +       test_tick &&
> +       git -C explicit-sha256 commit -S -m "signed" B &&
> +       SHA256_B=$(git -C explicit-sha256 rev-parse dual-signed) &&
> +
> +       # Create the corresponding SHA-1 commit
> +       SHA1_B=$(git -C explicit-sha256 rev-parse --output-object-format=sha1 dual-signed) &&
> +
> +       # Check that the resulting SHA-1 commit has both signatures
> +       git -C explicit-sha256 cat-file -p $SHA1_B >out &&
> +       test_grep -E "^gpgsig " out &&
> +       test_grep -E "^gpgsig-sha256 " out
> +'
> +
> +test_expect_success GPG 'strip both OpenPGP signatures with --signed-commits=warn-strip' '
> +       git -C explicit-sha256 fast-export --signed-commits=verbatim dual-signed >output &&
> +       test_grep -E "^gpgsig sha1 openpgp" output &&
> +       test_grep -E "^gpgsig sha256 openpgp" output &&
> +       git -C new fast-import --quiet --signed-commits=warn-strip <output >log 2>&1 &&
> +       git -C new cat-file commit refs/heads/dual-signed >actual &&
> +       test_grep ! -E "^gpgsig " actual &&
> +       test_grep ! -E "^gpgsig-sha256 " actual &&
> +       test_grep "stripping a commit signature" log >out &&
> +       test_line_count = 2 out
> +'
> +
> +test_done
> --
> 2.51.0.195.gf8f8f06677
>
Previous: Christian CouderNext: Patrick Steinhardt
Message 4 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.