* [PATCH v2 0/2] fast-import: start controlling how commit signatures are handled
@ 2025-09-12 12:40 Christian Couder
2025-09-12 12:40 ` [PATCH v2 1/2] gpg-interface: refactor 'enum sign_mode' parsing Christian Couder
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: Christian Couder @ 2025-09-12 12:40 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Patrick Steinhardt, Elijah Newren, Jeff King,
brian m . carlson, Johannes Schindelin, Christian Couder
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 v1:
=================
Thanks to Junio and Patrick for reviewing V1.
In patch 1/2:
- the commit message now says that a single option will be added in
the following commit
- instead of returning success in the `!parse_sign_mode(arg, val)`
case, we return error in the `parse_sign_mode(arg, val)` case,
- a '.' has been added at the end of a code comment.
In patch 2/2:
- the import_signature() function has been removed and we just call
parse_one_signature() in all cases except `SIGN_ABORT`, before
handling the signature according to `signed_commit_mode`,
- we now mark for translation all new strings that could be
displayed to users,
- usagef() is used instead of die() when the mode is unknown,
- the warning for `warn-verbatim` has been improved,
- the tests have been improved by using more idiomatic and
simplified commands
CI tests:
=========
They have all passed. See:
https://github.com/chriscool/git/actions/runs/17672015528
range-diff vs V1:
=================
1: 7c8216a701 ! 1: 87149ae92d gpg-interface: refactor 'enum sign_mode' parsing
@@ Commit message
only command with '--signed-tags=<mode>' or '--signed-commits=<mode>'
options.
- In a following commit, we are going to add such options to `git
+ In a following commit, we are going to add a similar option to `git
fast-import`, which will be simpler, easier and cleaner if we can reuse
the 'enum sign_mode' defintion and parsing code.
@@ builtin/fast-export.c: static struct hashmap anonymized_seeds;
- else if (!strcmp(arg, "strip"))
- *val = SIGN_STRIP;
- else
-- return error("Unknown %s mode: %s", opt->long_name, arg);
-- return 0;
+
-+ if (!parse_sign_mode(arg, val))
-+ return 0;
++ if (parse_sign_mode(arg, val))
+ return error("Unknown %s mode: %s", opt->long_name, arg);
+
-+ return error("Unknown %s mode: %s", opt->long_name, arg);
+ return 0;
}
- static int parse_opt_tag_of_filtered_mode(const struct option *opt,
## gpg-interface.c ##
@@ gpg-interface.c: static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
@@ gpg-interface.h: int check_signature(struct signature_check *sigc,
void print_signature_buffer(const struct signature_check *sigc,
unsigned flags);
-+/* Modes for --signed-tags=<mode> and --signed-commits=<mode> options */
++/* Modes for --signed-tags=<mode> and --signed-commits=<mode> options. */
+enum sign_mode {
+ SIGN_ABORT,
+ SIGN_WARN_VERBATIM,
2: 0294f05ae6 ! 2: e34f015aea fast-import: add '--signed-commits=<mode>' option
@@ 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 store_signature(struct signature_data *stored_sig,
- }
- }
-
-+/* Process signatures (up to 2: one "sha1" and one "sha256") */
-+static void import_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
-+ BUG("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"));
+
- 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");
--
-+ struct strbuf data = STRBUF_INIT;
++ parse_one_signature(&sig, v);
+
+ switch (signed_commit_mode) {
+ case SIGN_ABORT:
-+ die("encountered signed commit; use "
-+ "--signed-commits=<mode> to handle it");
++ BUG("SIGN_ABORT should be handled before calling parse_one_signature()");
++ break;
+ case SIGN_WARN_VERBATIM:
-+ warning("importing a commit signature");
++ warning(_("importing a commit signature verbatim"));
+ /* fallthru */
+ case SIGN_VERBATIM:
-+ import_signature(&sig_sha1, &sig_sha256, 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"));
+ break;
+ case SIGN_WARN_STRIP:
-+ warning("stripping a commit signature");
++ warning(_("stripping a commit signature"));
+ /* fallthru */
+ case SIGN_STRIP:
-+ /* Read signature data and discard it */
-+ read_next_command();
-+ parse_data(&data, 0, NULL);
-+ strbuf_release(&data);
++ /* Just discard signature data */
++ strbuf_release(&sig.data);
++ free(sig.hash_algo);
+ break;
+ }
read_next_command();
@@ builtin/fast-import.c: static int parse_one_option(const char *option)
option_export_pack_edges(option);
+ } else if (skip_prefix(option, "signed-commits=", &option)) {
+ if (parse_sign_mode(option, &signed_commit_mode))
-+ die("unknown --signed-commits mode '%s'", option);
++ usagef(_("unknown --signed-commits mode '%s'"), option);
} else if (!strcmp(option, "quiet")) {
show_stats = 0;
quiet = 1;
@@ t/t9305-fast-import-signatures.sh (new)
+test_description='git fast-import --signed-commits=<mode>'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
-+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY/lib-gpg.sh"
+
+test_expect_success 'set up unsigned initial commit and import repo' '
+ test_commit first &&
-+ mkdir new &&
-+ git --git-dir=new/.git init
++ git init new
+'
+
+test_expect_success GPG 'set up OpenPGP signed commit' '
@@ t/t9305-fast-import-signatures.sh (new)
+ SHA1_B=$(git -C explicit-sha256 rev-parse --output-object-format=sha1 dual-signed) &&
+
+ # Check that the resulting SHA-1 commit has both signatures
-+ echo $SHA1_B | git -C explicit-sha256 cat-file --batch >out &&
++ git -C explicit-sha256 cat-file -p $SHA1_B >out &&
+ test_grep -E "^gpgsig " out &&
+ test_grep -E "^gpgsig-sha256 " out
+'
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 | 41 ++++++++---
gpg-interface.c | 17 +++++
gpg-interface.h | 15 ++++
t/meson.build | 1 +
t/t9305-fast-import-signatures.sh | 106 +++++++++++++++++++++++++++++
7 files changed, 182 insertions(+), 22 deletions(-)
create mode 100755 t/t9305-fast-import-signatures.sh
--
2.51.0.195.gf8f8f06677
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 1/2] gpg-interface: refactor 'enum sign_mode' parsing
2025-09-12 12:40 [PATCH v2 0/2] fast-import: start controlling how commit signatures are handled Christian Couder
@ 2025-09-12 12:40 ` Christian Couder
2025-09-12 12:40 ` [PATCH v2 2/2] fast-import: add '--signed-commits=<mode>' option Christian Couder
2025-09-17 18:14 ` [PATCH v3 0/2] fast-import: start controlling how commit signatures are handled Christian Couder
2 siblings, 0 replies; 11+ messages in thread
From: Christian Couder @ 2025-09-12 12:40 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Patrick Steinhardt, Elijah Newren, Jeff King,
brian m . carlson, Johannes Schindelin, Christian Couder,
Christian Couder
The definition of 'enum sign_mode' as well as its parsing code are in
"builtin/fast-export.c". This was fine because `git fast-export` was the
only command with '--signed-tags=<mode>' or '--signed-commits=<mode>'
options.
In a following commit, we are going to add a similar option to `git
fast-import`, which will be simpler, easier and cleaner if we can reuse
the 'enum sign_mode' defintion and parsing code.
So let's move that definition and parsing code from
"builtin/fast-export.c" to "gpg-interface.{c,h}".
While at it, let's fix a small indentation issue with the arguments of
parse_opt_sign_mode().
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
builtin/fast-export.c | 19 +++++--------------
gpg-interface.c | 17 +++++++++++++++++
gpg-interface.h | 15 +++++++++++++++
3 files changed, 37 insertions(+), 14 deletions(-)
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index c06ee0b213..dc2486f9a8 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -37,8 +37,6 @@ static const char *const fast_export_usage[] = {
NULL
};
-enum sign_mode { SIGN_ABORT, SIGN_VERBATIM, SIGN_STRIP, SIGN_WARN_VERBATIM, SIGN_WARN_STRIP };
-
static int progress;
static enum sign_mode signed_tag_mode = SIGN_ABORT;
static enum sign_mode signed_commit_mode = SIGN_STRIP;
@@ -59,23 +57,16 @@ static struct hashmap anonymized_seeds;
static struct revision_sources revision_sources;
static int parse_opt_sign_mode(const struct option *opt,
- const char *arg, int unset)
+ const char *arg, int unset)
{
enum sign_mode *val = opt->value;
+
if (unset)
return 0;
- else if (!strcmp(arg, "abort"))
- *val = SIGN_ABORT;
- else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
- *val = SIGN_VERBATIM;
- else if (!strcmp(arg, "warn-verbatim") || !strcmp(arg, "warn"))
- *val = SIGN_WARN_VERBATIM;
- else if (!strcmp(arg, "warn-strip"))
- *val = SIGN_WARN_STRIP;
- else if (!strcmp(arg, "strip"))
- *val = SIGN_STRIP;
- else
+
+ if (parse_sign_mode(arg, val))
return error("Unknown %s mode: %s", opt->long_name, arg);
+
return 0;
}
diff --git a/gpg-interface.c b/gpg-interface.c
index 06e7fb5060..2f4f0e32cb 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -1125,3 +1125,20 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
FREE_AND_NULL(ssh_signing_key_file);
return ret;
}
+
+int parse_sign_mode(const char *arg, enum sign_mode *mode)
+{
+ if (!strcmp(arg, "abort"))
+ *mode = SIGN_ABORT;
+ else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
+ *mode = SIGN_VERBATIM;
+ else if (!strcmp(arg, "warn-verbatim") || !strcmp(arg, "warn"))
+ *mode = SIGN_WARN_VERBATIM;
+ else if (!strcmp(arg, "warn-strip"))
+ *mode = SIGN_WARN_STRIP;
+ else if (!strcmp(arg, "strip"))
+ *mode = SIGN_STRIP;
+ else
+ return -1;
+ return 0;
+}
diff --git a/gpg-interface.h b/gpg-interface.h
index 60ddf8bbfa..50487aa148 100644
--- a/gpg-interface.h
+++ b/gpg-interface.h
@@ -104,4 +104,19 @@ int check_signature(struct signature_check *sigc,
void print_signature_buffer(const struct signature_check *sigc,
unsigned flags);
+/* Modes for --signed-tags=<mode> and --signed-commits=<mode> options. */
+enum sign_mode {
+ SIGN_ABORT,
+ SIGN_WARN_VERBATIM,
+ SIGN_VERBATIM,
+ SIGN_WARN_STRIP,
+ SIGN_STRIP,
+};
+
+/*
+ * Return 0 if `arg` can be parsed into an `enum sign_mode`. Return -1
+ * otherwise.
+ */
+int parse_sign_mode(const char *arg, enum sign_mode *mode);
+
#endif
--
2.51.0.195.gf8f8f06677
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 2/2] fast-import: add '--signed-commits=<mode>' option
2025-09-12 12:40 [PATCH v2 0/2] fast-import: start controlling how commit signatures are handled Christian Couder
2025-09-12 12:40 ` [PATCH v2 1/2] gpg-interface: refactor 'enum sign_mode' parsing Christian Couder
@ 2025-09-12 12:40 ` Christian Couder
2025-09-12 12:45 ` Christian Couder
2025-09-15 6:27 ` Patrick Steinhardt
2025-09-17 18:14 ` [PATCH v3 0/2] fast-import: start controlling how commit signatures are handled Christian Couder
2 siblings, 2 replies; 11+ messages in thread
From: Christian Couder @ 2025-09-12 12:40 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Patrick Steinhardt, Elijah Newren, Jeff King,
brian m . carlson, Johannes Schindelin, Christian Couder,
Christian Couder
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
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v2 2/2] fast-import: add '--signed-commits=<mode>' option
2025-09-12 12:40 ` [PATCH v2 2/2] fast-import: add '--signed-commits=<mode>' option Christian Couder
@ 2025-09-12 12:45 ` Christian Couder
2025-09-15 6:27 ` Patrick Steinhardt
1 sibling, 0 replies; 11+ messages in thread
From: Christian Couder @ 2025-09-12 12:45 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Patrick Steinhardt, Elijah Newren, Jeff King,
brian m . carlson, Johannes Schindelin, Christian Couder
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:
>
> 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
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 2/2] fast-import: add '--signed-commits=<mode>' option
2025-09-12 12:40 ` [PATCH v2 2/2] fast-import: add '--signed-commits=<mode>' option Christian Couder
2025-09-12 12:45 ` Christian Couder
@ 2025-09-15 6:27 ` Patrick Steinhardt
2025-09-15 10:17 ` Christian Couder
1 sibling, 1 reply; 11+ messages in thread
From: Patrick Steinhardt @ 2025-09-15 6:27 UTC (permalink / raw)
To: Christian Couder
Cc: git, Junio C Hamano, Elijah Newren, Jeff King, brian m . carlson,
Johannes Schindelin, Christian Couder
On Fri, Sep 12, 2025 at 02:40:42PM +0200, Christian Couder wrote:
> 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
> 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
> @@ -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;
Let's be defensive and convert this into a `default:` case so that any
unhandled value will cause a BUG.
> + 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();
> }
>
Other than that the patch looks good to me, thanks!
Patrick
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 2/2] fast-import: add '--signed-commits=<mode>' option
2025-09-15 6:27 ` Patrick Steinhardt
@ 2025-09-15 10:17 ` Christian Couder
2025-09-15 10:56 ` Patrick Steinhardt
0 siblings, 1 reply; 11+ messages in thread
From: Christian Couder @ 2025-09-15 10:17 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: git, Junio C Hamano, Elijah Newren, Jeff King, brian m . carlson,
Johannes Schindelin, Christian Couder
On Mon, Sep 15, 2025 at 8:27 AM Patrick Steinhardt <ps@pks.im> wrote:
>
> On Fri, Sep 12, 2025 at 02:40:42PM +0200, Christian Couder wrote:
> >
> > - /* 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;
>
> Let's be defensive and convert this into a `default:` case so that any
> unhandled value will cause a BUG.
Ok, maybe something like BUG("invalid signed_commit_mode value %d",
signed_commit_mode) then?
Note that if we later develop new modes like "re-sign" or
"strip-if-invalid", and users tries one such mode with an old version
of Git, that should already be handled by the following code in
parse_one_option():
} else if (skip_prefix(option, "signed-commits=", &option)) {
if (parse_sign_mode(option, &signed_commit_mode))
usagef(_("unknown --signed-commits mode '%s'"), option);
} ...
Thanks,
Christian.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 2/2] fast-import: add '--signed-commits=<mode>' option
2025-09-15 10:17 ` Christian Couder
@ 2025-09-15 10:56 ` Patrick Steinhardt
2025-09-17 18:23 ` Christian Couder
0 siblings, 1 reply; 11+ messages in thread
From: Patrick Steinhardt @ 2025-09-15 10:56 UTC (permalink / raw)
To: Christian Couder
Cc: git, Junio C Hamano, Elijah Newren, Jeff King, brian m . carlson,
Johannes Schindelin, Christian Couder
On Mon, Sep 15, 2025 at 12:17:33PM +0200, Christian Couder wrote:
> On Mon, Sep 15, 2025 at 8:27 AM Patrick Steinhardt <ps@pks.im> wrote:
> >
> > On Fri, Sep 12, 2025 at 02:40:42PM +0200, Christian Couder wrote:
>
> > >
> > > - /* 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;
> >
> > Let's be defensive and convert this into a `default:` case so that any
> > unhandled value will cause a BUG.
>
> Ok, maybe something like BUG("invalid signed_commit_mode value %d",
> signed_commit_mode) then?
Yeah, that should do the job.
Thanks!
Patrick
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 0/2] fast-import: start controlling how commit signatures are handled
2025-09-12 12:40 [PATCH v2 0/2] fast-import: start controlling how commit signatures are handled Christian Couder
2025-09-12 12:40 ` [PATCH v2 1/2] gpg-interface: refactor 'enum sign_mode' parsing Christian Couder
2025-09-12 12:40 ` [PATCH v2 2/2] fast-import: add '--signed-commits=<mode>' option Christian Couder
@ 2025-09-17 18:14 ` Christian Couder
2025-09-17 18:14 ` [PATCH v3 1/2] gpg-interface: refactor 'enum sign_mode' parsing Christian Couder
2025-09-17 18:14 ` [PATCH v3 2/2] fast-import: add '--signed-commits=<mode>' option Christian Couder
2 siblings, 2 replies; 11+ messages in thread
From: Christian Couder @ 2025-09-17 18:14 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Patrick Steinhardt, Elijah Newren, Jeff King,
brian m . carlson, Johannes Schindelin, Christian Couder
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
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 1/2] gpg-interface: refactor 'enum sign_mode' parsing
2025-09-17 18:14 ` [PATCH v3 0/2] fast-import: start controlling how commit signatures are handled Christian Couder
@ 2025-09-17 18:14 ` Christian Couder
2025-09-17 18:14 ` [PATCH v3 2/2] fast-import: add '--signed-commits=<mode>' option Christian Couder
1 sibling, 0 replies; 11+ messages in thread
From: Christian Couder @ 2025-09-17 18:14 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Patrick Steinhardt, Elijah Newren, Jeff King,
brian m . carlson, Johannes Schindelin, Christian Couder,
Christian Couder
The definition of 'enum sign_mode' as well as its parsing code are in
"builtin/fast-export.c". This was fine because `git fast-export` was the
only command with '--signed-tags=<mode>' or '--signed-commits=<mode>'
options.
In a following commit, we are going to add a similar option to `git
fast-import`, which will be simpler, easier and cleaner if we can reuse
the 'enum sign_mode' defintion and parsing code.
So let's move that definition and parsing code from
"builtin/fast-export.c" to "gpg-interface.{c,h}".
While at it, let's fix a small indentation issue with the arguments of
parse_opt_sign_mode().
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
builtin/fast-export.c | 19 +++++--------------
gpg-interface.c | 17 +++++++++++++++++
gpg-interface.h | 15 +++++++++++++++
3 files changed, 37 insertions(+), 14 deletions(-)
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index c06ee0b213..dc2486f9a8 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -37,8 +37,6 @@ static const char *const fast_export_usage[] = {
NULL
};
-enum sign_mode { SIGN_ABORT, SIGN_VERBATIM, SIGN_STRIP, SIGN_WARN_VERBATIM, SIGN_WARN_STRIP };
-
static int progress;
static enum sign_mode signed_tag_mode = SIGN_ABORT;
static enum sign_mode signed_commit_mode = SIGN_STRIP;
@@ -59,23 +57,16 @@ static struct hashmap anonymized_seeds;
static struct revision_sources revision_sources;
static int parse_opt_sign_mode(const struct option *opt,
- const char *arg, int unset)
+ const char *arg, int unset)
{
enum sign_mode *val = opt->value;
+
if (unset)
return 0;
- else if (!strcmp(arg, "abort"))
- *val = SIGN_ABORT;
- else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
- *val = SIGN_VERBATIM;
- else if (!strcmp(arg, "warn-verbatim") || !strcmp(arg, "warn"))
- *val = SIGN_WARN_VERBATIM;
- else if (!strcmp(arg, "warn-strip"))
- *val = SIGN_WARN_STRIP;
- else if (!strcmp(arg, "strip"))
- *val = SIGN_STRIP;
- else
+
+ if (parse_sign_mode(arg, val))
return error("Unknown %s mode: %s", opt->long_name, arg);
+
return 0;
}
diff --git a/gpg-interface.c b/gpg-interface.c
index 06e7fb5060..2f4f0e32cb 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -1125,3 +1125,20 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
FREE_AND_NULL(ssh_signing_key_file);
return ret;
}
+
+int parse_sign_mode(const char *arg, enum sign_mode *mode)
+{
+ if (!strcmp(arg, "abort"))
+ *mode = SIGN_ABORT;
+ else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
+ *mode = SIGN_VERBATIM;
+ else if (!strcmp(arg, "warn-verbatim") || !strcmp(arg, "warn"))
+ *mode = SIGN_WARN_VERBATIM;
+ else if (!strcmp(arg, "warn-strip"))
+ *mode = SIGN_WARN_STRIP;
+ else if (!strcmp(arg, "strip"))
+ *mode = SIGN_STRIP;
+ else
+ return -1;
+ return 0;
+}
diff --git a/gpg-interface.h b/gpg-interface.h
index 60ddf8bbfa..50487aa148 100644
--- a/gpg-interface.h
+++ b/gpg-interface.h
@@ -104,4 +104,19 @@ int check_signature(struct signature_check *sigc,
void print_signature_buffer(const struct signature_check *sigc,
unsigned flags);
+/* Modes for --signed-tags=<mode> and --signed-commits=<mode> options. */
+enum sign_mode {
+ SIGN_ABORT,
+ SIGN_WARN_VERBATIM,
+ SIGN_VERBATIM,
+ SIGN_WARN_STRIP,
+ SIGN_STRIP,
+};
+
+/*
+ * Return 0 if `arg` can be parsed into an `enum sign_mode`. Return -1
+ * otherwise.
+ */
+int parse_sign_mode(const char *arg, enum sign_mode *mode);
+
#endif
--
2.51.0.195.ge34f015aea.dirty
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 2/2] fast-import: add '--signed-commits=<mode>' option
2025-09-17 18:14 ` [PATCH v3 0/2] fast-import: start controlling how commit signatures are handled Christian Couder
2025-09-17 18:14 ` [PATCH v3 1/2] gpg-interface: refactor 'enum sign_mode' parsing Christian Couder
@ 2025-09-17 18:14 ` Christian Couder
1 sibling, 0 replies; 11+ messages in thread
From: Christian Couder @ 2025-09-17 18:14 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Patrick Steinhardt, Elijah Newren, Jeff King,
brian m . carlson, Johannes Schindelin, Christian Couder,
Christian Couder
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`.
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 | 5 ++
builtin/fast-import.c | 63 ++++++++++++++---
t/meson.build | 1 +
t/t9305-fast-import-signatures.sh | 106 +++++++++++++++++++++++++++++
4 files changed, 165 insertions(+), 10 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..2010e78475 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),
@@ -2752,6 +2754,15 @@ 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)
@@ -2785,6 +2796,22 @@ 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;
@@ -2817,19 +2844,32 @@ 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);
+ 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");
- else if (!strcmp(sig.hash_algo, "sha256"))
- store_signature(&sig_sha256, &sig, "SHA-256");
- else
- BUG("parse_one_signature() returned unknown hash algo");
+ /* Second, modes that parse the signature */
+ case SIGN_WARN_VERBATIM:
+ warning(_("importing a commit signature verbatim"));
+ /* fallthru */
+ case SIGN_VERBATIM:
+ 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();
}
@@ -3501,6 +3541,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.ge34f015aea.dirty
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v2 2/2] fast-import: add '--signed-commits=<mode>' option
2025-09-15 10:56 ` Patrick Steinhardt
@ 2025-09-17 18:23 ` Christian Couder
0 siblings, 0 replies; 11+ messages in thread
From: Christian Couder @ 2025-09-17 18:23 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: git, Junio C Hamano, Elijah Newren, Jeff King, brian m . carlson,
Johannes Schindelin, Christian Couder
On Mon, Sep 15, 2025 at 12:56 PM Patrick Steinhardt <ps@pks.im> wrote:
>
> On Mon, Sep 15, 2025 at 12:17:33PM +0200, Christian Couder wrote:
> > On Mon, Sep 15, 2025 at 8:27 AM Patrick Steinhardt <ps@pks.im> wrote:
> > >
> > > On Fri, Sep 12, 2025 at 02:40:42PM +0200, Christian Couder wrote:
> > > >
> > > > + switch (signed_commit_mode) {
> > > > + case SIGN_ABORT:
> > > > + BUG("SIGN_ABORT should be handled before calling parse_one_signature()");
> > > > + break;
> > >
> > > Let's be defensive and convert this into a `default:` case so that any
> > > unhandled value will cause a BUG.
> >
> > Ok, maybe something like BUG("invalid signed_commit_mode value %d",
> > signed_commit_mode) then?
>
> Yeah, that should do the job.
In the V3 I just sent, I have changed the switch (...) { ... } but
there is a `default: ...` case with the BUG() instruction we
discussed. Hopefully it still does the job.
Thanks.
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-09-17 18:24 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-12 12:40 [PATCH v2 0/2] fast-import: start controlling how commit signatures are handled Christian Couder
2025-09-12 12:40 ` [PATCH v2 1/2] gpg-interface: refactor 'enum sign_mode' parsing Christian Couder
2025-09-12 12:40 ` [PATCH v2 2/2] fast-import: add '--signed-commits=<mode>' option Christian Couder
2025-09-12 12:45 ` Christian Couder
2025-09-15 6:27 ` Patrick Steinhardt
2025-09-15 10:17 ` Christian Couder
2025-09-15 10:56 ` Patrick Steinhardt
2025-09-17 18:23 ` Christian Couder
2025-09-17 18:14 ` [PATCH v3 0/2] fast-import: start controlling how commit signatures are handled Christian Couder
2025-09-17 18:14 ` [PATCH v3 1/2] gpg-interface: refactor 'enum sign_mode' parsing Christian Couder
2025-09-17 18:14 ` [PATCH v3 2/2] fast-import: add '--signed-commits=<mode>' option Christian Couder
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).