Skip to content

Commit

Permalink
rebase continue: Add --no-edit flag to skip opening an editor
Browse files Browse the repository at this point in the history
Git's `rebase --continue` always opens an editor
to edit the commit message after resoling the conflict.
There are cases where this is not necessary.

This adds a `--no-edit` flag to `gs rebase continue`
to skip opening an editor.

`rebase` does not have a `--no-edit` flag to skip the editor
but we can get the same effect by setting the editor to `true`
for that command.

Resolves #503
  • Loading branch information
abhinav committed Dec 1, 2024
1 parent b566d05 commit 2d57a25
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 2 deletions.
6 changes: 6 additions & 0 deletions .changes/unreleased/Added-20241130-172501.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Added
body: >-
rebase continue:
Add `--[no-]edit` flag to skip opening an editor when continuing a rebase,
or opt into it if the new `spice.rebaseContinue.edit` configuration is `true`.
time: 2024-11-30T17:25:01.584724-08:00
12 changes: 11 additions & 1 deletion doc/includes/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ Branches upstack are restacked as needed.
### gs rebase continue

```
gs rebase (rb) continue (c)
gs rebase (rb) continue (c) [flags]
```

Continue an interrupted operation
Expand All @@ -834,6 +834,16 @@ you can resolve the conflict and run 'gs rebase continue'
The command can be used in place of 'git rebase --continue'
even if a git-spice operation is not currently in progress.

Use the --no-edit flag to continue without opening an editor.
Make --no-edit the default by setting 'spice.rebaseContinue.edit' to false
and use --edit to override it.

**Flags**

