Subject: [PATCH] rebase.c: teach --no-gpg-sign to git-rebase

From: Danh Doan <[email-masked]>
Date: Tue, 31 Mar 2020 13:44:56 +0700

On 2020-03-30 16:03:55-0400, Dominic Chen <[email-masked]> wrote:
> The subcommand `git commit` supports a `--no-gpg-sign` argument, which I
> find useful for cases where e.g. a GPG key is specified in `.gitconfig`,
> but is located on a hardware key that may not currently be attached to
> the system. However, other commands like `git rebase`, `git
> cherry-pick`, etc, which internally invoke `git commit`, don't support

cherry-pick (in git 2.25.1) understands --no-gpg-sign

I've encountered this in the past, but I stopped signing my commit.

Anyways, here is the patch

-----------------8<-----------------
From: Đoàn Trần Công Danh <[email-masked]>
Subject: [PATCH] rebase.c: teach --no-gpg-sign to git-rebase

Signed-off-by: Đoàn Trần Công Danh <[email-masked]>
---
 Documentation/git-rebase.txt |  5 +++
 builtin/rebase.c             | 10 +++--
 t/t3435-rebase-gpg-sign.sh   | 72 ++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+), 3 deletions(-)
 create mode 100755 t/t3435-rebase-gpg-sign.sh

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index f7a6033607..54023cf3bb 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -358,6 +358,11 @@ See also INCOMPATIBLE OPTIONS below.
 	defaults to the committer identity; if specified, it must be
 	stuck to the option without a space.
 
+--no-gpg-sign::
+	Countermand `commit.gpgSign` configuration variable that is
+	set to force each and every commit to be signed.
+
+
 -q::
 --quiet::
 	Be quiet. Implies --no-stat.
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 27a07d4e78..a8cc5cfe0c 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -1593,6 +1593,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
 	options.allow_empty_message = 1;
 	git_config(rebase_config, &options);
+	// options.gpg_sign_opt will be either "-S" or NULL
+	// It'll be freed later, hence, no skip-prefix
+	gpg_sign = options.gpg_sign_opt ? "" : NULL;
 
 	if (options.use_legacy_rebase ||
 	    !git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1))
@@ -1823,10 +1826,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (options.empty != EMPTY_UNSPECIFIED)
 		imply_merge(&options, "--empty");
 
-	if (gpg_sign) {
-		free(options.gpg_sign_opt);
+	free(options.gpg_sign_opt);
+	if (gpg_sign)
 		options.gpg_sign_opt = xstrfmt("-S%s", gpg_sign);
-	}
+	else
+		options.gpg_sign_opt = NULL;
 
 	if (exec.nr) {
 		int i;
diff --git a/t/t3435-rebase-gpg-sign.sh b/t/t3435-rebase-gpg-sign.sh
new file mode 100755
index 0000000000..d12b30b033
--- /dev/null
+++ b/t/t3435-rebase-gpg-sign.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+#
+# Copyright (c) 2020 Doan Tran Cong Danh
+#
+
+test_description='test rebase --[no-]gpg-sign'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY/lib-gpg.sh"
+
+if ! test_have_prereq GPG
+then
+	skip_all='skip all test rebase --[no-]gpg-sign, gpg not available'
+	test_done
+fi
+
+test_expect_success 'setup: not-signed commit' '
+	test_commit one &&
+	test_commit two &&
+	test_must_fail git verify-commit HEAD &&
+	test_must_fail git verify-commit HEAD^ &&
+	git tag unsigned
+'
+
+test_expect_success 'setup: rebase --gpg-sign to sign all commit' '
+	git rebase --gpg-sign --force-rebase --root &&
+	git verify-commit HEAD &&
+	git verify-commit HEAD^ &&
+	git tag signed
+'
+
+test_expect_success 'rebase without commit.gpgsign config' '
+	git reset --hard signed &&
+	test_might_fail git config --unset commit.gpgsign &&
+	git rebase --force-rebase --root &&
+	test_must_fail git verify-commit HEAD &&
+	test_must_fail git verify-commit HEAD^
+'
+
+test_expect_success 'rebase respects commit.gpgsign=true config' '
+	git reset --hard unsigned &&
+	git config commit.gpgsign true &&
+	git rebase --force-rebase --root &&
+	git verify-commit HEAD &&
+	git verify-commit HEAD^
+'
+
+test_expect_success 'rebase --no-gpg-sign overrides commit.gpgsign' '
+	git reset --hard unsigned &&
+	git config commit.gpgsign true &&
+	git rebase --no-gpg-sign --force-rebase --root &&
+	test_must_fail git verify-commit HEAD &&
+	test_must_fail git verify-commit HEAD^
+'
+
+test_expect_success 'rebase --no-gpg-sign clear signed commit' '
+	git reset --hard signed &&
+	git config commit.gpgsign true &&
+	git rebase --no-gpg-sign --force-rebase --root &&
+	test_must_fail git verify-commit HEAD &&
+	test_must_fail git verify-commit HEAD^
+'
+
+test_expect_success 'rebase -i --no-gpg-sign override commit.gpgsign' '
+	git reset --hard signed &&
+	git config commit.gpgsign true &&
+	GIT_EDITOR=true git rebase -i --no-gpg-sign --force-rebase --root &&
+	test_must_fail git verify-commit HEAD &&
+	test_must_fail git verify-commit HEAD^
+'
+
+test_done
-- 
2.26.0.334.g6536db25bb