Repository: jesseduffield/lazygit (language: go)

Issue:
Rewording last commit freezes when GPG passphrase is needed in CLI
**Describe the bug**
When you have GPG passphrase setup to be prompt in CLI, it will hang indefinitely when trying to reword the last commit. No input can reach the gpg prompt.

While it works when you just want to do a normal commit.

**To Reproduce**
Steps to reproduce the behavior:

1. Have your GPG setup with passphrase, see [here](https://docs.github.com/en/authentication/managing-commit-signature-verification/generating-a-new-gpg-key)
2. Change GPG to ask passphrase in CLI by having `pinentry-mode loopback` in `~/.gnupg/gpg.conf`
3. Maybe restart your gpg agent by doing `gpg-connect-agent reloadagent /bye`
4. Reword the last commit in a repo by going to the Commits panel and press **r** on the last commit
5. Type your reworded message and press enter
6. See it asks for passphrase on top of lazygit TUI

**Expected behavior**
You should be able to enter your passphrase and submit it to GPG prompt.

**Screenshots**
![image](https://github.com/user-attachments/assets/8197c991-7179-405f-8171-21a6c9f76df8)

**Version info:**
`commit=v0.42.0, build date=2024-05-19T10:54:29Z, build source=binaryRelease, version=0.42.0, os=linux, arch=amd64, git version=2.45.2`

**Additional context**
This relates #3758 and #30.

It seems like it goes through the same code path as rebasing which does not have explicit GPG support.

The line in question is in here:
https://github.com/jesseduffield/lazygit/blob/a3560eb451fcf375378a316cbc2f4e08e24bf756/pkg/commands/git_commands/rebase.go#L37-L41

GPG works fine when committing normally, it goes to a different code path which can handle gpg.

https://github.com/jesseduffield/lazygit/blob/a3560eb451fcf375378a316cbc2f4e08e24bf756/pkg/gui/controllers/helpers/working_tree_helper.go#L103-L110

The question is just to access `gpghelper` from `RebaseCommands` and wrap the commands using `gpghelper`.

Maybe I can try to figure it out this weekend or this month when I am free, could also see if I can add initial gpg support to rebasing as mentioned here.

https://github.com/jesseduffield/lazygit/blob/a3560eb451fcf375378a316cbc2f4e08e24bf756/pkg/commands/git_commands/rebase.go#L392-L405










Discussion / hints:
An easier fix is probably to make the distinction of "is this the head commit" at the call site of `RebaseCommands.RewordCommit` (in `LocalCommitsController.handleReword`) rather than inside it. LocalCommitsController has access to the gpgHelper. This would then be similar to what we already do for Amend.

Fix patch:
diff --git a/pkg/commands/git_commands/commit.go b/pkg/commands/git_commands/commit.go
index 4153dfeb909..1ff7c095f1d 100644
--- a/pkg/commands/git_commands/commit.go
+++ b/pkg/commands/git_commands/commit.go
@@ -117,7 +117,7 @@ func (self *CommitCommands) CommitInEditorWithMessageFileCmdObj(tmpMessageFile s
 }
 
 // RewordLastCommit rewords the topmost commit with the given message
-func (self *CommitCommands) RewordLastCommit(summary string, description string) error {
+func (self *CommitCommands) RewordLastCommit(summary string, description string) oscommands.ICmdObj {
 	messageArgs := self.commitMessageArgs(summary, description)
 
 	cmdArgs := NewGitCmd("commit").
@@ -125,7 +125,7 @@ func (self *CommitCommands) RewordLastCommit(summary string, description string)
 		Arg(messageArgs...).
 		ToArgv()
 
-	return self.cmd.New(cmdArgs).Run()
+	return self.cmd.New(cmdArgs)
 }
 
 func (self *CommitCommands) commitMessageArgs(summary string, description string) []string {
diff --git a/pkg/commands/git_commands/rebase.go b/pkg/commands/git_commands/rebase.go
index 59c2c6833c0..56537e92fcc 100644
--- a/pkg/commands/git_commands/rebase.go
+++ b/pkg/commands/git_commands/rebase.go
@@ -35,9 +35,8 @@ func NewRebaseCommands(
 }
 
 func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, summary string, description string) error {
-	if models.IsHeadCommit(commits, index) {
-		// we've selected the top commit so no rebase is required
-		return self.commit.RewordLastCommit(summary, description)
+	if self.config.UsingGpg() {
+		return errors.New(self.Tr.DisabledForGPG)
 	}
 
 	err := self.BeginInteractiveRebaseForCommit(commits, index, false)
@@ -46,7 +45,7 @@ func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, su
 	}
 
 	// now the selected commit should be our head so we'll amend it with the new message
-	err = self.commit.RewordLastCommit(summary, description)
+	err = self.commit.RewordLastCommit(summary, description).Run()
 	if err != nil {
 		return err
 	}
diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go
index f95062fdbe3..913601b5c7f 100644
--- a/pkg/gui/controllers/local_commits_controller.go
+++ b/pkg/gui/controllers/local_commits_controller.go
@@ -400,7 +400,16 @@ func (self *LocalCommitsController) switchFromCommitMessagePanelToEditor(filepat
 }
 
 func (self *LocalCommitsController) handleReword(summary string, description string) error {
-	err := self.c.Git().Rebase.RewordCommit(self.c.Model().Commits, self.c.Contexts().LocalCommits.GetSelectedLineIdx(), summary, description)
+	var err error
+
+	if models.IsHeadCommit(self.c.Model().Commits, self.c.Contexts().LocalCommits.GetSelectedLineIdx()) {
+		// we've selected the top commit so no rebase is required
+		err = self.c.Helpers().GPG.WithGpgHandling(self.c.Git().Commit.RewordLastCommit(summary, description),
+			self.c.Tr.CommittingStatus, nil)
+	} else {
+		err = self.c.Git().Rebase.RewordCommit(self.c.Model().Commits, self.c.Contexts().LocalCommits.GetSelectedLineIdx(), summary, description)
+	}
+
 	if err != nil {
 		return err
 	}


Test patch:
diff --git a/pkg/commands/git_commands/commit_test.go b/pkg/commands/git_commands/commit_test.go
index 239d7fa8f4c..3e2c9e664f4 100644
--- a/pkg/commands/git_commands/commit_test.go
+++ b/pkg/commands/git_commands/commit_test.go
@@ -33,7 +33,7 @@ func TestCommitRewordCommit(t *testing.T) {
 		t.Run(s.testName, func(t *testing.T) {
 			instance := buildCommitCommands(commonDeps{runner: s.runner})
 
-			assert.NoError(t, instance.RewordLastCommit(s.summary, s.description))
+			assert.NoError(t, instance.RewordLastCommit(s.summary, s.description).Run())
 			s.runner.CheckForMissingCalls()
 		})
 	}