* `--[no-]edit` ([:material-wrench:{ .middle title="spice.rebaseContinue.edit" }](/cli/config.md#spicerebasecontinueedit)): Whehter to open an editor to edit the commit message.

**Configuration**: [spice.rebaseContinue.edit](/cli/config.md#spicerebasecontinueedit)

### gs rebase abort

```
Expand Down
14 changes: 14 additions & 0 deletions doc/src/cli/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,20 @@ instead of showing just the current stack.
- `true`
- `false` (default)

### spice.rebaseContinue.edit

<!-- gs:version unreleased -->

Whether $$gs rebase continue$$ should open an editor to modify the commit message
when continuing after resolving a rebase conflict.

If set to false, you can opt in to opening the editor with the `--edit` flag.

**Accepted values:**

- `true` (default)
- `false`

### spice.submit.listTemplatesTimeout

<!-- gs:version v0.8.0 -->
Expand Down
21 changes: 21 additions & 0 deletions internal/git/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ type Repository struct {

log *log.Logger
exec execer
cfg extraConfig
}

func newRepository(root, gitDir string, log *log.Logger, exec execer) *Repository {
Expand All @@ -124,5 +125,25 @@ func newRepository(root, gitDir string, log *log.Logger, exec execer) *Repositor
// gitCmd returns a gitCmd that will run
// with the repository's root as the working directory.
func (r *Repository) gitCmd(ctx context.Context, args ...string) *gitCmd {
args = append(r.cfg.Args(), args...)
return newGitCmd(ctx, r.log, args...).Dir(r.root)
}

// WithEditor returns a copy of the repository
// that will use the given editor when running git commands.
func (r *Repository) WithEditor(editor string) *Repository {
newR := *r
newR.cfg.Editor = editor
return &newR
}

type extraConfig struct {
Editor string // core.editor
}

func (ec extraConfig) Args() (args []string) {
if ec.Editor != "" {
args = append(args, "-c", "core.editor="+ec.Editor)
}
return args
}
23 changes: 23 additions & 0 deletions internal/git/repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
"go.abhg.dev/gs/internal/logtest"
)

Expand All @@ -22,3 +23,25 @@ func NewTestRepository(t testing.TB, dir string, execer execer) *Repository {

return newRepository(dir, gitDir, logtest.New(t), execer)
}

func TestExtraConfig_Args(t *testing.T) {
tests := []struct {
name string
give extraConfig
want []string
}{
{name: "empty"},
{
name: "editor",
give: extraConfig{Editor: "vim"},
want: []string{"-c", "core.editor=vim"},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.give.Args()
assert.Equal(t, tt.want, got)
})
}
}
12 changes: 11 additions & 1 deletion rebase_continue.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import (
"go.abhg.dev/gs/internal/ui"
)

type rebaseContinueCmd struct{}
type rebaseContinueCmd struct {
Edit bool `default:"true" negatable:"" config:"rebaseContinue.edit" help:"Whehter to open an editor to edit the commit message."`
}

func (*rebaseContinueCmd) Help() string {
return text.Dedent(`
Expand All @@ -26,6 +28,10 @@ func (*rebaseContinueCmd) Help() string {
The command can be used in place of 'git rebase --continue'
even if a git-spice operation is not currently in progress.
Use the --no-edit flag to continue without opening an editor.
Make --no-edit the default by setting 'spice.rebaseContinue.edit' to false
and use --edit to override it.
`)
}

Expand Down Expand Up @@ -54,6 +60,10 @@ func (cmd *rebaseContinueCmd) Run(
return errors.New("no rebase in progress")
}

if !cmd.Edit {
repo = repo.WithEditor("true")
}

// Finish the ongoing rebase.
if err := repo.RebaseContinue(ctx); err != nil {
var rebaseErr *git.RebaseInterruptError
Expand Down
120 changes: 120 additions & 0 deletions testdata/script/branch_restack_conflict_no_edit.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# 'rebase continue --no-edit' is able to continue from a conflict
# without opening an editor.

as 'Test <[email protected]>'
at '2024-12-01T10:18:19Z'

mkdir repo
cd repo
git init
git commit --allow-empty -m 'Initial commit'
gs repo init

# add main -> feat1
gs trunk
cp $WORK/extra/feat1.txt feat.txt
git add feat.txt
gs bc feat1 -m 'Add feature 1'

# add main -> feat2
gs trunk
cp $WORK/extra/feat2.txt feat.txt
git add feat.txt
gs bc feat2 -m 'Add feature 2'

# add main -> feat3
gs trunk
cp $WORK/extra/feat3.txt feat.txt
git add feat.txt
gs bc feat3 -m 'Add feature 3'

# main: introduce a conflict
gs trunk
cp $WORK/extra/feat0.txt feat.txt
git add feat.txt
git commit -m 'Add feature 0'

# Set editor to false to fail the test
# if the editor is opened by any command
env EDITOR=false

# feat1: rebase continue --no-edit
gs bco feat1
! gs branch restack
stderr 'There was a conflict'
cp $WORK/extra/feat1.txt feat.txt
git add feat.txt
gs rebase continue --no-edit

# feat1: verify resolved
cmp feat.txt $WORK/extra/feat1.txt
git status --porcelain
! stdout '.' # no changes

# Make --no-edit the default
git config spice.rebaseContinue.edit false

# feat2: rebase continue --no-edit is default
gs bco feat2
! gs branch restack
stderr 'There was a conflict'
cp $WORK/extra/feat2.txt feat.txt
git add feat.txt
gs rebase continue

# feat2: verify resolved
cmp feat.txt $WORK/extra/feat2.txt
git status --porcelain
! stdout '.' # no changes

# feat3: rebase continue, --edit opt-in
gs bco feat3
! gs branch restack
stderr 'There was a conflict'

env EDITOR=mockedit MOCKEDIT_GIVE=$WORK/input/feat3-msg.txt MOCKEDIT_RECORD=$WORK/feat3-conflict-msg.txt
cp $WORK/extra/feat3.txt feat.txt
git add feat.txt
gs rebase continue --edit
cmp $WORK/feat3-conflict-msg.txt $WORK/golden/feat3-conflict-msg.txt

git graph
cmp stdout $WORK/golden/log.txt

-- extra/feat0.txt --
feature 0

-- extra/feat1.txt --
feature 1

-- extra/feat2.txt --
feature 2

-- extra/feat3.txt --
feature 3

-- input/feat3-msg.txt --
feat3: resolved

-- golden/feat3-conflict-msg.txt --
Add feature 3

# Conflicts:
# feat.txt

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# interactive rebase in progress; onto ccf2371
# Last command done (1 command done):
# pick 712f10b Add feature 3
# No commands remaining.
# You are currently rebasing branch 'feat3' on 'ccf2371'.
#
# Changes to be committed:
# modified: feat.txt
#
-- golden/log.txt --
* 200dbc4 (HEAD -> feat3) feat3: resolved
* ccf2371 (main) Add feature 0
* 585bc4c Initial commit

0 comments on commit 2d57a25

Please sign in to comment.